Blob Blame History Raw
From 32faf80489f8ee7b4c973660c286f6d228f8e738 Mon Sep 17 00:00:00 2001
From: Carlos Garnacho <carlosg@gnome.org>
Date: Sat, 25 Feb 2017 23:21:06 +0100
Subject: [PATCH] cogl: Prefer swizzling to convert BGRA buffers

(squashed/rebased for gnome-3-22)

If the GL implementation/hw supports the GL_*_texture_swizzle extension,
pretend that BGRA textures shall contain RGBA data, and let the flipping
happen when the texture will be used in the rendering pipeline.

This avoids rather expensive format conversions when forcing BGRA buffers
into RGBA textures, which happens rather often with WL_SHM_FORMAT_ARGB8888
buffers (like gtk+ uses) in little-endian machines.

In intel/mesa/wayland, the performance improvement is rather noticeable,
CPU% as seen by top decreases from 45-50% to 25-30% when running
gtk+/tests/scrolling-performance with a cairo renderer.

https://bugzilla.gnome.org/show_bug.cgi?id=779234
---
 cogl/cogl/cogl-driver.h                         |  7 +++++
 cogl/cogl/driver/gl/cogl-framebuffer-gl.c       |  9 ++++++
 cogl/cogl/driver/gl/cogl-texture-2d-gl.c        | 11 ++++----
 cogl/cogl/driver/gl/gl/cogl-driver-gl.c         | 37 +++++++++++++++++++++----
 cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c | 12 ++++++++
 cogl/cogl/driver/gl/gles/cogl-driver-gles.c     | 26 +++++++++++++----
 cogl/cogl/driver/nop/cogl-driver-nop.c          |  1 +
 7 files changed, 87 insertions(+), 16 deletions(-)

diff --git a/cogl/cogl/cogl-driver.h b/cogl/cogl/cogl-driver.h
index 648228c..85aa0d8 100644
--- a/cogl/cogl/cogl-driver.h
+++ b/cogl/cogl/cogl-driver.h
@@ -55,6 +55,13 @@ struct _CoglDriverVtable
                           GLenum *out_glintformat,
                           GLenum *out_glformat,
                           GLenum *out_gltype);
+  CoglPixelFormat
+  (* pixel_format_to_gl_with_target) (CoglContext *context,
+                                      CoglPixelFormat format,
+                                      CoglPixelFormat target_format,
+                                      GLenum *out_glintformat,
+                                      GLenum *out_glformat,
+                                      GLenum *out_gltype);
 
   CoglBool
   (* update_features) (CoglContext *context,
diff --git a/cogl/cogl/driver/gl/cogl-framebuffer-gl.c b/cogl/cogl/driver/gl/cogl-framebuffer-gl.c
index 18ba08a..2af36f0 100644
--- a/cogl/cogl/driver/gl/cogl-framebuffer-gl.c
+++ b/cogl/cogl/driver/gl/cogl-framebuffer-gl.c
@@ -1418,6 +1418,15 @@ _cogl_framebuffer_gl_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
                                                             &gl_format,
                                                             &gl_type);
 
+  /* As we are reading pixels, we want to consider the bitmap according to
+   * its real pixel format, not the swizzled channels we pretend face to the
+   * pipeline.
+   */
+  if ((format == COGL_PIXEL_FORMAT_BGRA_8888 ||
+       format == COGL_PIXEL_FORMAT_BGRA_8888_PRE) &&
+      _cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE))
+    gl_format = GL_BGRA;
+
   /* NB: All offscreen rendering is done upside down so there is no need
    * to flip in this case... */
   if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_MESA_PACK_INVERT) &&
diff --git a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c
index 1193df4..817dd53 100644
--- a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c
+++ b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c
@@ -657,11 +657,12 @@ _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d,
 
   upload_format = cogl_bitmap_get_format (upload_bmp);
 
