[PATCH xserver 11/12] glamor: Replace "finish access" shader with texture swizzling.

Eric Anholt eric at anholt.net
Mon Feb 1 22:58:14 CET 2016


For pictures without alpha, and for most other formats for GLES2, we
would make a temporary FBO, make another temporary texture, upload our
GLAMORY_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.

Signed-off-by: Eric Anholt <eric at anholt.net>
---
 glamor/glamor.c         |   9 +-
 glamor/glamor_core.c    | 158 --------------------
 glamor/glamor_fbo.c     |  11 ++
 glamor/glamor_picture.c | 381 ++++++++++++++++++------------------------------
 glamor/glamor_priv.h    |   8 +-
 5 files changed, 160 insertions(+), 407 deletions(-)

diff --git a/glamor/glamor.c b/glamor/glamor.c
index e9c1d9e..efe5953 100644
--- a/glamor/glamor.c
+++ b/glamor/glamor.c
@@ -605,9 +605,15 @@ glamor_init(ScreenPtr screen, unsigned int flags)
     glamor_priv->max_fbo_size = MAX_FBO_SIZE;
 #endif
 
+    glamor_priv->has_texture_swizzle =
+        (epoxy_has_gl_extension("GL_ARB_texture_swizzle") ||
+         (glamor_priv->gl_flavor != GLAMOR_GL_DESKTOP && gl_version >= 30));
+
     glamor_priv->one_channel_format = GL_ALPHA;
-    if (epoxy_has_gl_extension("GL_ARB_texture_rg") && epoxy_has_gl_extension("GL_ARB_texture_swizzle"))
+    if (epoxy_has_gl_extension("GL_ARB_texture_rg") &&
+        glamor_priv->has_texture_swizzle) {
         glamor_priv->one_channel_format = GL_RED;
+    }
 
     glamor_set_debug_level(&glamor_debug_level);
 
@@ -668,7 +674,6 @@ glamor_init(ScreenPtr screen, unsigned int flags)
 
     glamor_init_vbo(screen);
     glamor_init_pixmap_fbo(screen);
-    glamor_init_finish_access_shaders(screen);
 
 #ifdef GLAMOR_GRADIENT_SHADER
     glamor_init_gradient_shader(screen);
diff --git a/glamor/glamor_core.c b/glamor/glamor_core.c
index a8768f4..7b2b396 100644
--- a/glamor/glamor_core.c
+++ b/glamor/glamor_core.c
@@ -113,164 +113,6 @@ glamor_link_glsl_prog(ScreenPtr screen, GLint prog, const char *format, ...)
     }
 }
 
