Merge branch 'glamor-accelerate-xy' into 'master'

WIP: Accelerate XY images in glamor

See merge request xorg/xserver!417
This commit is contained in:
Adam Jackson 2025-12-31 07:13:01 -05:00
commit e7cdcf9c44
2 changed files with 229 additions and 10 deletions

View file

@ -29,8 +29,8 @@
*/
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)
glamor_put_image_zpixmap_gl(DrawablePtr drawable, GCPtr gc, int depth, int x, int y,
int w, int h, char *bits)
{
ScreenPtr screen = drawable->pScreen;
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
@ -52,12 +52,6 @@ glamor_put_image_gl(DrawablePtr drawable, GCPtr gc, int depth, int x, int y,
if (!glamor_pm_is_solid(gc->depth, 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;
@ -84,6 +78,211 @@ bail:
return FALSE;
}
static const char vs_vars_put_bitmap[] =
"attribute vec4 primitive;\n"
"attribute vec2 source;\n"
"varying vec2 image_pos;\n";
static const char vs_exec_put_bitmap[] =
" vec2 pos = primitive.zw * vec2(gl_VertexID&1, (gl_VertexID&2)>>1);\n"
GLAMOR_POS(gl_Position, (primitive.xy + pos))
" image_pos = source + pos;\n";
static const char fs_vars_put_bitmap[] =
"varying vec2 image_pos;\n";
static Bool
glamor_put_bitmap_use(DrawablePtr drawable, GCPtr gc, glamor_program *prog, void *arg)
{
if (!glamor_set_solid(drawable, gc, TRUE, prog->fg_uniform))
return FALSE;
glamor_set_color(drawable, gc->bgPixel, prog->bg_uniform);
return TRUE;
}
static const char fs_exec_put_bitmap[] =
" ivec2 itile_texture = ivec2(image_pos);\n"
" uint x = uint(itile_texture.x & 7);\n"
" itile_texture.x >>= 3;\n"
" uint texel = texelFetch(font, itile_texture, 0).x;\n"
" uint bit = (texel >> x) & uint(1);\n"
" if (bit == uint(0))\n"
" gl_FragColor = bg;\n"
" else\n"
" gl_FragColor = fg;\n";
const glamor_facet glamor_facet_put_bitmap = {
.name = "put_bitmap",
.version = 130,
.vs_vars = vs_vars_put_bitmap,
.vs_exec = vs_exec_put_bitmap,
.fs_vars = fs_vars_put_bitmap,
.fs_exec = fs_exec_put_bitmap,
.locations = glamor_program_location_fg | glamor_program_location_bg | glamor_program_location_font,
.source_name = "source",
.use = glamor_put_bitmap_use,
};
/*
* Use a program like the terminal emulator text program to fetch single
* bits from the source image and expand them to full pixel values.
*/
static Bool
glamor_put_image_xybitmap_gl(DrawablePtr drawable, GCPtr gc, int x, int y,
int w, int h, int leftPad, 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 = glamor_get_pixmap_private(pixmap);
uint32_t byte_stride = BitmapBytePad(w + leftPad);
GLuint texture_id;
glamor_program *prog;
char *vbo_offset;
GLshort *v;
int box_index;
int off_x, off_y;
Bool ret = FALSE;
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
return FALSE;
glamor_make_current(glamor_priv);
prog = &glamor_priv->put_bitmap_prog;
if (prog->failed)
goto bail;
if (!prog->prog) {
if (!glamor_build_program(screen, prog, &glamor_facet_put_bitmap, NULL, NULL, NULL))
goto bail;
}
if (!glamor_use_program(&pixmap->drawable, gc, prog, NULL))
goto bail;
glGenTextures(1, &texture_id);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glamor_priv->suppress_gl_out_of_memory_logging = true;
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, byte_stride, h,
0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, bits);
glamor_priv->suppress_gl_out_of_memory_logging = false;
if (glGetError() == GL_OUT_OF_MEMORY)
goto bail;
glUniform1i(prog->font_uniform, 1);
/* Set up the vertex buffers for the font and destination */
v = glamor_get_vbo_space(drawable->pScreen, (6 * sizeof (GLshort)), &vbo_offset);
glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
glVertexAttribDivisor(GLAMOR_VERTEX_POS, 1);
glVertexAttribPointer(GLAMOR_VERTEX_POS, 4, GL_SHORT, GL_FALSE,
6 * sizeof (GLshort), vbo_offset);
glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
glVertexAttribDivisor(GLAMOR_VERTEX_SOURCE, 1);
glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_SHORT, GL_FALSE,
6 * sizeof (GLshort), vbo_offset + 4 * sizeof (GLshort));
v[0] = x;
v[1] = y;
v[2] = w;
v[3] = h;
v[4] = leftPad;
v[5] = 0;
glamor_put_vbo_space(drawable->pScreen);
glEnable(GL_SCISSOR_TEST);
glamor_pixmap_loop(pixmap_priv, box_index) {
BoxPtr box = RegionRects(gc->pCompositeClip);
int nbox = RegionNumRects(gc->pCompositeClip);
glamor_set_destination_drawable(drawable, box_index, TRUE, FALSE,
prog->matrix_uniform,
&off_x, &off_y);
/* Run over the clip list, drawing the glyphs
* in each box
*/
while (nbox--) {
glScissor(box->x1 + off_x,
box->y1 + off_y,
box->x2 - box->x1,
box->y2 - box->y1);
box++;
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 1);
}
}
glDisable(GL_SCISSOR_TEST);
glVertexAttribDivisor(GLAMOR_VERTEX_SOURCE, 0);
glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
glVertexAttribDivisor(GLAMOR_VERTEX_POS, 0);
glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
ret = TRUE;
bail:
glDeleteTextures(1, &texture_id);
return ret;
}
/*
* Create a temporary in-memory pixmap, put the image there then copy
* to the destination.
*/
static Bool
glamor_put_image_xy_gl(DrawablePtr drawable, GCPtr gc, int depth, int x, int y,
int w, int h, int leftPad, int format, char *bits)
{
PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
ScreenPtr screen = drawable->pScreen;
PixmapPtr temp_pixmap = NULL;
DrawablePtr temp_drawable;
GCPtr temp_gc;
Bool ret = FALSE;
ChangeGCVal gcv[3];
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
return FALSE;
temp_pixmap = (*screen->CreatePixmap)(screen, w, h, drawable->depth, GLAMOR_CREATE_PIXMAP_CPU);
if (!temp_pixmap)
goto bail;
temp_drawable = &temp_pixmap->drawable;
temp_gc = GetScratchGC(temp_drawable->depth, screen);
if (!temp_gc)
goto bail_pixmap;
/* copy mode for the first plane to clear all of the other bits */
gcv[0].val = GXcopy;
gcv[1].val = gc->fgPixel;
gcv[2].val = gc->bgPixel;
ChangeGC(NullClient, temp_gc, GCFunction|GCForeground|GCBackground, gcv);
ValidateGC(temp_drawable, temp_gc);
(*temp_gc->ops->PutImage)(temp_drawable, temp_gc, depth, 0, 0, w, h, leftPad, format, bits);
(*gc->ops->CopyArea)(&temp_pixmap->drawable, drawable, gc, 0, 0, w, h, x, y);
ret = TRUE;
FreeScratchGC(temp_gc);
bail_pixmap:
(*screen->DestroyPixmap)(temp_pixmap);
bail:
return ret;
}
static void
glamor_put_image_bail(DrawablePtr drawable, GCPtr gc, int depth, int x, int y,
int w, int h, int leftPad, int format, char *bits)
@ -97,8 +296,25 @@ void
glamor_put_image(DrawablePtr drawable, GCPtr gc, int depth, int x, int y,
int w, int h, int leftPad, int format, char *bits)
{
if (glamor_put_image_gl(drawable, gc, depth, x, y, w, h, leftPad, format, bits))
return;
switch (format) {
case ZPixmap:
if (glamor_put_image_zpixmap_gl(drawable, gc, depth, x, y, w, h, bits))
return;
break;
case XYPixmap:
if (glamor_put_image_xy_gl(drawable, gc, depth, x, y, w, h, leftPad, format, bits))
return;
break;
case XYBitmap:
if (w * h >= 100 * 100) {
if (glamor_put_image_xybitmap_gl(drawable, gc, x, y, w, h, leftPad, bits))
return;
} else {
if (glamor_put_image_xy_gl(drawable, gc, depth, x, y, w, h, leftPad, format, bits))
return;
}
break;
}
glamor_put_image_bail(drawable, gc, depth, x, y, w, h, leftPad, format, bits);
}

View file

@ -280,6 +280,9 @@ typedef struct glamor_screen_private {
glamor_program copy_area_prog;
glamor_program copy_plane_prog;
/* glamor image shaders */
glamor_program put_bitmap_prog;
/* glamor line shader */
glamor_program_fill poly_line_program;