summaryrefslogtreecommitdiff
path: root/glamor/glamor_picture.c
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2016-02-01 13:58:14 -0800
committerAdam Jackson <ajax@redhat.com>2016-03-10 11:12:43 -0500
commit0b4c0c75d06f3dbe92be1a26a637e9f05529cb3d (patch)
tree64df0f3068a30650ca3cff0c12509aa40a22bdb1 /glamor/glamor_picture.c
parentb0cc04992ced5d96bb5c52fc1e5c868797cc0a17 (diff)
glamor: Replace "finish access" shader with texture swizzling.
For pictures without alpha, and for most other formats for GLES2, we would make a temporary FBO, make another temporary texture, upload our GLAMOR_MEMORY pixmap to the texture, then run the "finish access" shader across it to swizzle its values around into the temporary FBO (which we would use for a single Render operation and then throw away). We can simplify everything by using GL_ARB_texture_swizzle (or its GLES3 counterpart). It's just not worth the complexity to try to improve the performance of this already low-performance path (SHM pixmaps + Render) on GLES2. Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Eric Anholt <eric@anholt.net>
Diffstat (limited to 'glamor/glamor_picture.c')
-rw-r--r--glamor/glamor_picture.c381
1 files changed, 141 insertions, 240 deletions
diff --git a/glamor/glamor_picture.c b/glamor/glamor_picture.c
index 42fee1bd7..84a33ad6a 100644
--- a/glamor/glamor_picture.c
+++ b/glamor/glamor_picture.c
@@ -1,4 +1,5 @@
/*
+ * Copyright © 2016 Broadcom
* Copyright © 2009 Intel Corporation
* Copyright © 1998 Keith Packard
*
@@ -20,10 +21,19 @@
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
+ */
+
+/**
+ * @file glamor_picture.c
*
- * Authors:
- * Zhigang Gong <zhigang.gong@gmail.com>
+ * Implements temporary uploads of GL_MEMORY Pixmaps to a texture that
+ * is swizzled appropriately for a given Render picture format.
+ * laid *
*
+ * This is important because GTK likes to use SHM Pixmaps for Render
+ * blending operations, and we don't want a blend operation to fall
+ * back to software (readback is more expensive than the upload we do
+ * here, and you'd have to re-upload the fallback output anyway).
*/
#include <stdlib.h>
@@ -31,40 +41,54 @@
#include "glamor_priv.h"
#include "mipict.h"
-/*
- * Map picture's format to the correct gl texture format and type.
- * no_alpha is used to indicate whehter we need to wire alpha to 1.
- *
- * Although opengl support A1/GL_BITMAP, we still don't use it
- * here, it seems that mesa has bugs when uploading a A1 bitmap.
+static void byte_swap_swizzle(GLenum *swizzle)
+{
+ GLenum temp;
+
+ temp = swizzle[0];
+ swizzle[0] = swizzle[3];
+ swizzle[3] = temp;
+
+ temp = swizzle[1];
+ swizzle[1] = swizzle[2];
+ swizzle[2] = temp;
+}
+
+/**
+ * Returns the GL format and type for uploading our bits to a given PictFormat.
*
- * Return 0 if find a matched texture type. Otherwise return -1.
- **/
+ * We may need to tell the caller to translate the bits to another
+ * format, as in PICT_a1 (which GL doesn't support). We may also need
+ * to tell the GL to swizzle the texture on sampling, because GLES3
+ * doesn't support the GL_UNSIGNED_INT_8_8_8_8{,_REV} types, so we
+ * don't have enough channel reordering options at upload time without
+ * it.
+ */
static Bool
glamor_get_tex_format_type_from_pictformat(ScreenPtr pScreen,
PictFormatShort format,
+ PictFormatShort *temp_format,
GLenum *tex_format,
GLenum *tex_type,
- int *no_alpha,
- int *revert,
- int *swap_rb)
+ GLenum *swizzle)
{
glamor_screen_private *glamor_priv = glamor_get_screen_private(pScreen);
Bool is_little_endian = IMAGE_BYTE_ORDER == LSBFirst;
- *no_alpha = 0;
- *revert = REVERT_NONE;
- *swap_rb = SWAP_NONE_UPLOADING;
+ *temp_format = format;
+ swizzle[0] = GL_RED;
+ swizzle[1] = GL_GREEN;
+ swizzle[2] = GL_BLUE;
+ swizzle[3] = GL_ALPHA;
switch (format) {
case PICT_a1:
*tex_format = glamor_priv->one_channel_format;
*tex_type = GL_UNSIGNED_BYTE;
- *revert = REVERT_UPLOADING_A1;
+ *temp_format = PICT_a8;
break;
case PICT_b8g8r8x8:
- *no_alpha = 1;
case PICT_b8g8r8a8:
if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
*tex_format = GL_BGRA;
@@ -72,13 +96,18 @@ glamor_get_tex_format_type_from_pictformat(ScreenPtr pScreen,
} else {
*tex_format = GL_RGBA;
*tex_type = GL_UNSIGNED_BYTE;
- *swap_rb = SWAP_UPLOADING;
- *revert = is_little_endian ? REVERT_NORMAL : REVERT_NONE;
+
+ swizzle[0] = GL_GREEN;
+ swizzle[1] = GL_BLUE;
+ swizzle[2] = GL_ALPHA;
+ swizzle[3] = GL_RED;
+
+ if (!is_little_endian)
+ byte_swap_swizzle(swizzle);
}
break;
case PICT_x8r8g8b8:
- *no_alpha = 1;
case PICT_a8r8g8b8:
if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
*tex_format = GL_BGRA;
@@ -86,26 +115,31 @@ glamor_get_tex_format_type_from_pictformat(ScreenPtr pScreen,
} else {
*tex_format = GL_RGBA;
*tex_type = GL_UNSIGNED_BYTE;
- *swap_rb = SWAP_UPLOADING;
- *revert = is_little_endian ? REVERT_NONE : REVERT_NORMAL;
+
+ swizzle[0] = GL_BLUE;
+ swizzle[2] = GL_RED;
+
+ if (!is_little_endian)
+ byte_swap_swizzle(swizzle);
break;
}
break;
case PICT_x8b8g8r8:
- *no_alpha = 1;
case PICT_a8b8g8r8:
*tex_format = GL_RGBA;
if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
*tex_type = GL_UNSIGNED_INT_8_8_8_8_REV;
} else {
+ *tex_format = GL_RGBA;
*tex_type = GL_UNSIGNED_BYTE;
- *revert = is_little_endian ? REVERT_NONE : REVERT_NORMAL;
+
+ if (!is_little_endian)
+ byte_swap_swizzle(swizzle);
}
break;
case PICT_x2r10g10b10:
- *no_alpha = 1;
case PICT_a2r10g10b10:
if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
*tex_format = GL_BGRA;
@@ -116,7 +150,6 @@ glamor_get_tex_format_type_from_pictformat(ScreenPtr pScreen,
break;
case PICT_x2b10g10r10:
- *no_alpha = 1;
case PICT_a2b10g10r10:
if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
*tex_format = GL_RGBA;
@@ -129,8 +162,6 @@ glamor_get_tex_format_type_from_pictformat(ScreenPtr pScreen,
case PICT_r5g6b5:
*tex_format = GL_RGB;
*tex_type = GL_UNSIGNED_SHORT_5_6_5;
- if (glamor_priv->gl_flavor != GLAMOR_GL_DESKTOP)
- *revert = is_little_endian ? REVERT_NONE : REVERT_NORMAL;
break;
case PICT_b5g6r5:
*tex_format = GL_RGB;
@@ -138,14 +169,12 @@ glamor_get_tex_format_type_from_pictformat(ScreenPtr pScreen,
*tex_type = GL_UNSIGNED_SHORT_5_6_5_REV;
} else {
*tex_type = GL_UNSIGNED_SHORT_5_6_5;
- if (is_little_endian)
- *swap_rb = SWAP_UPLOADING;
- *revert = is_little_endian ? REVERT_NONE : REVERT_NORMAL;
+ swizzle[0] = GL_BLUE;
+ swizzle[2] = GL_RED;
}
break;
case PICT_x1b5g5r5:
- *no_alpha = 1;
case PICT_a1b5g5r5:
*tex_format = GL_RGBA;
if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
@@ -156,7 +185,6 @@ glamor_get_tex_format_type_from_pictformat(ScreenPtr pScreen,
break;
case PICT_x1r5g5b5:
- *no_alpha = 1;
case PICT_a1r5g5b5:
if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
*tex_format = GL_BGRA;
@@ -172,35 +200,36 @@ glamor_get_tex_format_type_from_pictformat(ScreenPtr pScreen,
break;
case PICT_x4r4g4b4:
- *no_alpha = 1;
case PICT_a4r4g4b4:
if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
*tex_format = GL_BGRA;
*tex_type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
} else {
+ /* XXX */
*tex_format = GL_RGBA;
*tex_type = GL_UNSIGNED_SHORT_4_4_4_4;
- *revert = is_little_endian ? REVERT_NORMAL : REVERT_NONE;
- *swap_rb = SWAP_UPLOADING;
}
break;
case PICT_x4b4g4r4:
- *no_alpha = 1;
case PICT_a4b4g4r4:
if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
*tex_format = GL_RGBA;
*tex_type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
} else {
+ /* XXX */
*tex_format = GL_RGBA;
*tex_type = GL_UNSIGNED_SHORT_4_4_4_4;
- *revert = is_little_endian ? REVERT_NORMAL : REVERT_NONE;
}
break;
default:
return FALSE;
}
+
+ if (!PICT_FORMAT_A(format))
+ swizzle[3] = GL_ONE;
+
return TRUE;
}
@@ -238,194 +267,6 @@ glamor_get_converted_image(PictFormatShort dst_format,
}
/**
- * Upload pixmap to a specified texture.
- * This texture may not be the one attached to it.
- **/
-static Bool
-__glamor_upload_pixmap_to_texture(PixmapPtr pixmap, unsigned int *tex,
- GLenum format,
- GLenum type,
- int x, int y, int w, int h,
- void *bits)
-{
- glamor_screen_private *glamor_priv =
- glamor_get_screen_private(pixmap->drawable.pScreen);
- int non_sub = 0;
- unsigned int iformat = 0;
-
- glamor_make_current(glamor_priv);
- if (*tex == 0) {
- glGenTextures(1, tex);
- if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
- iformat = gl_iformat_for_pixmap(pixmap);
- else
- iformat = format;
- non_sub = 1;
- assert(x == 0 && y == 0);
- }
-
- 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);
- glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
-
- glamor_priv->suppress_gl_out_of_memory_logging = true;
- if (non_sub)
- glTexImage2D(GL_TEXTURE_2D, 0, iformat, w, h, 0, format, type, bits);
- else
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, format, type, bits);
- glamor_priv->suppress_gl_out_of_memory_logging = false;
- if (glGetError() == GL_OUT_OF_MEMORY) {
- if (non_sub) {
- glDeleteTextures(1, tex);
- *tex = 0;
- }
- return FALSE;
- }
-
- return TRUE;
-}
-
-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)
-{
- 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;
- pixman_image_t *converted_image = NULL;
-
- if (revert == REVERT_UPLOADING_A1) {
- converted_image = glamor_get_converted_image(PICT_a8,
- PICT_a1,
- bits,
- PixmapBytePad(w, 1),
- w, h);
- if (!converted_image)
- return FALSE;
-
- bits = pixman_image_get_data(converted_image);
- }
-
- /* 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) {
- 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)) {
- if (converted_image)
- pixman_image_unref(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)) {
- if (converted_image)
- pixman_image_unref(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 (converted_image)
- pixman_image_unref(bits);
- return TRUE;
-}
-
-/*
- * Prepare to upload a pixmap to texture memory.
- * no_alpha equals 1 means the format needs to wire alpha to 1.
- */
-static int
-glamor_pixmap_upload_prepare(PixmapPtr pixmap, GLenum format, int no_alpha,
- int revert, int swap_rb)
-{
- int flag = 0;
- glamor_screen_private *glamor_priv =
- glamor_get_screen_private(pixmap->drawable.pScreen);
- GLenum iformat;
-
- if (!(no_alpha || (revert == REVERT_NORMAL)
- || (swap_rb != SWAP_NONE_UPLOADING))) {
- /* We don't need a fbo, a simple texture uploading should work. */
-
- flag = GLAMOR_CREATE_FBO_NO_FBO;
- }
-
- if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
- iformat = gl_iformat_for_pixmap(pixmap);
- else
- iformat = format;
-
- if (!glamor_pixmap_ensure_fbo(pixmap, iformat, flag))
- return -1;
-
- return 0;
-}
-
-/**
* Uploads a picture based on a GLAMOR_MEMORY pixmap to a texture in a
* temporary FBO.
*/
@@ -433,17 +274,24 @@ Bool
glamor_upload_picture_to_texture(PicturePtr picture)
{
PixmapPtr pixmap = glamor_get_drawable_pixmap(picture->pDrawable);
- void *bits = pixmap->devPrivate.ptr;
- int stride = pixmap->devKind;
ScreenPtr screen = pixmap->drawable.pScreen;
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
- GLenum format, type;
- int no_alpha, revert, swap_rb;
glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
+ PictFormatShort converted_format;
+ void *bits = pixmap->devPrivate.ptr;
+ int stride = pixmap->devKind;
+ GLenum format, type;
+ GLenum swizzle[4];
+ GLenum iformat;
+ Bool ret = TRUE;
+ Bool needs_swizzle;
+ pixman_image_t *converted_image = NULL;
assert(glamor_pixmap_is_memory(pixmap));
assert(!pixmap_priv->fbo);
+ glamor_make_current(glamor_priv);
+
/* No handling of large pixmap pictures here (would need to make
* an FBO array and split the uploads across it).
*/
@@ -455,20 +303,73 @@ glamor_upload_picture_to_texture(PicturePtr picture)
if (!glamor_get_tex_format_type_from_pictformat(screen,
picture->format,
+ &converted_format,
&format,
&type,
- &no_alpha,
- &revert, &swap_rb)) {
+ swizzle)) {
glamor_fallback("Unknown pixmap depth %d.\n", pixmap->drawable.depth);
return FALSE;
}
- if (glamor_pixmap_upload_prepare(pixmap, format, no_alpha, revert, swap_rb))
+
+ needs_swizzle = (swizzle[0] != GL_RED ||
+ swizzle[1] != GL_GREEN ||
+ swizzle[2] != GL_BLUE ||
+ swizzle[3] != GL_ALPHA);
+
+ if (!glamor_priv->has_texture_swizzle && needs_swizzle) {
+ glamor_fallback("Couldn't upload temporary picture due to missing "
+ "GL_ARB_texture_swizzle.\n");
return FALSE;
+ }
+
+ if (converted_format != picture->format) {
+ converted_image = glamor_get_converted_image(converted_format,
+ picture->format,
+ bits, stride,
+ pixmap->drawable.width,
+ pixmap->drawable.height);
+ if (!converted_image)
+ return FALSE;
+
+ bits = pixman_image_get_data(converted_image);
+ stride = pixman_image_get_stride(converted_image);
+ }
+
+ if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
+ iformat = gl_iformat_for_pixmap(pixmap);
+ else
+ iformat = format;
+
+ if (!glamor_pixmap_ensure_fbo(pixmap, iformat, GLAMOR_CREATE_FBO_NO_FBO))
+ goto fail;
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+
+ glamor_priv->suppress_gl_out_of_memory_logging = true;
+
+ /* We can't use glamor_pixmap_loop() because GLAMOR_MEMORY pixmaps
+ * don't have initialized boxes.
+ */
+ glBindTexture(GL_TEXTURE_2D, pixmap_priv->fbo->tex);
+ glTexImage2D(GL_TEXTURE_2D, 0, iformat,
+ pixmap->drawable.width, pixmap->drawable.height, 0,
+ format, type, bits);
+
+ if (needs_swizzle) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, swizzle[0]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, swizzle[1]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, swizzle[2]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, swizzle[3]);
+ }
+
+ glamor_priv->suppress_gl_out_of_memory_logging = false;
+ if (glGetError() == GL_OUT_OF_MEMORY) {
+ ret = FALSE;
+ }
+
+fail:
+ if (converted_image)
+ pixman_image_unref(converted_image);
- return _glamor_upload_bits_to_pixmap_texture(pixmap, format, type,
- no_alpha, revert, swap_rb,
- 0, 0,
- pixmap->drawable.width,
- pixmap->drawable.height,
- stride, bits);
+ return ret;
}