-/*
- *  When downloading a unsupported color format to CPU memory,
-    we need to shuffle the color elements and then use a supported
-    color format to read it back to CPU memory.
-
-    For an example, the picture's format is PICT_b8g8r8a8,
-    Then the expecting color layout is as below (little endian):
-    0	1	2	3   : address
-    a	r	g	b
-
-    Now the in GLES2 the supported color format is GL_RGBA, type is
-    GL_UNSIGNED_TYPE, then we need to shuffle the fragment
-    color as :
-	frag_color = sample(texture).argb;
-    before we use glReadPixel to get it back.
-
-    For the uploading process, the shuffle is a revert shuffle.
-    We still use GL_RGBA, GL_UNSIGNED_BYTE to upload the color
-    to a texture, then let's see
-    0	1	2	3   : address
-    a	r	g	b   : correct colors
-    R	G	B	A   : GL_RGBA with GL_UNSIGNED_BYTE
-
-    Now we need to shuffle again, the mapping rule is
-    r = G, g = B, b = A, a = R. Then the uploading shuffle is as
-    below:
-	frag_color = sample(texture).gbar;
-*/
-
-void
-glamor_init_finish_access_shaders(ScreenPtr screen)
-{
-    glamor_screen_private *glamor_priv;
-    const char *vs_source =
-        "attribute vec4 v_position;\n"
-        "attribute vec4 v_texcoord0;\n"
-        "varying vec2 source_texture;\n"
-        "void main()\n"
-        "{\n"
-        "	gl_Position = v_position;\n"
-        "	source_texture = v_texcoord0.xy;\n"
-        "}\n";
-
-    const char *common_source =
-        GLAMOR_DEFAULT_PRECISION
-        "varying vec2 source_texture;\n"
-        "uniform sampler2D sampler;\n"
-        "uniform int revert;\n"
-        "uniform int swap_rb;\n"
-        "#define REVERT_NONE       			0\n"
-        "#define REVERT_NORMAL     			1\n"
-        "#define SWAP_UPLOADING	  		2\n"
-        "#define SWAP_NONE_UPLOADING		3\n";
-
-    const char *fs_source =
-        "void main()\n"
-        "{\n"
-        "   vec4 color = texture2D(sampler, source_texture);\n"
-        "   if (revert == REVERT_NONE) \n"
-        "    { \n"
-        "     if ((swap_rb != SWAP_NONE_UPLOADING))   \n"
-        "		gl_FragColor = color.bgra;\n"
-        "     else \n"
-        "		gl_FragColor = color.rgba;\n"
-        "    } \n"
-        "   else \n"
-        "    { \n"
-        "     if (swap_rb == SWAP_UPLOADING)\n"
-        "		gl_FragColor = color.gbar;\n"
-        "     else if (swap_rb == SWAP_NONE_UPLOADING)\n"
-        "		gl_FragColor = color.abgr;\n"
-        "    } \n"
-        "}\n";
-
-    const char *set_alpha_source =
-        "void main()\n"
-        "{\n"
-        "   vec4 color = texture2D(sampler, source_texture);\n"
-        "   if (revert == REVERT_NONE) \n"
-        "    { \n"
-        "     if (swap_rb != SWAP_NONE_UPLOADING)   \n"
-        "		gl_FragColor = vec4(color.bgr, 1);\n"
-        "     else \n"
-        "		gl_FragColor = vec4(color.rgb, 1);\n"
-        "    } \n"
-        "   else \n"
-        "    { \n"
-        "     if (swap_rb == SWAP_UPLOADING)\n"
-        "		gl_FragColor = vec4(color.gba, 1);\n"
-        "     else if (swap_rb == SWAP_NONE_UPLOADING)\n"
-        "		gl_FragColor = vec4(color.abg, 1);\n"
-        "    } \n"
-        "}\n";
-    GLint fs_prog, vs_prog, avs_prog, set_alpha_prog;
-    GLint sampler_uniform_location;
-    char *source;
-
-    glamor_priv = glamor_get_screen_private(screen);
-    glamor_make_current(glamor_priv);
-    glamor_priv->finish_access_prog[0] = glCreateProgram();
-    glamor_priv->finish_access_prog[1] = glCreateProgram();
-
-    vs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, vs_source);
-
-    XNFasprintf(&source, "%s%s", common_source, fs_source);
-    fs_prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, source);
-    free(source);
-
-    glAttachShader(glamor_priv->finish_access_prog[0], vs_prog);
-    glAttachShader(glamor_priv->finish_access_prog[0], fs_prog);
-
-    avs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, vs_source);
-
-    XNFasprintf(&source, "%s%s", common_source, set_alpha_source);
-    set_alpha_prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER,
-                                              source);
-    free(source);
-
-    glAttachShader(glamor_priv->finish_access_prog[1], avs_prog);
-    glAttachShader(glamor_priv->finish_access_prog[1], set_alpha_prog);
-
-    glBindAttribLocation(glamor_priv->finish_access_prog[0],
-                         GLAMOR_VERTEX_POS, "v_position");
-    glBindAttribLocation(glamor_priv->finish_access_prog[0],
-                         GLAMOR_VERTEX_SOURCE, "v_texcoord0");
-    glamor_link_glsl_prog(screen, glamor_priv->finish_access_prog[0],
-                          "finish access 0");
-
-    glBindAttribLocation(glamor_priv->finish_access_prog[1],
-                         GLAMOR_VERTEX_POS, "v_position");
-    glBindAttribLocation(glamor_priv->finish_access_prog[1],
-                         GLAMOR_VERTEX_SOURCE, "v_texcoord0");
-    glamor_link_glsl_prog(screen, glamor_priv->finish_access_prog[1],
-                          "finish access 1");
-
-    glamor_priv->finish_access_revert[0] =
-        glGetUniformLocation(glamor_priv->finish_access_prog[0], "revert");
-
-    glamor_priv->finish_access_swap_rb[0] =
-        glGetUniformLocation(glamor_priv->finish_access_prog[0], "swap_rb");
-    sampler_uniform_location =
-        glGetUniformLocation(glamor_priv->finish_access_prog[0], "sampler");
-    glUseProgram(glamor_priv->finish_access_prog[0]);
-    glUniform1i(sampler_uniform_location, 0);
-    glUniform1i(glamor_priv->finish_access_revert[0], 0);
-    glUniform1i(glamor_priv->finish_access_swap_rb[0], 0);
-
-    glamor_priv->finish_access_revert[1] =
-        glGetUniformLocation(glamor_priv->finish_access_prog[1], "revert");
-    glamor_priv->finish_access_swap_rb[1] =
-        glGetUniformLocation(glamor_priv->finish_access_prog[1], "swap_rb");
-    sampler_uniform_location =
-        glGetUniformLocation(glamor_priv->finish_access_prog[1], "sampler");
-    glUseProgram(glamor_priv->finish_access_prog[1]);
-    glUniform1i(glamor_priv->finish_access_revert[1], 0);
-    glUniform1i(sampler_uniform_location, 0);
-    glUniform1i(glamor_priv->finish_access_swap_rb[1], 0);
-}
 
 static GCOps glamor_gc_ops = {
     .FillSpans = glamor_fill_spans,
diff --git a/glamor/glamor_fbo.c b/glamor/glamor_fbo.c
index 0bfc1dd..d5311a9 100644
--- a/glamor/glamor_fbo.c
+++ b/glamor/glamor_fbo.c
@@ -170,6 +170,17 @@ glamor_pixmap_fbo_cache_put(glamor_screen_private *glamor_priv,
         ("Put cache entry %p to cache %p w %d h %d format %x fbo %d tex %d \n",
          fbo, cache, fbo->width, fbo->height, fbo->format, fbo->fb, fbo->tex);
 
+    /* Reset the texture swizzle that may have been set by
+     * glamor_picture.c.  Don't reset GL_RED -> GL_ALPHA swizzle, though
+     */
+    if (glamor_priv->has_texture_swizzle && n_format != 2) {
+        glBindTexture(GL_TEXTURE_2D, fbo->tex);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_GREEN);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_BLUE);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ALPHA);
+    }
+
     glamor_priv->fbo_cache_watermark += fbo->width * fbo->height;
     xorg_list_add(&fbo->list, cache);
     fbo->expire = glamor_priv->tick + GLAMOR_CACHE_EXPIRE_MAX;
