static Bool glamor_get_image_gl(DrawablePtr drawable, int x, int y, int w, int h, unsigned int format, unsigned long plane_mask, char *d) { PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable); glamor_pixmap_private *pixmap_priv; uint32_t byte_stride = PixmapBytePad(w, drawable->depth); BoxRec box; int off_x, off_y; pixmap_priv = glamor_get_pixmap_private(pixmap); if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) goto bail; if (format != ZPixmap || !glamor_pm_is_solid(drawable, plane_mask)) goto bail; glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y); box.x1 = x; box.x2 = x + w; box.y1 = y; box.y2 = y + h; glamor_download_boxes(pixmap, &box, 1, drawable->x + off_x, drawable->y + off_y, -x, -y, (uint8_t *) d, byte_stride); return TRUE; bail: return FALSE; }
/* * We should already have drawable attached to it, if it has one. * Then set the attached pixmap to is_picture format, and set * the pict format. * */ int glamor_create_picture(PicturePtr picture) { PixmapPtr pixmap; glamor_pixmap_private *pixmap_priv; if (!picture || !picture->pDrawable) return 0; pixmap = glamor_get_drawable_pixmap(picture->pDrawable); pixmap_priv = glamor_get_pixmap_private(pixmap); if (!pixmap_priv) { /* We must create a pixmap priv to track the picture format even * if the pixmap is a pure in memory pixmap. The reason is that * we may need to upload this pixmap to a texture on the fly. During * the uploading, we need to know the picture format. */ glamor_set_pixmap_type(pixmap, GLAMOR_MEMORY); pixmap_priv = glamor_get_pixmap_private(pixmap); } else { if (GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) { /* If the picture format is not compatible with glamor fbo format, * we have to mark this pixmap as a separated texture, and don't * fallback to DDX layer. */ if (pixmap_priv->type == GLAMOR_TEXTURE_DRM && !glamor_pict_format_is_compatible(picture)) glamor_set_pixmap_type(pixmap, GLAMOR_SEPARATE_TEXTURE); } } pixmap_priv->base.is_picture = 1; pixmap_priv->base.picture = picture; return miCreatePicture(picture); }
int glamor_set_destination_pixmap_priv(glamor_pixmap_private *pixmap_priv) { if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) return -1; glamor_set_destination_pixmap_priv_nc(pixmap_priv); return 0; }
static Bool glamor_put_image_gl(DrawablePtr drawable, GCPtr gc, int depth, int x, int y, int w, int h, int leftPad, int format, char *bits) { 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; uint32_t byte_stride = PixmapBytePad(w, drawable->depth); RegionRec region; BoxRec box; int off_x, off_y; pixmap_priv = glamor_get_pixmap_private(pixmap); if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) return FALSE; if (gc->alu != GXcopy) goto bail; if (!glamor_pm_is_solid(&pixmap->drawable, gc->planemask)) goto bail; if (format == XYPixmap && drawable->depth == 1 && leftPad == 0) format = ZPixmap; if (format != ZPixmap) goto bail; x += drawable->x; y += drawable->y; box.x1 = x; box.y1 = y; box.x2 = box.x1 + w; box.y2 = box.y1 + h; RegionInit(®ion, &box, 1); RegionIntersect(®ion, ®ion, gc->pCompositeClip); glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y); if (off_x || off_y) { x += off_x; y += off_y; RegionTranslate(®ion, off_x, off_y); } glamor_make_current(glamor_priv); glamor_upload_region(pixmap, ®ion, x, y, (uint8_t *) bits, byte_stride); RegionUninit(®ion); return TRUE; bail: return FALSE; }
static Bool _glamor_get_spans(DrawablePtr drawable, int wmax, DDXPointPtr points, int *widths, int count, char *dst, Bool fallback) { PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable); glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap); int i; uint8_t *readpixels_dst = (uint8_t *) dst; int x_off, y_off; Bool ret = FALSE; if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) goto fail; glamor_get_drawable_deltas(drawable, pixmap, &x_off, &y_off); for (i = 0; i < count; i++) { #ifdef DEBUG void *data = #endif glamor_download_sub_pixmap_to_cpu(pixmap, points[i].x + x_off, points[i].y + y_off, widths[i], 1, PixmapBytePad(widths[i], drawable->depth), readpixels_dst, 0, GLAMOR_ACCESS_RO); assert(data == readpixels_dst); readpixels_dst += PixmapBytePad(widths[i], drawable->depth); } ret = TRUE; goto done; fail: if (!fallback && glamor_ddx_fallback_check_pixmap(drawable)) goto done; ret = TRUE; if (glamor_prepare_access(drawable, GLAMOR_ACCESS_RO)) { fbGetSpans(drawable, wmax, points, widths, count, dst); } glamor_finish_access(drawable); done: return ret; }
Bool glamor_solid_boxes(PixmapPtr pixmap, BoxPtr box, int nbox, unsigned long fg_pixel) { glamor_pixmap_private *pixmap_priv; GLfloat color[4]; pixmap_priv = glamor_get_pixmap_private(pixmap); if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) return FALSE; glamor_get_rgba_from_pixel(fg_pixel, &color[0], &color[1], &color[2], &color[3], format_for_pixmap(pixmap)); if (pixmap_priv->type == GLAMOR_TEXTURE_LARGE) { RegionRec region; int n_region; glamor_pixmap_clipped_regions *clipped_regions; int i; RegionInitBoxes(®ion, box, nbox); clipped_regions = glamor_compute_clipped_regions(pixmap_priv, ®ion, &n_region, 0, 0, 0); for (i = 0; i < n_region; i++) { BoxPtr inner_box; int inner_nbox; SET_PIXMAP_FBO_CURRENT(pixmap_priv, clipped_regions[i].block_idx); inner_box = RegionRects(clipped_regions[i].region); inner_nbox = RegionNumRects(clipped_regions[i].region); _glamor_solid_boxes(pixmap, inner_box, inner_nbox, color); RegionDestroy(clipped_regions[i].region); } free(clipped_regions); RegionUninit(®ion); } else _glamor_solid_boxes(pixmap, box, nbox, color); return TRUE; }
Bool glamor_solid(PixmapPtr pixmap, int x, int y, int width, int height, unsigned char alu, unsigned long planemask, unsigned long fg_pixel) { ScreenPtr screen = pixmap->drawable.pScreen; glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); glamor_pixmap_private *pixmap_priv; BoxRec box; pixmap_priv = glamor_get_pixmap_private(pixmap); if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) return FALSE; if (!glamor_set_planemask(pixmap, planemask)) { glamor_fallback("Failedto set planemask in glamor_solid.\n"); return FALSE; } glamor_get_context(glamor_priv); if (!glamor_set_alu(screen, alu)) { if (alu == GXclear) fg_pixel = 0; else { glamor_fallback("unsupported alu %x\n", alu); glamor_put_context(glamor_priv); return FALSE; } } box.x1 = x; box.y1 = y; box.x2 = x + width; box.y2 = y + height; glamor_solid_boxes(pixmap, &box, 1, fg_pixel); glamor_set_alu(screen, GXcopy); glamor_put_context(glamor_priv); return TRUE; }
Bool glamor_set_texture_pixmap(PixmapPtr texture) { glamor_pixmap_private *texture_priv; texture_priv = glamor_get_pixmap_private(texture); if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(texture_priv)) return FALSE; if (glamor_pixmap_priv_is_large(texture_priv)) return FALSE; glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture_priv->fbo->tex); /* we're not setting the sampler uniform here as we always use * GL_TEXTURE0, and the default value for uniforms is zero. So, * save a bit of CPU time by taking advantage of that. */ return TRUE; }
Bool glamor_set_texture_pixmap(PixmapPtr texture, Bool destination_red) { glamor_pixmap_private *texture_priv; texture_priv = glamor_get_pixmap_private(texture); if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(texture_priv)) return FALSE; if (glamor_pixmap_priv_is_large(texture_priv)) return FALSE; glamor_bind_texture(glamor_get_screen_private(texture->drawable.pScreen), GL_TEXTURE0, texture_priv->fbo, destination_red); /* we're not setting the sampler uniform here as we always use * GL_TEXTURE0, and the default value for uniforms is zero. So, * save a bit of CPU time by taking advantage of that. */ return TRUE; }
static Bool _glamor_put_image(DrawablePtr drawable, GCPtr gc, int depth, int x, int y, int w, int h, int left_pad, int image_format, char *bits, Bool fallback) { PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable); glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap); RegionPtr clip; int x_off, y_off; Bool ret = FALSE; PixmapPtr temp_pixmap, sub_pixmap; glamor_pixmap_private *temp_pixmap_priv; BoxRec box; int stride; glamor_get_drawable_deltas(drawable, pixmap, &x_off, &y_off); clip = fbGetCompositeClip(gc); if (image_format == XYBitmap) { assert(depth == 1); goto fail; } if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) { glamor_fallback("has no fbo.\n"); goto fail; } if (image_format != ZPixmap) { glamor_fallback("non-ZPixmap\n"); goto fail; } if (!glamor_set_planemask(pixmap, gc->planemask)) { goto fail; } /* create a temporary pixmap and upload the bits to that * pixmap, then apply clip copy it to the destination pixmap.*/ stride = PixmapBytePad(w, depth); box.x1 = x + drawable->x; box.y1 = y + drawable->y; box.x2 = x + w + drawable->x; box.y2 = y + h + drawable->y; if ((clip != NULL && RegionContainsRect(clip, &box) != rgnIN) || gc->alu != GXcopy) { temp_pixmap = glamor_create_pixmap(drawable->pScreen, w, h, depth, 0); if (temp_pixmap == NULL) goto fail; temp_pixmap_priv = glamor_get_pixmap_private(temp_pixmap); if (GLAMOR_PIXMAP_PRIV_IS_PICTURE(pixmap_priv)) { temp_pixmap_priv->base.picture = pixmap_priv->base.picture; temp_pixmap_priv->base.is_picture = pixmap_priv->base.is_picture; } glamor_upload_sub_pixmap_to_texture(temp_pixmap, 0, 0, w, h, stride, bits, 0); glamor_copy_area(&temp_pixmap->drawable, drawable, gc, 0, 0, w, h, x, y); glamor_destroy_pixmap(temp_pixmap); } else { glamor_upload_sub_pixmap_to_texture(pixmap, x + drawable->x + x_off, y + drawable->y + y_off, w, h, stride, bits, 0); } ret = TRUE; goto done; fail: glamor_set_planemask(pixmap, ~0); if (!fallback && glamor_ddx_fallback_check_pixmap(&pixmap->drawable)) goto done; glamor_fallback("to %p (%c)\n", drawable, glamor_get_drawable_location(drawable)); sub_pixmap = glamor_get_sub_pixmap(pixmap, x + x_off + drawable->x, y + y_off + drawable->y, w, h, GLAMOR_ACCESS_RW); if (sub_pixmap) { if (clip != NULL) pixman_region_translate (clip, -x - drawable->x, -y - drawable->y); fbPutImage(&sub_pixmap->drawable, gc, depth, 0, 0, w, h, left_pad, image_format, bits); glamor_put_sub_pixmap(sub_pixmap, pixmap, x + x_off + drawable->x, y + y_off + drawable->y, w, h, GLAMOR_ACCESS_RW); if (clip != NULL) pixman_region_translate (clip, x + drawable->x, y + drawable->y); } else fbPutImage(drawable, gc, depth, x, y, w, h, left_pad, image_format, bits); ret = TRUE; done: return ret; }
Bool glamor_tile(PixmapPtr pixmap, PixmapPtr tile, int x, int y, int width, int height, unsigned char alu, unsigned long planemask, int tile_x, int tile_y) { ScreenPtr screen = pixmap->drawable.pScreen; glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); glamor_pixmap_private *dst_pixmap_priv; glamor_pixmap_private *src_pixmap_priv; dst_pixmap_priv = glamor_get_pixmap_private(pixmap); src_pixmap_priv = glamor_get_pixmap_private(tile); if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dst_pixmap_priv)) return FALSE; if (glamor_priv->tile_prog == 0) { glamor_fallback("Tiling unsupported\n"); goto fail; } if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(src_pixmap_priv)) { /* XXX dynamic uploading candidate. */ glamor_fallback("Non-texture tile pixmap\n"); goto fail; } if (!glamor_set_planemask(pixmap, planemask)) { glamor_fallback("unsupported planemask %lx\n", planemask); goto fail; } glamor_make_current(glamor_priv); if (!glamor_set_alu(screen, alu)) { glamor_fallback("unsupported alu %x\n", alu); goto fail; } if (dst_pixmap_priv->type == GLAMOR_TEXTURE_LARGE || src_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) { glamor_pixmap_clipped_regions *clipped_dst_regions; int n_dst_region, i, j, k; BoxRec box; RegionRec region; box.x1 = x; box.y1 = y; box.x2 = x + width; box.y2 = y + height; RegionInitBoxes(®ion, &box, 1); clipped_dst_regions = glamor_compute_clipped_regions(dst_pixmap_priv, ®ion, &n_dst_region, 0, 0, 0); for (i = 0; i < n_dst_region; i++) { int n_src_region; glamor_pixmap_clipped_regions *clipped_src_regions; BoxPtr current_boxes; int n_current_boxes; SET_PIXMAP_FBO_CURRENT(dst_pixmap_priv, clipped_dst_regions[i].block_idx); if (src_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) { RegionTranslate(clipped_dst_regions[i].region, tile_x - x, tile_y - y); DEBUGF("tiled a large src pixmap. %dx%d \n", tile->drawable.width, tile->drawable.height); clipped_src_regions = glamor_compute_clipped_regions(src_pixmap_priv, clipped_dst_regions[i]. region, &n_src_region, 1, 0, 0); DEBUGF("got %d src regions %d \n", n_src_region); for (j = 0; j < n_src_region; j++) { SET_PIXMAP_FBO_CURRENT(src_pixmap_priv, clipped_src_regions[j].block_idx); RegionTranslate(clipped_src_regions[j].region, x - tile_x, y - tile_y); current_boxes = RegionRects(clipped_src_regions[j].region); n_current_boxes = RegionNumRects(clipped_src_regions[j].region); for (k = 0; k < n_current_boxes; k++) { DEBUGF ("Tile on %d %d %d %d dst block id %d tile block id %d tilex %d tiley %d\n", current_boxes[k].x1, current_boxes[k].y1, current_boxes[k].x2 - current_boxes[k].x1, current_boxes[k].y2 - current_boxes[k].y1, clipped_dst_regions[i].block_idx, clipped_src_regions[j].block_idx, (tile_x + (current_boxes[k].x1 - x)), tile_y + (current_boxes[k].y1 - y)); _glamor_tile(pixmap, tile, current_boxes[k].x1, current_boxes[k].y1, current_boxes[k].x2 - current_boxes[k].x1, current_boxes[k].y2 - current_boxes[k].y1, (tile_x + (current_boxes[k].x1 - x)), (tile_y + (current_boxes[k].y1 - y))); } RegionDestroy(clipped_src_regions[j].region); } free(clipped_src_regions); } else { current_boxes = RegionRects(clipped_dst_regions[i].region); n_current_boxes = RegionNumRects(clipped_dst_regions[i].region); for (k = 0; k < n_current_boxes; k++) { _glamor_tile(pixmap, tile, current_boxes[k].x1, current_boxes[k].y1, current_boxes[k].x2 - current_boxes[k].x1, current_boxes[k].y2 - current_boxes[k].y1, (tile_x + (current_boxes[k].x1 - x)), (tile_y + (current_boxes[k].y1 - y))); } } RegionDestroy(clipped_dst_regions[i].region); } free(clipped_dst_regions); RegionUninit(®ion); } else _glamor_tile(pixmap, tile, x, y, width, height, tile_x, tile_y); glamor_set_alu(screen, GXcopy); return TRUE; fail: return FALSE; }
static Bool _glamor_copy_n_to_n(DrawablePtr src, DrawablePtr dst, GCPtr gc, BoxPtr box, int nbox, int dx, int dy, Bool reverse, Bool upsidedown, Pixel bitplane, void *closure, Bool fallback) { PixmapPtr dst_pixmap, src_pixmap; glamor_pixmap_private *dst_pixmap_priv, *src_pixmap_priv; glamor_screen_private *glamor_priv; glamor_gl_dispatch *dispatch; BoxPtr extent; RegionRec region; int src_x_off, src_y_off, dst_x_off, dst_y_off; Bool ok = FALSE; int force_clip = 0; if (nbox == 0) return TRUE; dst_pixmap = glamor_get_drawable_pixmap(dst); dst_pixmap_priv = glamor_get_pixmap_private(dst_pixmap); src_pixmap = glamor_get_drawable_pixmap(src); src_pixmap_priv = glamor_get_pixmap_private(src_pixmap); glamor_priv = glamor_get_screen_private(dst->pScreen); DEBUGF("Copy %d %d %dx%d dx %d dy %d from %p to %p \n", box[0].x1, box[0].y1, box[0].x2 - box[0].x1, box[0].y2 - box[0].y1, dx, dy, src_pixmap, dst_pixmap); if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dst_pixmap_priv)) goto fall_back; if (gc) { if (!glamor_set_planemask(dst_pixmap, gc->planemask)) goto fall_back; dispatch = glamor_get_dispatch(glamor_priv); if (!glamor_set_alu(dispatch, gc->alu)) { glamor_put_dispatch(glamor_priv); goto fail_noregion; } glamor_put_dispatch(glamor_priv); } if (!src_pixmap_priv) { glamor_set_pixmap_type(src_pixmap, GLAMOR_MEMORY); src_pixmap_priv = glamor_get_pixmap_private(src_pixmap); } glamor_get_drawable_deltas(src, src_pixmap, &src_x_off, &src_y_off); glamor_get_drawable_deltas(dst, dst_pixmap, &dst_x_off, &dst_y_off); RegionInitBoxes(®ion, box, nbox); extent = RegionExtents(®ion); if (!glamor_check_fbo_size(glamor_priv, extent->x2 - extent->x1, extent->y2 - extent->y1) && (src_pixmap_priv->type == GLAMOR_MEMORY || (src_pixmap_priv == dst_pixmap_priv))) { force_clip = 1; } if (force_clip || dst_pixmap_priv->type == GLAMOR_TEXTURE_LARGE || src_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) { glamor_pixmap_clipped_regions *clipped_dst_regions; int n_dst_region, i, j; PixmapPtr temp_source_pixmap; glamor_pixmap_private *temp_source_priv = NULL; RegionTranslate(®ion, dst_x_off, dst_y_off); if (!force_clip) clipped_dst_regions = glamor_compute_clipped_regions(dst_pixmap_priv, ®ion, &n_dst_region, 0, reverse, upsidedown); else clipped_dst_regions = glamor_compute_clipped_regions_ext(dst_pixmap_priv, ®ion, &n_dst_region, glamor_priv->max_fbo_size, glamor_priv->max_fbo_size, reverse, upsidedown); for(i = 0; i < n_dst_region; i++) { int n_src_region; glamor_pixmap_clipped_regions *clipped_src_regions; BoxPtr current_boxes; int n_current_boxes; SET_PIXMAP_FBO_CURRENT(dst_pixmap_priv, clipped_dst_regions[i].block_idx); temp_source_pixmap = NULL; if (src_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) { RegionTranslate(clipped_dst_regions[i].region, -dst_x_off + src_x_off + dx, -dst_y_off + src_y_off + dy); clipped_src_regions = glamor_compute_clipped_regions(src_pixmap_priv, clipped_dst_regions[i].region, &n_src_region, 0, reverse, upsidedown); DEBUGF("Source is large pixmap.\n"); for (j = 0; j < n_src_region; j++) { if (src_pixmap_priv != dst_pixmap_priv) SET_PIXMAP_FBO_CURRENT(src_pixmap_priv, clipped_src_regions[j].block_idx); else if (src_pixmap_priv == dst_pixmap_priv && clipped_src_regions[j].block_idx != clipped_dst_regions[i].block_idx) { /* source and the dest are the same, but need different block_idx. * we create a empty pixmap and fill the required source fbo and box to * it. It's a little hacky, but avoid extra copy. */ temp_source_pixmap = glamor_create_pixmap(src->pScreen, 0, 0, src->depth, 0); if (!temp_source_pixmap) { ok = FALSE; goto fail; } src->pScreen->ModifyPixmapHeader(temp_source_pixmap, src_pixmap->drawable.width, src_pixmap->drawable.height, 0, 0, src_pixmap->devKind, NULL); temp_source_priv = glamor_get_pixmap_private(temp_source_pixmap); *temp_source_priv = *src_pixmap_priv; temp_source_priv->large.box = src_pixmap_priv->large.box_array[clipped_src_regions[j].block_idx]; temp_source_priv->base.fbo = src_pixmap_priv->large.fbo_array[clipped_src_regions[j].block_idx]; temp_source_priv->base.pixmap = temp_source_pixmap; } assert(temp_source_pixmap || !(src_pixmap_priv == dst_pixmap_priv && (clipped_src_regions[j].block_idx != clipped_dst_regions[i].block_idx))); RegionTranslate(clipped_src_regions[j].region, -src_x_off - dx, -src_y_off - dy); current_boxes = RegionRects(clipped_src_regions[j].region); n_current_boxes = RegionNumRects(clipped_src_regions[j].region); DEBUGF("dst pixmap fbo idx %d src pixmap fbo idx %d \n", clipped_dst_regions[i].block_idx, clipped_src_regions[j].block_idx); DEBUGF("Copy %d %d %d %d dx %d dy %d from %p to %p \n", current_boxes[0].x1, current_boxes[0].y1, current_boxes[0].x2, current_boxes[0].y2, dx, dy, src_pixmap, dst_pixmap); if (!temp_source_pixmap) ok = __glamor_copy_n_to_n(src, dst, gc, current_boxes, n_current_boxes, dx, dy, reverse, upsidedown, bitplane, closure); else { ok = __glamor_copy_n_to_n(&temp_source_pixmap->drawable, dst, gc, current_boxes, n_current_boxes, dx, dy, reverse, upsidedown, bitplane, closure); temp_source_priv->type = GLAMOR_MEMORY; temp_source_priv->base.fbo = NULL; glamor_destroy_pixmap(temp_source_pixmap); temp_source_pixmap = NULL; } RegionDestroy(clipped_src_regions[j].region); if (!ok) { assert(0); goto fail; } } if (n_src_region == 0) ok = TRUE; free(clipped_src_regions); } else { RegionTranslate(clipped_dst_regions[i].region, - dst_x_off, - dst_y_off); current_boxes = RegionRects(clipped_dst_regions[i].region); n_current_boxes = RegionNumRects(clipped_dst_regions[i].region); DEBUGF("dest pixmap fbo idx %d \n", clipped_dst_regions[i].block_idx); DEBUGF("Copy %d %d %d %d dx %d dy %d from %p to %p \n", current_boxes[0].x1, current_boxes[0].y1, current_boxes[0].x2, current_boxes[0].y2, dx, dy, src_pixmap, dst_pixmap); ok = __glamor_copy_n_to_n(src, dst, gc, current_boxes, n_current_boxes, dx, dy, reverse, upsidedown, bitplane, closure); } RegionDestroy(clipped_dst_regions[i].region); } if (n_dst_region == 0) ok = TRUE; free(clipped_dst_regions); } else { ok = __glamor_copy_n_to_n(src, dst, gc, box, nbox, dx, dy, reverse, upsidedown, bitplane, closure); } fail: RegionUninit(®ion); fail_noregion: dispatch = glamor_get_dispatch(glamor_priv); glamor_set_alu(dispatch, GXcopy); glamor_put_dispatch(glamor_priv); if (ok) return TRUE; fall_back: if (!fallback && glamor_ddx_fallback_check_pixmap(src) && glamor_ddx_fallback_check_pixmap(dst)) goto done; if (src_pixmap_priv->type == GLAMOR_DRM_ONLY || dst_pixmap_priv->type == GLAMOR_DRM_ONLY) { LogMessage(X_WARNING, "Access a DRM only pixmap is not allowed within glamor.\n"); return TRUE; } glamor_report_delayed_fallbacks(src->pScreen); glamor_report_delayed_fallbacks(dst->pScreen); glamor_fallback("from %p to %p (%c,%c)\n", src, dst, glamor_get_drawable_location(src), glamor_get_drawable_location(dst)); if (glamor_prepare_access(dst, GLAMOR_ACCESS_RW) && glamor_prepare_access(src, GLAMOR_ACCESS_RO) && glamor_prepare_access_gc(gc)) { fbCopyNtoN(src, dst, gc, box, nbox, dx, dy, reverse, upsidedown, bitplane, closure); } glamor_finish_access_gc(gc); glamor_finish_access(src); glamor_finish_access(dst); ok = TRUE; done: glamor_clear_delayed_fallbacks(src->pScreen); glamor_clear_delayed_fallbacks(dst->pScreen); return ok; }
static Bool glamor_copy_n_to_n_fbo_blit(DrawablePtr src, DrawablePtr dst, GCPtr gc, BoxPtr box, int nbox, int dx, int dy) { ScreenPtr screen = dst->pScreen; PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst); PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src); glamor_pixmap_private *src_pixmap_priv, *dst_pixmap_priv; glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); glamor_gl_dispatch *dispatch; int dst_x_off, dst_y_off, src_x_off, src_y_off, i; int fbo_x_off, fbo_y_off; int src_fbo_x_off, src_fbo_y_off; if (!glamor_priv->has_fbo_blit) { glamor_delayed_fallback(screen, "no EXT_framebuffer_blit\n"); return FALSE; } src_pixmap_priv = glamor_get_pixmap_private(src_pixmap); dst_pixmap_priv = glamor_get_pixmap_private(dst_pixmap); if (gc) { if (gc->alu != GXcopy) { glamor_delayed_fallback(screen, "non-copy ALU\n"); return FALSE; } } if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(src_pixmap_priv)) { glamor_delayed_fallback(screen, "no src fbo\n"); return FALSE; } if (glamor_set_destination_pixmap(dst_pixmap)) return FALSE; pixmap_priv_get_fbo_off(dst_pixmap_priv, &fbo_x_off, &fbo_y_off); pixmap_priv_get_fbo_off(src_pixmap_priv, &src_fbo_x_off, &src_fbo_y_off); dispatch = glamor_get_dispatch(glamor_priv); dispatch->glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, src_pixmap_priv->base.fbo->fb); glamor_get_drawable_deltas(dst, dst_pixmap, &dst_x_off, &dst_y_off); glamor_get_drawable_deltas(src, src_pixmap, &src_x_off, &src_y_off); dst_x_off += fbo_x_off; dst_y_off += fbo_y_off; src_y_off += dy + src_fbo_y_off; src_x_off += src_fbo_x_off; for (i = 0; i < nbox; i++) { if (glamor_priv->yInverted) { dispatch->glBlitFramebuffer((box[i].x1 + dx + src_x_off), (box[i].y1 + src_y_off), (box[i].x2 + dx + src_x_off), (box[i].y2 + src_y_off), (box[i].x1 + dst_x_off), (box[i].y1 + dst_y_off), (box[i].x2 + dst_x_off), (box[i].y2 + dst_y_off), GL_COLOR_BUFFER_BIT, GL_NEAREST); } else { int flip_dst_y1 = dst_pixmap->drawable.height - (box[i].y2 + dst_y_off); int flip_dst_y2 = dst_pixmap->drawable.height - (box[i].y1 + dst_y_off); int flip_src_y1 = src_pixmap->drawable.height - (box[i].y2 + src_y_off); int flip_src_y2 = src_pixmap->drawable.height - (box[i].y1 + src_y_off); dispatch->glBlitFramebuffer(box[i].x1 + dx + src_x_off, flip_src_y1, box[i].x2 + dx + src_x_off, flip_src_y2, box[i].x1 + dst_x_off, flip_dst_y1, box[i].x2 + dst_x_off, flip_dst_y2, GL_COLOR_BUFFER_BIT, GL_NEAREST); } } glamor_put_dispatch(glamor_priv); glamor_priv->state = BLIT_STATE; return TRUE; }
static Bool __glamor_copy_n_to_n(DrawablePtr src, DrawablePtr dst, GCPtr gc, BoxPtr box, int nbox, int dx, int dy, Bool reverse, Bool upsidedown, Pixel bitplane, void *closure) { PixmapPtr dst_pixmap, src_pixmap, temp_pixmap = NULL; DrawablePtr temp_src = src; glamor_pixmap_private *dst_pixmap_priv, *src_pixmap_priv; glamor_screen_private *glamor_priv; BoxRec bound; ScreenPtr screen; int temp_dx = dx; int temp_dy = dy; int src_x_off, src_y_off, dst_x_off, dst_y_off; int i; int overlaped = 0; Bool ret = FALSE; dst_pixmap = glamor_get_drawable_pixmap(dst); dst_pixmap_priv = glamor_get_pixmap_private(dst_pixmap); src_pixmap = glamor_get_drawable_pixmap(src); src_pixmap_priv = glamor_get_pixmap_private(src_pixmap); screen = dst_pixmap->drawable.pScreen; glamor_priv = glamor_get_screen_private(dst->pScreen); glamor_get_drawable_deltas(src, src_pixmap, &src_x_off, &src_y_off); glamor_get_drawable_deltas(dst, dst_pixmap, &dst_x_off, &dst_y_off); if (src_pixmap_priv->base.fbo && src_pixmap_priv->base.fbo->fb == dst_pixmap_priv->base.fbo->fb) { int x_shift = abs(src_x_off - dx - dst_x_off); int y_shift = abs(src_y_off - dy - dst_y_off); for (i = 0; i < nbox; i++) { if (x_shift < abs(box[i].x2 - box[i].x1) && y_shift < abs(box[i].y2 - box[i].y1)) { overlaped = 1; break; } } } DEBUGF("Copy %d %d %dx%d dx %d dy %d from %p to %p \n", box[0].x1, box[0].y1, box[0].x2 - box[0].x1, box[0].y2 - box[0].y1, dx, dy, src_pixmap, dst_pixmap); #ifndef GLAMOR_GLES2 if (!overlaped && (glamor_priv->state != RENDER_STATE || !src_pixmap_priv->base.gl_tex || !dst_pixmap_priv->base.gl_tex) && glamor_copy_n_to_n_fbo_blit(src, dst, gc, box, nbox, dx, dy)) { ret = TRUE; goto done; } #endif glamor_calculate_boxes_bound(&bound, box, nbox); /* Overlaped indicate the src and dst are the same pixmap. */ if (overlaped || (!GLAMOR_PIXMAP_PRIV_HAS_FBO(src_pixmap_priv) && (((bound.x2 - bound.x1) * (bound.y2 - bound.y1) * 4 > src_pixmap->drawable.width * src_pixmap->drawable.height) || !(glamor_check_fbo_size(glamor_priv, src_pixmap->drawable.width, src_pixmap->drawable.height))))) { temp_pixmap = glamor_create_pixmap(screen, bound.x2 - bound.x1, bound.y2 - bound.y1, src_pixmap-> drawable.depth, overlaped ? 0 : GLAMOR_CREATE_PIXMAP_CPU); assert(bound.x2 - bound.x1 <= glamor_priv->max_fbo_size); assert(bound.y2 - bound.y1 <= glamor_priv->max_fbo_size); if (!temp_pixmap) goto done; glamor_translate_boxes(box, nbox, -bound.x1, -bound.y1); temp_src = &temp_pixmap->drawable; if (overlaped) glamor_copy_n_to_n_textured(src, temp_src, gc, box, nbox, temp_dx + bound.x1, temp_dy + bound.y1); else fbCopyNtoN(src, temp_src, gc, box, nbox, temp_dx + bound.x1, temp_dy + bound.y1, reverse, upsidedown, bitplane, closure); glamor_translate_boxes(box, nbox, bound.x1, bound.y1); temp_dx = -bound.x1; temp_dy = -bound.y1; } else { temp_dx = dx; temp_dy = dy; temp_src = src; } if (glamor_copy_n_to_n_textured (temp_src, dst, gc, box, nbox, temp_dx, temp_dy)) { ret = TRUE; } done: if (temp_src != src) glamor_destroy_pixmap(temp_pixmap); return ret; }
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; /* 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; /* 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 { glamor_glDrawArrays_GL_QUADS(glamor_priv, nbox); } } }
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_get_context(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_ctx; /* 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_ctx; /* 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 { if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) { glDrawArrays(GL_QUADS, 0, nrect * 4); } else { int i; for (i = 0; i < nrect; i++) { glDrawArrays(GL_TRIANGLE_FAN, i * 4, 4); } } } } }
/** * uxa_validate_gc() sets the ops to glamor's implementations, which may be * accelerated or may sync the card and fall back to fb. */ void glamor_validate_gc(GCPtr gc, unsigned long changes, DrawablePtr drawable) { /* fbValidateGC will do direct access to pixmaps if the tiling has changed. * Preempt fbValidateGC by doing its work and masking the change out, so * that we can do the Prepare/finish_access. */ #ifdef FB_24_32BIT if ((changes & GCTile) && fbGetRotatedPixmap(gc)) { gc->pScreen->DestroyPixmap(fbGetRotatedPixmap(gc)); fbGetRotatedPixmap(gc) = 0; } if (gc->fillStyle == FillTiled) { PixmapPtr old_tile, new_tile; old_tile = gc->tile.pixmap; if (old_tile->drawable.bitsPerPixel != drawable->bitsPerPixel) { new_tile = fbGetRotatedPixmap(gc); if (!new_tile || new_tile->drawable.bitsPerPixel != drawable->bitsPerPixel) { if (new_tile) gc->pScreen->DestroyPixmap(new_tile); /* fb24_32ReformatTile will do direct access of a newly- * allocated pixmap. */ glamor_fallback ("GC %p tile FB_24_32 transformat %p.\n", gc, old_tile); if (glamor_prepare_access (&old_tile->drawable, GLAMOR_ACCESS_RO)) { new_tile = fb24_32ReformatTile(old_tile, drawable->bitsPerPixel); glamor_finish_access(&old_tile->drawable, GLAMOR_ACCESS_RO); } } if (new_tile) { fbGetRotatedPixmap(gc) = old_tile; gc->tile.pixmap = new_tile; changes |= GCTile; } } } #endif if (changes & GCTile) { if (!gc->tileIsPixel) { glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(gc->tile.pixmap); if ((!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) && FbEvenTile(gc->tile.pixmap->drawable.width * drawable->bitsPerPixel)) { glamor_fallback ("GC %p tile changed %p.\n", gc, gc->tile.pixmap); if (glamor_prepare_access (&gc->tile.pixmap->drawable, GLAMOR_ACCESS_RW)) { fbPadPixmap(gc->tile.pixmap); glamor_finish_access (&gc->tile.pixmap->drawable, GLAMOR_ACCESS_RW); } } } /* Mask out the GCTile change notification, now that we've done FB's * job for it. */ changes &= ~GCTile; } if (changes & GCStipple && gc->stipple) { /* We can't inline stipple handling like we do for GCTile because * it sets fbgc privates. */ if (glamor_prepare_access(&gc->stipple->drawable, GLAMOR_ACCESS_RW)) { fbValidateGC(gc, changes, drawable); glamor_finish_access(&gc->stipple->drawable, GLAMOR_ACCESS_RW); } } else { fbValidateGC(gc, changes, drawable); } gc->ops = &glamor_gc_ops; }
static Bool _glamor_set_spans(DrawablePtr drawable, GCPtr gc, char *src, DDXPointPtr points, int *widths, int numPoints, int sorted, Bool fallback) { PixmapPtr dest_pixmap = glamor_get_drawable_pixmap(drawable); glamor_pixmap_private *dest_pixmap_priv; int i; uint8_t *drawpixels_src = (uint8_t *) src; RegionPtr clip = fbGetCompositeClip(gc); BoxRec *pbox; int x_off, y_off; Bool ret = FALSE; dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap); if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dest_pixmap_priv)) { glamor_fallback("pixmap has no fbo.\n"); goto fail; } /* XXX Shall we set alu here? */ if (!glamor_set_planemask(dest_pixmap, gc->planemask)) goto fail; glamor_get_drawable_deltas(drawable, dest_pixmap, &x_off, &y_off); for (i = 0; i < numPoints; i++) { int n = REGION_NUM_RECTS(clip); pbox = REGION_RECTS(clip); while (n--) { int x1 = points[i].x; int x2 = x1 + widths[i]; int y1 = points[i].y; if (pbox->y1 > points[i].y || pbox->y2 < points[i].y) break; x1 = x1 > pbox->x1 ? x1 : pbox->x1; x2 = x2 < pbox->x2 ? x2 : pbox->x2; if (x1 >= x2) continue; glamor_upload_sub_pixmap_to_texture(dest_pixmap, x1 + x_off, y1 + y_off, x2 - x1, 1, PixmapBytePad(widths[i], drawable->depth), drawpixels_src, 0); } drawpixels_src += PixmapBytePad(widths[i], drawable->depth); } ret = TRUE; goto done; fail: if (!fallback && glamor_ddx_fallback_check_pixmap(drawable)) goto done; glamor_fallback("to %p (%c)\n", drawable, glamor_get_drawable_location(drawable)); if (glamor_prepare_access(drawable, GLAMOR_ACCESS_RW)) { fbSetSpans(drawable, gc, src, points, widths, numPoints, sorted); glamor_finish_access(drawable, GLAMOR_ACCESS_RW); } ret = TRUE; done: return ret; }
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_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); } }