-  ctx->driver_vtable->pixel_format_to_gl (ctx,
-                                          upload_format,
-                                          NULL, /* internal format */
-                                          &gl_format,
-                                          &gl_type);
+  ctx->driver_vtable->pixel_format_to_gl_with_target (ctx,
+                                                      upload_format,
+                                                      _cogl_texture_get_format (tex),
+                                                      NULL, /* internal gl format */
+                                                      &gl_format,
+                                                      &gl_type);
 
   /* If this touches the first pixel then we'll update our copy */
   if (dst_x == 0 && dst_y == 0 &&
diff --git a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
index 2b9a49c..178262a 100644
--- a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
+++ b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
@@ -96,11 +96,12 @@ _cogl_driver_pixel_format_from_gl_internal (CoglContext *context,
 }
 
 static CoglPixelFormat
-_cogl_driver_pixel_format_to_gl (CoglContext *context,
-                                 CoglPixelFormat  format,
-                                 GLenum *out_glintformat,
-                                 GLenum *out_glformat,
-                                 GLenum *out_gltype)
+_cogl_driver_pixel_format_to_gl_with_target (CoglContext *context,
+                                             CoglPixelFormat format,
+                                             CoglPixelFormat target_format,
+                                             GLenum *out_glintformat,
+                                             GLenum *out_glformat,
+                                             GLenum *out_gltype)
 {
   CoglPixelFormat required_format;
   GLenum glintformat = 0;
@@ -174,7 +175,16 @@ _cogl_driver_pixel_format_to_gl (CoglContext *context,
     case COGL_PIXEL_FORMAT_BGRA_8888:
     case COGL_PIXEL_FORMAT_BGRA_8888_PRE:
       glintformat = GL_RGBA;
-      glformat = GL_BGRA;
+      /* If the driver has texture_swizzle, pretend internal
+       * and buffer format are the same here, the pixels
+       * will be flipped through this extension.
+       */
+      if (target_format == format &&
+          _cogl_has_private_feature
+          (context, COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE))
+        glformat = GL_RGBA;
+      else
+        glformat = GL_BGRA;
       gltype = GL_UNSIGNED_BYTE;
       break;
 
@@ -289,6 +299,20 @@ _cogl_driver_pixel_format_to_gl (CoglContext *context,
   return required_format;
 }
 
+static CoglPixelFormat
+_cogl_driver_pixel_format_to_gl (CoglContext *context,
+                                 CoglPixelFormat  format,
+                                 GLenum *out_glintformat,
+                                 GLenum *out_glformat,
+                                 GLenum *out_gltype)
+{
+  return _cogl_driver_pixel_format_to_gl_with_target (context,
+                                                      format, format,
+                                                      out_glintformat,
+                                                      out_glformat,
+                                                      out_gltype);
+}
+
 static CoglBool
 _cogl_get_gl_version (CoglContext *ctx,
                       int *major_out,
@@ -669,6 +693,7 @@ _cogl_driver_gl =
   {
     _cogl_driver_pixel_format_from_gl_internal,
     _cogl_driver_pixel_format_to_gl,
+    _cogl_driver_pixel_format_to_gl_with_target,
     _cogl_driver_update_features,
     _cogl_offscreen_gl_allocate,
     _cogl_offscreen_gl_free,
diff --git a/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c b/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c
index c76a0cf..d5ee4b4 100644
--- a/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c
+++ b/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c
@@ -114,6 +114,18 @@ _cogl_texture_driver_gen (CoglContext *ctx,
                                  red_swizzle) );
     }
 
+  /* If swizzle extension is available, prefer it to flip bgra buffers to rgba */
+  if ((internal_format == COGL_PIXEL_FORMAT_BGRA_8888 ||
+       internal_format == COGL_PIXEL_FORMAT_BGRA_8888_PRE) &&
+      _cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE))
+    {
+      static const GLint bgra_swizzle[] = { GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA };
+
+      GE( ctx, glTexParameteriv (gl_target,
+                                 GL_TEXTURE_SWIZZLE_RGBA,
+                                 bgra_swizzle) );
+    }
+
   return tex;
 }
 
diff --git a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
index bf63fcc..521f6ef 100644
--- a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
+++ b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
@@ -67,11 +67,12 @@ _cogl_driver_pixel_format_from_gl_internal (CoglContext *context,
 }
 
 static CoglPixelFormat
-_cogl_driver_pixel_format_to_gl (CoglContext *context,
-                                 CoglPixelFormat  format,
-                                 GLenum *out_glintformat,
-                                 GLenum *out_glformat,
-                                 GLenum *out_gltype)
+_cogl_driver_pixel_format_to_gl_with_target (CoglContext *context,
+                                             CoglPixelFormat format,
+                                             CoglPixelFormat target_format,
+                                             GLenum *out_glintformat,
+                                             GLenum *out_glformat,
+                                             GLenum *out_gltype)
 {
   CoglPixelFormat required_format;
   GLenum glintformat;
@@ -219,6 +220,20 @@ _cogl_driver_pixel_format_to_gl (CoglContext *context,
   return required_format;
 }
 
+static CoglPixelFormat
+_cogl_driver_pixel_format_to_gl (CoglContext *context,
+                                 CoglPixelFormat  format,
+                                 GLenum *out_glintformat,
+                                 GLenum *out_glformat,
+                                 GLenum *out_gltype)
+{
+  return _cogl_driver_pixel_format_to_gl_with_target (context,
+                                                      format, format,
+                                                      out_glintformat,
+                                                      out_glformat,
+                                                      out_gltype);
+}
+
 static CoglBool
 _cogl_get_gl_version (CoglContext *ctx,
                       int *major_out,
@@ -457,6 +472,7 @@ _cogl_driver_gles =
   {
     _cogl_driver_pixel_format_from_gl_internal,
     _cogl_driver_pixel_format_to_gl,
+    _cogl_driver_pixel_format_to_gl_with_target,
     _cogl_driver_update_features,
     _cogl_offscreen_gl_allocate,
     _cogl_offscreen_gl_free,
diff --git a/cogl/cogl/driver/nop/cogl-driver-nop.c b/cogl/cogl/driver/nop/cogl-driver-nop.c
index d9b1d0f..6e04e71 100644
--- a/cogl/cogl/driver/nop/cogl-driver-nop.c
+++ b/cogl/cogl/driver/nop/cogl-driver-nop.c
@@ -61,6 +61,7 @@ _cogl_driver_nop =
   {
     NULL, /* pixel_format_from_gl_internal */
     NULL, /* pixel_format_to_gl */
+    NULL, /* pixel_format_to_gl_with_target */
     _cogl_driver_update_features,
     _cogl_offscreen_nop_allocate,
     _cogl_offscreen_nop_free,
-- 
2.9.3