static glamor_program * glamor_dash_setup(DrawablePtr drawable, GCPtr gc) { ScreenPtr screen = drawable->pScreen; glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable); glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap); PixmapPtr dash_pixmap; glamor_pixmap_private *dash_priv; glamor_program *prog; if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) goto bail; if (gc->lineWidth != 0) goto bail; dash_pixmap = glamor_get_dash_pixmap(gc); dash_priv = glamor_get_pixmap_private(pixmap); if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dash_priv)) goto bail; glamor_make_current(glamor_priv); switch (gc->lineStyle) { case LineOnOffDash: prog = glamor_use_program_fill(pixmap, gc, &glamor_priv->on_off_dash_line_progs, &glamor_facet_on_off_dash_lines); if (!prog) goto bail; break; case LineDoubleDash: if (gc->fillStyle != FillSolid) goto bail; prog = &glamor_priv->double_dash_line_prog; if (!prog->prog) { if (!glamor_build_program(screen, prog, &glamor_facet_double_dash_lines, NULL, NULL, NULL)) goto bail; } if (!glamor_use_program(pixmap, gc, prog, NULL)) goto bail; glamor_set_color(pixmap, gc->fgPixel, prog->fg_uniform); glamor_set_color(pixmap, gc->bgPixel, prog->bg_uniform); break; default: goto bail; } /* Set the dash pattern as texture 1 */ glamor_bind_texture(glamor_priv, GL_TEXTURE1, dash_priv->fbo, FALSE); glUniform1i(prog->dash_uniform, 1); glUniform1f(prog->dash_length_uniform, dash_pixmap->drawable.width); return prog; bail: return NULL; }
static Bool glamor_fill_spans_gl(DrawablePtr drawable, GCPtr gc, int n, DDXPointPtr points, int *widths, int sorted) { ScreenPtr screen = drawable->pScreen; glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable); glamor_pixmap_private *pixmap_priv; glamor_program *prog; int off_x, off_y; GLshort *v; char *vbo_offset; int c; int box_x, box_y; pixmap_priv = glamor_get_pixmap_private(pixmap); if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) goto bail; glamor_make_current(glamor_priv); if (glamor_priv->glsl_version >= 130) { prog = glamor_use_program_fill(pixmap, gc, &glamor_priv->fill_spans_program, &glamor_facet_fillspans_130); if (!prog) goto bail_ctx; /* Set up the vertex buffers for the points */ v = glamor_get_vbo_space(drawable->pScreen, n * (4 * sizeof (GLshort)), &vbo_offset); glEnableVertexAttribArray(GLAMOR_VERTEX_POS); glVertexAttribDivisor(GLAMOR_VERTEX_POS, 1); glVertexAttribPointer(GLAMOR_VERTEX_POS, 3, GL_SHORT, GL_FALSE, 4 * sizeof (GLshort), vbo_offset); for (c = 0; c < n; c++) { v[0] = points->x; v[1] = points->y; v[2] = *widths++; points++; v += 4; } glamor_put_vbo_space(screen); } else { prog = glamor_use_program_fill(pixmap, gc, &glamor_priv->fill_spans_program, &glamor_facet_fillspans_120); if (!prog) goto bail_ctx; /* Set up the vertex buffers for the points */ v = glamor_get_vbo_space(drawable->pScreen, n * 8 * sizeof (short), &vbo_offset); glEnableVertexAttribArray(GLAMOR_VERTEX_POS); glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_SHORT, GL_FALSE, 2 * sizeof (short), vbo_offset); for (c = 0; c < n; c++) { v[0] = points->x; v[1] = points->y; v[2] = points->x; v[3] = points->y + 1; v[4] = points->x + *widths; v[5] = points->y + 1; v[6] = points->x + *widths; v[7] = points->y; widths++; points++; v += 8; } glamor_put_vbo_space(screen); } glEnable(GL_SCISSOR_TEST); glamor_pixmap_loop(pixmap_priv, box_x, box_y) { int nbox = RegionNumRects(gc->pCompositeClip); BoxPtr box = RegionRects(gc->pCompositeClip); glamor_set_destination_drawable(drawable, box_x, box_y, FALSE, FALSE, prog->matrix_uniform, &off_x, &off_y); while (nbox--) { glScissor(box->x1 + off_x, box->y1 + off_y, box->x2 - box->x1, box->y2 - box->y1); box++; if (glamor_priv->glsl_version >= 130) glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, n); else { if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) { glDrawArrays(GL_QUADS, 0, 4 * n); } else { int i; for (i = 0; i < n; i++) { glDrawArrays(GL_TRIANGLE_FAN, i * 4, 4); } } } } }
static Bool glamor_poly_glyph_blt_gl(DrawablePtr drawable, GCPtr gc, int start_x, int y, unsigned int nglyph, CharInfoPtr *ppci, void *pglyph_base) { ScreenPtr screen = drawable->pScreen; glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable); glamor_pixmap_private *pixmap_priv; glamor_program *prog; RegionPtr clip = gc->pCompositeClip; int box_index; pixmap_priv = glamor_get_pixmap_private(pixmap); if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) goto bail; glamor_make_current(glamor_priv); prog = glamor_use_program_fill(pixmap, gc, &glamor_priv->poly_glyph_blt_progs, &glamor_facet_poly_glyph_blt); if (!prog) goto bail; glEnableVertexAttribArray(GLAMOR_VERTEX_POS); start_x += drawable->x; y += drawable->y; glamor_pixmap_loop(pixmap_priv, box_index) { int x; int n; int num_points, max_points; INT16 *points = NULL; int off_x, off_y; char *vbo_offset; glamor_set_destination_drawable(drawable, box_index, FALSE, TRUE, prog->matrix_uniform, &off_x, &off_y); max_points = 500; num_points = 0; x = start_x; for (n = 0; n < nglyph; n++) { CharInfoPtr charinfo = ppci[n]; int w = GLYPHWIDTHPIXELS(charinfo); int h = GLYPHHEIGHTPIXELS(charinfo); uint8_t *glyphbits = FONTGLYPHBITS(NULL, charinfo); if (w && h) { int glyph_x = x + charinfo->metrics.leftSideBearing; int glyph_y = y - charinfo->metrics.ascent; int glyph_stride = GLYPHWIDTHBYTESPADDED(charinfo); int xx, yy; for (yy = 0; yy < h; yy++) { uint8_t *glyph = glyphbits; for (xx = 0; xx < w; glyph += ((xx&7) == 7), xx++) { int pt_x_i = glyph_x + xx; int pt_y_i = glyph_y + yy; if (!(*glyph & (1 << (xx & 7)))) continue; if (!RegionContainsPoint(clip, pt_x_i, pt_y_i, NULL)) continue; if (!num_points) { points = glamor_get_vbo_space(screen, max_points * (2 * sizeof (INT16)), &vbo_offset); glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_SHORT, GL_FALSE, 0, vbo_offset); } *points++ = pt_x_i; *points++ = pt_y_i; num_points++; if (num_points == max_points) { glamor_put_vbo_space(screen); glDrawArrays(GL_POINTS, 0, num_points); num_points = 0; } } glyphbits += glyph_stride; } } x += charinfo->metrics.characterWidth; } if (num_points) { glamor_put_vbo_space(screen); glDrawArrays(GL_POINTS, 0, num_points); } }
/* * Write a region of bits into a pixmap */ void glamor_upload_boxes(PixmapPtr pixmap, BoxPtr in_boxes, int in_nbox, int dx_src, int dy_src, int dx_dst, int dy_dst, uint8_t *bits, uint32_t byte_stride) { ScreenPtr screen = pixmap->drawable.pScreen; glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap); int box_index; int bytes_per_pixel = pixmap->drawable.bitsPerPixel >> 3; GLenum type; GLenum format; glamor_format_for_pixmap(pixmap, &format, &type); glamor_make_current(glamor_priv); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); if (glamor_priv->has_unpack_subimage) glPixelStorei(GL_UNPACK_ROW_LENGTH, byte_stride / bytes_per_pixel); glamor_pixmap_loop(priv, box_index) { BoxPtr box = glamor_pixmap_box_at(priv, box_index); glamor_pixmap_fbo *fbo = glamor_pixmap_fbo_at(priv, box_index); BoxPtr boxes = in_boxes; int nbox = in_nbox; glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, fbo->tex); while (nbox--) { /* compute drawable coordinates */ int x1 = MAX(boxes->x1 + dx_dst, box->x1); int x2 = MIN(boxes->x2 + dx_dst, box->x2); int y1 = MAX(boxes->y1 + dy_dst, box->y1); int y2 = MIN(boxes->y2 + dy_dst, box->y2); size_t ofs = (y1 - dy_dst + dy_src) * byte_stride; ofs += (x1 - dx_dst + dx_src) * bytes_per_pixel; boxes++; if (x2 <= x1 || y2 <= y1) continue; if (glamor_priv->has_unpack_subimage || x2 - x1 == byte_stride / bytes_per_pixel) { glTexSubImage2D(GL_TEXTURE_2D, 0, x1 - box->x1, y1 - box->y1, x2 - x1, y2 - y1, format, type, bits + ofs); } else { for (; y1 < y2; y1++, ofs += byte_stride) glTexSubImage2D(GL_TEXTURE_2D, 0, x1 - box->x1, y1 - box->y1, x2 - x1, 1, format, type, bits + ofs); } } }
static Bool _glamor_upload_bits_to_pixmap_texture(PixmapPtr pixmap, GLenum format, GLenum type, int no_alpha, int revert, int swap_rb, int x, int y, int w, int h, int stride, void *bits, int pbo) { ScreenPtr screen = pixmap->drawable.pScreen; glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap); glamor_screen_private *glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen); float dst_xscale, dst_yscale; GLuint tex = 0; int need_free_bits = 0; if (bits == NULL) goto ready_to_upload; if (revert > REVERT_NORMAL) { /* XXX if we are restoring the pixmap, then we may not need to allocate * new buffer */ void *converted_bits; if (pixmap->drawable.depth == 1) stride = (((w * 8 + 7) / 8) + 3) & ~3; converted_bits = xallocarray(h, stride); if (converted_bits == NULL) return FALSE; bits = glamor_color_convert_to_bits(bits, converted_bits, w, h, stride, no_alpha, revert, swap_rb); if (bits == NULL) { free(converted_bits); ErrorF("Failed to convert pixmap no_alpha %d," "revert mode %d, swap mode %d\n", no_alpha, revert, swap_rb); return FALSE; } no_alpha = 0; revert = REVERT_NONE; swap_rb = SWAP_NONE_UPLOADING; need_free_bits = TRUE; } ready_to_upload: /* Try fast path firstly, upload the pixmap to the texture attached * to the fbo directly. */ if (no_alpha == 0 && revert == REVERT_NONE && swap_rb == SWAP_NONE_UPLOADING #ifdef WALKAROUND_LARGE_TEXTURE_MAP && glamor_pixmap_priv_is_small(pixmap_priv) #endif ) { int fbo_x_off, fbo_y_off; assert(pixmap_priv->fbo->tex); pixmap_priv_get_fbo_off(pixmap_priv, &fbo_x_off, &fbo_y_off); assert(x + fbo_x_off >= 0 && y + fbo_y_off >= 0); assert(x + fbo_x_off + w <= pixmap_priv->fbo->width); assert(y + fbo_y_off + h <= pixmap_priv->fbo->height); if (!__glamor_upload_pixmap_to_texture(pixmap, &pixmap_priv->fbo->tex, format, type, x + fbo_x_off, y + fbo_y_off, w, h, bits, pbo)) { if (need_free_bits) free(bits); return FALSE; } } else { static const float texcoords_inv[8] = { 0, 0, 1, 0, 1, 1, 0, 1 }; GLfloat *v; char *vbo_offset; v = glamor_get_vbo_space(screen, 16 * sizeof(GLfloat), &vbo_offset); pixmap_priv_get_dest_scale(pixmap, pixmap_priv, &dst_xscale, &dst_yscale); glamor_set_normalize_vcoords(pixmap_priv, dst_xscale, dst_yscale, x, y, x + w, y + h, v); /* Slow path, we need to flip y or wire alpha to 1. */ glamor_make_current(glamor_priv); if (!__glamor_upload_pixmap_to_texture(pixmap, &tex, format, type, 0, 0, w, h, bits, pbo)) { if (need_free_bits) free(bits); return FALSE; } memcpy(&v[8], texcoords_inv, 8 * sizeof(GLfloat)); glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), vbo_offset); glEnableVertexAttribArray(GLAMOR_VERTEX_POS); glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), vbo_offset + 8 * sizeof(GLfloat)); glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE); glamor_put_vbo_space(screen); glamor_set_destination_pixmap_priv_nc(glamor_priv, pixmap, pixmap_priv); glamor_set_alu(screen, GXcopy); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glUseProgram(glamor_priv->finish_access_prog[no_alpha]); glUniform1i(glamor_priv->finish_access_revert[no_alpha], revert); glUniform1i(glamor_priv->finish_access_swap_rb[no_alpha], swap_rb); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableVertexAttribArray(GLAMOR_VERTEX_POS); glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE); glDeleteTextures(1, &tex); glBindFramebuffer(GL_FRAMEBUFFER, 0); } if (need_free_bits) free(bits); return TRUE; }
static Bool glamor_poly_fill_rect_gl(DrawablePtr drawable, GCPtr gc, int nrect, xRectangle *prect) { ScreenPtr screen = drawable->pScreen; glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable); glamor_pixmap_private *pixmap_priv; glamor_program *prog; int off_x, off_y; GLshort *v; char *vbo_offset; int box_x, box_y; pixmap_priv = glamor_get_pixmap_private(pixmap); if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) goto bail; glamor_make_current(glamor_priv); if (glamor_priv->glsl_version >= 130) { prog = glamor_use_program_fill(pixmap, gc, &glamor_priv->poly_fill_rect_program, &glamor_facet_polyfillrect_130); if (!prog) goto bail; /* Set up the vertex buffers for the points */ v = glamor_get_vbo_space(drawable->pScreen, nrect * sizeof (xRectangle), &vbo_offset); glEnableVertexAttribArray(GLAMOR_VERTEX_POS); glVertexAttribDivisor(GLAMOR_VERTEX_POS, 1); glVertexAttribPointer(GLAMOR_VERTEX_POS, 4, GL_SHORT, GL_FALSE, 4 * sizeof (short), vbo_offset); memcpy(v, prect, nrect * sizeof (xRectangle)); glamor_put_vbo_space(screen); } else { int n; prog = glamor_use_program_fill(pixmap, gc, &glamor_priv->poly_fill_rect_program, &glamor_facet_polyfillrect_120); if (!prog) goto bail; /* Set up the vertex buffers for the points */ v = glamor_get_vbo_space(drawable->pScreen, nrect * 8 * sizeof (short), &vbo_offset); glEnableVertexAttribArray(GLAMOR_VERTEX_POS); glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_SHORT, GL_FALSE, 2 * sizeof (short), vbo_offset); for (n = 0; n < nrect; n++) { v[0] = prect->x; v[1] = prect->y; v[2] = prect->x; v[3] = prect->y + prect->height; v[4] = prect->x + prect->width; v[5] = prect->y + prect->height; v[6] = prect->x + prect->width; v[7] = prect->y; prect++; v += 8; } glamor_put_vbo_space(screen); } glEnable(GL_SCISSOR_TEST); glamor_pixmap_loop(pixmap_priv, box_x, box_y) { int nbox = RegionNumRects(gc->pCompositeClip); BoxPtr box = RegionRects(gc->pCompositeClip); glamor_set_destination_drawable(drawable, box_x, box_y, TRUE, FALSE, prog->matrix_uniform, &off_x, &off_y); while (nbox--) { glScissor(box->x1 + off_x, box->y1 + off_y, box->x2 - box->x1, box->y2 - box->y1); box++; if (glamor_priv->glsl_version >= 130) glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, nrect); else { glamor_glDrawArrays_GL_QUADS(glamor_priv, nrect); } } }
static Bool glamor_copy_fbo_fbo_draw(DrawablePtr src, DrawablePtr dst, GCPtr gc, BoxPtr box, int nbox, int dx, int dy, Bool reverse, Bool upsidedown, Pixel bitplane, void *closure) { ScreenPtr screen = dst->pScreen; glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src); PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst); glamor_pixmap_private *src_priv = glamor_get_pixmap_private(src_pixmap); glamor_pixmap_private *dst_priv = glamor_get_pixmap_private(dst_pixmap); int src_box_index, dst_box_index; int dst_off_x, dst_off_y; int src_off_x, src_off_y; GLshort *v; char *vbo_offset; struct copy_args args; glamor_program *prog; const glamor_facet *copy_facet; int n; glamor_make_current(glamor_priv); if (gc && !glamor_set_planemask(gc->depth, gc->planemask)) goto bail_ctx; if (!glamor_set_alu(screen, gc ? gc->alu : GXcopy)) goto bail_ctx; if (bitplane && !glamor_priv->can_copyplane) goto bail_ctx; if (bitplane) { prog = &glamor_priv->copy_plane_prog; copy_facet = &glamor_facet_copyplane; } else { prog = &glamor_priv->copy_area_prog; copy_facet = &glamor_facet_copyarea; } if (prog->failed) goto bail_ctx; if (!prog->prog) { if (!glamor_build_program(screen, prog, copy_facet, NULL, NULL, NULL)) goto bail_ctx; } args.src_pixmap = src_pixmap; args.bitplane = bitplane; /* Set up the vertex buffers for the points */ v = glamor_get_vbo_space(dst->pScreen, nbox * 8 * sizeof (int16_t), &vbo_offset); glEnableVertexAttribArray(GLAMOR_VERTEX_POS); glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_SHORT, GL_FALSE, 2 * sizeof (GLshort), vbo_offset); for (n = 0; n < nbox; n++) { v[0] = box->x1; v[1] = box->y1; v[2] = box->x1; v[3] = box->y2; v[4] = box->x2; v[5] = box->y2; v[6] = box->x2; v[7] = box->y1; v += 8; box++; } glamor_put_vbo_space(screen); glamor_get_drawable_deltas(src, src_pixmap, &src_off_x, &src_off_y); glEnable(GL_SCISSOR_TEST); glamor_pixmap_loop(src_priv, src_box_index) { BoxPtr src_box = glamor_pixmap_box_at(src_priv, src_box_index); args.dx = dx + src_off_x - src_box->x1; args.dy = dy + src_off_y - src_box->y1; args.src = glamor_pixmap_fbo_at(src_priv, src_box_index); if (!glamor_use_program(dst_pixmap, gc, prog, &args)) goto bail_ctx; glamor_pixmap_loop(dst_priv, dst_box_index) { glamor_set_destination_drawable(dst, dst_box_index, FALSE, FALSE, prog->matrix_uniform, &dst_off_x, &dst_off_y); glScissor(dst_off_x - args.dx, dst_off_y - args.dy, src_box->x2 - src_box->x1, src_box->y2 - src_box->y1); glamor_glDrawArrays_GL_QUADS(glamor_priv, nbox); }
/** * Implements CopyPlane and CopyArea from the GPU to the GPU by using * the source as a texture and painting that into the destination. * * This requires that source and dest are different textures, or that * (if the copy area doesn't overlap), GL_NV_texture_barrier is used * to ensure that the caches are flushed at the right times. */ static Bool glamor_copy_cpu_fbo(DrawablePtr src, DrawablePtr dst, GCPtr gc, BoxPtr box, int nbox, int dx, int dy, Bool reverse, Bool upsidedown, Pixel bitplane, void *closure) { ScreenPtr screen = dst->pScreen; glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst); FbBits *src_bits; FbStride src_stride; int src_bpp; int src_xoff, src_yoff; int dst_xoff, dst_yoff; if (gc && gc->alu != GXcopy) goto bail; if (gc && !glamor_pm_is_solid(gc->depth, gc->planemask)) goto bail; glamor_make_current(glamor_priv); glamor_prepare_access(src, GLAMOR_ACCESS_RO); glamor_get_drawable_deltas(dst, dst_pixmap, &dst_xoff, &dst_yoff); if (bitplane) { PixmapPtr src_pix = fbCreatePixmap(screen, dst_pixmap->drawable.width, dst_pixmap->drawable.height, dst->depth, 0); if (!src_pix) { glamor_finish_access(src); goto bail; } src_pix->drawable.x = -dst->x; src_pix->drawable.y = -dst->y; fbGetDrawable(&src_pix->drawable, src_bits, src_stride, src_bpp, src_xoff, src_yoff); if (src->bitsPerPixel > 1) fbCopyNto1(src, &src_pix->drawable, gc, box, nbox, dx, dy, reverse, upsidedown, bitplane, closure); else fbCopy1toN(src, &src_pix->drawable, gc, box, nbox, dx, dy, reverse, upsidedown, bitplane, closure); glamor_upload_boxes(dst_pixmap, box, nbox, src_xoff, src_yoff, dst_xoff, dst_yoff, (uint8_t *) src_bits, src_stride * sizeof(FbBits)); fbDestroyPixmap(src_pix); } else { fbGetDrawable(src, src_bits, src_stride, src_bpp, src_xoff, src_yoff); glamor_upload_boxes(dst_pixmap, box, nbox, src_xoff + dx, src_yoff + dy, dst_xoff, dst_yoff, (uint8_t *) src_bits, src_stride * sizeof (FbBits)); } glamor_finish_access(src); return TRUE; bail: return FALSE; }