diff --git a/glamor/glamor_picture.c b/glamor/glamor_picture.c
index 42fee1b..84a33ad 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 at 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;
 }
diff --git a/glamor/glamor_priv.h b/glamor/glamor_priv.h
index 6656b28..8f994ea 100644
--- a/glamor/glamor_priv.h
+++ b/glamor/glamor_priv.h
@@ -208,6 +208,7 @@ typedef struct glamor_screen_private {
     Bool use_quads;
     Bool has_vertex_array_object;
     Bool has_dual_blend;
+    Bool has_texture_swizzle;
     Bool is_core_profile;
     int max_fbo_size;
 
@@ -286,11 +287,6 @@ typedef struct glamor_screen_private {
         [glamor_program_alpha_count]
         [SHADER_DEST_SWIZZLE_COUNT];
 
-    /* shaders to restore a texture to another texture. */
-    GLint finish_access_prog[2];
-    GLint finish_access_revert[2];
-    GLint finish_access_swap_rb[2];
-
     /* glamor gradient, 0 for small nstops, 1 for
        large nstops and 2 for dynamic generate. */
     GLint gradient_prog[SHADER_GRADIENT_COUNT][3];
@@ -586,8 +582,6 @@ void glamor_gldrawarrays_quads_using_indices(glamor_screen_private *glamor_priv,
                                              unsigned count);
 
 /* glamor_core.c */
-void glamor_init_finish_access_shaders(ScreenPtr screen);
-
 Bool glamor_get_drawable_location(const DrawablePtr drawable);
 void glamor_get_drawable_deltas(DrawablePtr drawable, PixmapPtr pixmap,
                                 int *x, int *y);
-- 
2.7.0



More information about the xorg-devel mailing list