glamor: Introduce a central place for our pixmap format/type handling.

We had various helper functions trying to come up with the
internalformat/format/type/render formats for pixmaps, and it's much
nicer to just detect what those should be once at startup.  This gives
us a chance to do the right thing for GLES.

It also, notably, fixes our format/type for depth 15 and 16 setup for
desktop GL, so that we actually allocate 16bpp (GL_RGB/565) on most
drivers instead of 32bpp (GL_RGB/UBYTE).

GLES still has regressions over desktop (2 regressions in llvmpipe
XTS, many in rendercheck), but I think this is a good baseline.

Signed-off-by: Eric Anholt <eric@anholt.net>
This commit is contained in:
Eric Anholt 2019-03-26 15:10:49 -07:00 committed by Adam Jackson
parent c94da112a7
commit 8702c938b3
10 changed files with 209 additions and 145 deletions

View File

@ -197,7 +197,7 @@ glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
w <= glamor_priv->glyph_max_dim &&
h <= glamor_priv->glyph_max_dim)
|| (w == 0 && h == 0)
|| !glamor_check_pixmap_fbo_depth(depth)))
|| !glamor_priv->formats[depth].format))
return fbCreatePixmap(screen, w, h, depth, usage);
else
pixmap = fbCreatePixmap(screen, 0, 0, depth, usage);
@ -425,6 +425,165 @@ glamor_setup_debug_output(ScreenPtr screen)
glEnable(GL_DEBUG_OUTPUT);
}
const struct glamor_format *
glamor_format_for_pixmap(PixmapPtr pixmap)
{
ScreenPtr pScreen = pixmap->drawable.pScreen;
glamor_screen_private *glamor_priv = glamor_get_screen_private(pScreen);
glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
if (pixmap_priv->is_cbcr)
return &glamor_priv->cbcr_format;
else
return &glamor_priv->formats[pixmap->drawable.depth];
}
static void
glamor_add_format(ScreenPtr screen, int depth, CARD32 render_format,
GLenum internalformat, GLenum format, GLenum type)
{
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
struct glamor_format *f = &glamor_priv->formats[depth];
/* If we're trying to run on GLES, make sure that we get the read
* formats that we're expecting, since glamor_transfer relies on
* them matching to get data back out. To avoid this limitation, we
* would need to have a more general glReadPixels() path in
* glamor_transfer that re-encoded the bits to the pixel format that
* we intended after.
*
* Note that we can't just create a pixmap because we're in
* screeninit.
*/
if (glamor_priv->is_gles) {
unsigned fbo, tex;
int read_format, read_type;
GLenum status;
glGenTextures(1, &tex);
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);
glTexImage2D(GL_TEXTURE_2D, 0, internalformat, 1, 1, 0,
format, type, NULL);
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, tex, 0);
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
ErrorF("glamor: Test fbo for depth %d incomplete. "
"Falling back to software.\n", depth);
glDeleteTextures(1, &tex);
glDeleteFramebuffers(1, &fbo);
return;
}
glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &read_format);
glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &read_type);
glDeleteTextures(1, &tex);
glDeleteFramebuffers(1, &fbo);
if (format != read_format || type != read_type) {
ErrorF("glamor: Implementation returned 0x%x/0x%x read format/type "
"for depth %d, expected 0x%x/0x%x. "
"Falling back to software.\n",
read_format, read_type, depth, format, type);
return;
}
}
f->depth = depth;
f->render_format = render_format;
f->internalformat = internalformat;
f->format = format;
f->type = type;
}
/* Set up the GL format/types that glamor will use for the various depths
*
* X11's pixel data doesn't have channels, but to store our data in GL
* we have to pick some sort of format to move X11 pixel data in and
* out with in glamor_transfer.c. For X11 core operations, other than
* GL logic ops (non-GXcopy GC ops) what the driver chooses internally
* doesn't matter as long as it doesn't drop any bits (we expect them
* to generally expand, if anything). For Render, we can expect
* clients to tend to render with PictFormats matching our channel
* layouts here since ultimately X11 pixels tend to end up on the
* screen. The render implementation will fall back to fb if the
* channels don't match.
*
* Note that these formats don't affect what glamor_egl.c or
* Xwayland's EGL layer choose for surfaces exposed through DRI or
* scanout. For now, those layers need to match what we're choosing
* here, or channels will end up swizzled around. Similarly, the
* driver's visual masks also need to match what we're doing here.
*/
static void
glamor_setup_formats(ScreenPtr screen)
{
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
/* Prefer r8 textures since they're required by GLES3 and core,
* only falling back to a8 if we can't do them.
*/
if (glamor_priv->is_gles || epoxy_has_gl_extension("GL_ARB_texture_rg")) {
glamor_add_format(screen, 8, PICT_a8,
GL_R8, GL_RED, GL_UNSIGNED_BYTE);
} else {
glamor_add_format(screen, 8, PICT_a8,
GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE);
}
if (glamor_priv->is_gles) {
/* For 15bpp, GLES supports format/type RGBA/5551, rather than
* bgra/1555_rev. GL_EXT_bgra lets the impl say the color
* read format/type is bgra/1555 even if we had to create it
* with rgba/5551, with Mesa does. That means we can't use
* the same format/type for TexSubImage and readpixels.
*
* Instead, just store 16 bits using the trusted 565 path, and
* disable render accel for now.
*/
glamor_add_format(screen, 15, PICT_x1r5g5b5,
GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1);
} else {
glamor_add_format(screen, 15, PICT_x1r5g5b5,
GL_RGBA, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV);
}
glamor_add_format(screen, 16, PICT_r5g6b5,
GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5);
if (glamor_priv->is_gles) {
assert(X_BYTE_ORDER == X_LITTLE_ENDIAN);
glamor_add_format(screen, 24, PICT_x8b8g8r8,
GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
glamor_add_format(screen, 32, PICT_a8b8g8r8,
GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
} else {
glamor_add_format(screen, 24, PICT_x8r8g8b8,
GL_RGBA, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV);
glamor_add_format(screen, 32, PICT_a8r8g8b8,
GL_RGBA, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV);
}
if (glamor_priv->is_gles) {
glamor_add_format(screen, 30, PICT_x2b10g10r10,
GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV);
} else {
glamor_add_format(screen, 30, PICT_x2r10g10b10,
GL_RGB10_A2, GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV);
}
glamor_priv->cbcr_format.depth = 16;
glamor_priv->cbcr_format.internalformat = GL_RG8;
glamor_priv->cbcr_format.format = GL_RG;
glamor_priv->cbcr_format.type = GL_UNSIGNED_BYTE;
}
/** Set up glamor for an already-configured GL context. */
Bool
glamor_init(ScreenPtr screen, unsigned int flags)
@ -649,11 +808,7 @@ glamor_init(ScreenPtr screen, unsigned int flags)
(epoxy_has_gl_extension("GL_ARB_texture_swizzle") ||
(glamor_priv->is_gles && gl_version >= 30));
glamor_priv->one_channel_format = GL_ALPHA;
if (epoxy_has_gl_extension("GL_ARB_texture_rg") &&
glamor_priv->has_texture_swizzle) {
glamor_priv->one_channel_format = GL_RED;
}
glamor_setup_formats(screen);
glamor_set_debug_level(&glamor_debug_level);

View File

@ -97,7 +97,7 @@ glamor_pixmap_fbo *
glamor_create_fbo_from_tex(glamor_screen_private *glamor_priv,
PixmapPtr pixmap, int w, int h, GLint tex, int flag)
{
GLenum format = gl_iformat_for_pixmap(pixmap);
const struct glamor_format *f = glamor_format_for_pixmap(pixmap);
glamor_pixmap_fbo *fbo;
fbo = calloc(1, sizeof(*fbo));
@ -107,7 +107,7 @@ glamor_create_fbo_from_tex(glamor_screen_private *glamor_priv,
fbo->tex = tex;
fbo->width = w;
fbo->height = h;
fbo->is_red = format == GL_RED;
fbo->is_red = f->format == GL_RED;
if (flag != GLAMOR_CREATE_FBO_NO_FBO) {
if (glamor_pixmap_ensure_fb(glamor_priv, fbo) != 0) {
@ -123,23 +123,19 @@ static int
_glamor_create_tex(glamor_screen_private *glamor_priv,
PixmapPtr pixmap, int w, int h)
{
GLenum iformat = gl_iformat_for_pixmap(pixmap);
GLenum format = iformat;
const struct glamor_format *f = glamor_format_for_pixmap(pixmap);
unsigned int tex;
if (format == GL_RGB10_A2)
format = GL_RGBA;
glamor_make_current(glamor_priv);
glGenTextures(1, &tex);
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);
if (format == glamor_priv->one_channel_format && format == GL_RED)
if (f->format == GL_RED)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED);
glamor_priv->suppress_gl_out_of_memory_logging = true;
glTexImage2D(GL_TEXTURE_2D, 0, iformat, w, h, 0,
format, GL_UNSIGNED_BYTE, NULL);
glTexImage2D(GL_TEXTURE_2D, 0, f->internalformat, w, h, 0,
f->format, f->type, NULL);
glamor_priv->suppress_gl_out_of_memory_logging = false;
if (glGetError() == GL_OUT_OF_MEMORY) {

View File

@ -83,7 +83,7 @@ glamor_get_tex_format_type_from_pictformat(ScreenPtr pScreen,
switch (format) {
case PICT_a1:
*tex_format = glamor_priv->one_channel_format;
*tex_format = glamor_priv->formats[1].format;
*tex_type = GL_UNSIGNED_BYTE;
*temp_format = PICT_a8;
break;
@ -195,7 +195,7 @@ glamor_get_tex_format_type_from_pictformat(ScreenPtr pScreen,
break;
case PICT_a8:
*tex_format = glamor_priv->one_channel_format;
*tex_format = glamor_priv->formats[8].format;
*tex_type = GL_UNSIGNED_BYTE;
break;
@ -286,6 +286,7 @@ glamor_upload_picture_to_texture(PicturePtr picture)
Bool ret = TRUE;
Bool needs_swizzle;
pixman_image_t *converted_image = NULL;
const struct glamor_format *f = glamor_format_for_pixmap(pixmap);
assert(glamor_pixmap_is_memory(pixmap));
assert(!pixmap_priv->fbo);
@ -336,7 +337,7 @@ glamor_upload_picture_to_texture(PicturePtr picture)
}
if (!glamor_priv->is_gles)
iformat = gl_iformat_for_pixmap(pixmap);
iformat = f->internalformat;
else
iformat = format;

View File

@ -156,6 +156,21 @@ struct glamor_pixmap_private;
#define GLAMOR_COMPOSITE_VBO_VERT_CNT (64*1024)
struct glamor_format {
/** X Server's "depth" value */
int depth;
/** GL internalformat for creating textures of this type */
GLenum internalformat;
/** GL format transferring pixels in/out of textures of this type. */
GLenum format;
/** GL type transferring pixels in/out of textures of this type. */
GLenum type;
/* Render PICT_* matching GL's channel layout for pixels
* transferred using format/type.
*/
CARD32 render_format;
};
struct glamor_saved_procs {
CloseScreenProcPtr close_screen;
CreateGCProcPtr create_gc;
@ -198,7 +213,8 @@ typedef struct glamor_screen_private {
Bool can_copyplane;
int max_fbo_size;
GLuint one_channel_format;
struct glamor_format formats[33];
struct glamor_format cbcr_format;
/* glamor point shader */
glamor_program point_prog;
@ -535,6 +551,8 @@ void glamor_destroy_fbo(glamor_screen_private *glamor_priv,
void glamor_pixmap_destroy_fbo(PixmapPtr pixmap);
Bool glamor_pixmap_fbo_fixup(ScreenPtr screen, PixmapPtr pixmap);
const struct glamor_format *glamor_format_for_pixmap(PixmapPtr pixmap);
/* Return whether 'picture' is alpha-only */
static inline Bool glamor_picture_is_alpha(PicturePtr picture)
{
@ -547,7 +565,7 @@ glamor_picture_red_is_alpha(PicturePtr picture)
{
/* True when the picture is alpha only and the screen is using GL_RED for alpha pictures */
return glamor_picture_is_alpha(picture) &&
glamor_get_screen_private(picture->pDrawable->pScreen)->one_channel_format == GL_RED;
glamor_get_screen_private(picture->pDrawable->pScreen)->formats[8].format == GL_RED;
}
void glamor_bind_texture(glamor_screen_private *glamor_priv,

View File

@ -772,12 +772,15 @@ static Bool
glamor_render_format_is_supported(PicturePtr picture)
{
PictFormatShort storage_format;
glamor_screen_private *glamor_priv;
/* Source-only pictures should always work */
if (!picture->pDrawable)
return TRUE;
storage_format = format_for_depth(picture->pDrawable->depth);
glamor_priv = glamor_get_screen_private(picture->pDrawable->pScreen);
storage_format =
glamor_priv->formats[picture->pDrawable->depth].render_format;
switch (picture->format) {
case PICT_a2r10g10b10:
@ -898,7 +901,7 @@ glamor_composite_choose_shader(CARD8 op,
}
if (dest_pixmap->drawable.bitsPerPixel <= 8 &&
glamor_priv->one_channel_format == GL_RED) {
glamor_priv->formats[8].format == GL_RED) {
key.dest_swizzle = SHADER_DEST_SWIZZLE_ALPHA_TO_RED;
} else {
key.dest_swizzle = SHADER_DEST_SWIZZLE_DEFAULT;

View File

@ -187,9 +187,8 @@ glamor_get_spans_gl(DrawablePtr drawable, int wmax,
int box_index;
int n;
char *d;
GLenum type;
GLenum format;
int off_x, off_y;
const struct glamor_format *f = glamor_format_for_pixmap(pixmap);
pixmap_priv = glamor_get_pixmap_private(pixmap);
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
@ -197,8 +196,6 @@ glamor_get_spans_gl(DrawablePtr drawable, int wmax,
glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y);
glamor_format_for_pixmap(pixmap, &format, &type);
glamor_make_current(glamor_priv);
glamor_pixmap_loop(pixmap_priv, box_index) {
@ -234,7 +231,8 @@ glamor_get_spans_gl(DrawablePtr drawable, int wmax,
if (y >= box->y2)
continue;
glReadPixels(x1 - box->x1, y - box->y1, x2 - x1, 1, format, type, l);
glReadPixels(x1 - box->x1, y - box->y1, x2 - x1, 1,
f->format, f->type, l);
}
}
@ -269,11 +267,10 @@ glamor_set_spans_gl(DrawablePtr drawable, GCPtr gc, char *src,
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
glamor_pixmap_private *pixmap_priv;
const struct glamor_format *f = glamor_format_for_pixmap(pixmap);
int box_index;
int n;
char *s;
GLenum type;
GLenum format;
int off_x, off_y;
pixmap_priv = glamor_get_pixmap_private(pixmap);
@ -287,7 +284,6 @@ glamor_set_spans_gl(DrawablePtr drawable, GCPtr gc, char *src,
goto bail;
glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y);
glamor_format_for_pixmap(pixmap, &format, &type);
glamor_make_current(glamor_priv);
@ -348,7 +344,7 @@ glamor_set_spans_gl(DrawablePtr drawable, GCPtr gc, char *src,
glTexSubImage2D(GL_TEXTURE_2D, 0,
x1 - box->x1, y1 - box->y1, x2 - x1, 1,
format, type,
f->format, f->type,
l);
}
s += PixmapBytePad(w, drawable->depth);

View File

@ -23,44 +23,6 @@
#include "glamor_priv.h"
#include "glamor_transfer.h"
/* XXX a kludge for now */
void
glamor_format_for_pixmap(PixmapPtr pixmap, GLenum *format, GLenum *type)
{
glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap);
switch (pixmap->drawable.depth) {
case 24:
case 32:
*format = GL_BGRA;
*type = GL_UNSIGNED_INT_8_8_8_8_REV;
break;
case 30:
*format = GL_BGRA;
*type = GL_UNSIGNED_INT_2_10_10_10_REV;
break;
case 16:
if (priv->is_cbcr) {
*format = GL_RG;
*type = GL_UNSIGNED_BYTE;
} else {
*format = GL_RGB;
*type = GL_UNSIGNED_SHORT_5_6_5;
}
break;
case 15:
*format = GL_BGRA;
*type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
break;
case 8:
*format = glamor_get_screen_private(pixmap->drawable.pScreen)->one_channel_format;
*type = GL_UNSIGNED_BYTE;
break;
default:
FatalError("Invalid pixmap depth %d\n", pixmap->drawable.depth);
break;
}
}
/*
* Write a region of bits into a pixmap
*/
@ -75,10 +37,7 @@ glamor_upload_boxes(PixmapPtr pixmap, BoxPtr in_boxes, int in_nbox,
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);
const struct glamor_format *f = glamor_format_for_pixmap(pixmap);
glamor_make_current(glamor_priv);
@ -116,14 +75,14 @@ glamor_upload_boxes(PixmapPtr pixmap, BoxPtr in_boxes, int in_nbox,
glTexSubImage2D(GL_TEXTURE_2D, 0,
x1 - box->x1, y1 - box->y1,
x2 - x1, y2 - y1,
format, type,
f->format, f->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,
f->format, f->type,
bits + ofs);
}
}
@ -178,10 +137,7 @@ glamor_download_boxes(PixmapPtr pixmap, BoxPtr in_boxes, int in_nbox,
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);
const struct glamor_format *f = glamor_format_for_pixmap(pixmap);
glamor_make_current(glamor_priv);
@ -216,10 +172,10 @@ glamor_download_boxes(PixmapPtr pixmap, BoxPtr in_boxes, int in_nbox,
if (glamor_priv->has_pack_subimage ||
x2 - x1 == byte_stride / bytes_per_pixel) {
glReadPixels(x1 - box->x1, y1 - box->y1, x2 - x1, y2 - y1, format, type, bits + ofs);
glReadPixels(x1 - box->x1, y1 - box->y1, x2 - x1, y2 - y1, f->format, f->type, bits + ofs);
} else {
for (; y1 < y2; y1++, ofs += byte_stride)
glReadPixels(x1 - box->x1, y1 - box->y1, x2 - x1, 1, format, type, bits + ofs);
glReadPixels(x1 - box->x1, y1 - box->y1, x2 - x1, 1, f->format, f->type, bits + ofs);
}
}
}

View File

@ -23,9 +23,6 @@
#ifndef _GLAMOR_TRANSFER_H_
#define _GLAMOR_TRANSFER_H_
void
glamor_format_for_pixmap(PixmapPtr pixmap, GLenum *format, GLenum *type);
void
glamor_upload_boxes(PixmapPtr pixmap, BoxPtr in_boxes, int in_nbox,
int dx_src, int dy_src,

View File

@ -121,10 +121,9 @@ glamor_set_color_depth(ScreenPtr pScreen,
glamor_get_rgba_from_pixel(pixel,
&color[0], &color[1], &color[2], &color[3],
format_for_depth(depth));
glamor_priv->formats[depth].render_format);
if ((depth == 1 || depth == 8) &&
glamor_priv->one_channel_format == GL_RED)
if ((depth <= 8) && glamor_priv->formats[8].format == GL_RED)
color[0] = color[3];
glUniform4fv(uniform, 1, color);

View File

@ -570,65 +570,8 @@
&& (_w_) <= _glamor_->max_fbo_size \
&& (_h_) <= _glamor_->max_fbo_size)
/* For 1bpp pixmap, we don't store it as texture. */
#define glamor_check_pixmap_fbo_depth(_depth_) ( \
_depth_ == 8 \
|| _depth_ == 15 \
|| _depth_ == 16 \
|| _depth_ == 24 \
|| _depth_ == 30 \
|| _depth_ == 32)
#define GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv) (pixmap_priv->gl_fbo == GLAMOR_FBO_NORMAL)
/**
* Borrow from uxa.
*/
static inline CARD32
format_for_depth(int depth)
{
switch (depth) {
case 1:
return PICT_a1;
case 4:
return PICT_a4;
case 8:
return PICT_a8;
case 15:
return PICT_x1r5g5b5;
case 16:
return PICT_r5g6b5;
default:
case 24:
return PICT_x8r8g8b8;
case 30:
return PICT_x2r10g10b10;
case 32:
return PICT_a8r8g8b8;
}
}
static inline GLenum
gl_iformat_for_pixmap(PixmapPtr pixmap)
{
glamor_screen_private *glamor_priv =
glamor_get_screen_private((pixmap)->drawable.pScreen);
glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
if (!glamor_priv->is_gles &&
((pixmap)->drawable.depth == 1 || (pixmap)->drawable.depth == 8)) {
return glamor_priv->one_channel_format;
} else if (!glamor_priv->is_gles &&
(pixmap)->drawable.depth == 16 && pixmap_priv->is_cbcr) {
return GL_RG;
} else if (!glamor_priv->is_gles &&
(pixmap)->drawable.depth == 30) {
return GL_RGB10_A2;
} else {
return GL_RGBA;
}
}
#define REVERT_NONE 0
#define REVERT_NORMAL 1
#define REVERT_UPLOADING_A1 3