When GL_RGBA readPixels are slow do swizzle using a draw then readPixels with GL_BGRA

Review URL: http://codereview.appspot.com/5339051/


git-svn-id: http://skia.googlecode.com/svn/trunk@2631 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrGpuGL.cpp b/src/gpu/GrGpuGL.cpp
index 9697a4e..d768a24 100644
--- a/src/gpu/GrGpuGL.cpp
+++ b/src/gpu/GrGpuGL.cpp
@@ -576,6 +576,14 @@
     }
 }
 
+GrPixelConfig GrGpuGL::preferredReadPixelsConfig(GrPixelConfig config) {
+    if (GR_GL_RGBA_8888_READBACK_SLOW && GrPixelConfigIsRGBA8888(config)) {
+        return GrPixelConfigSwapRAndB(config);
+    } else {
+        return config;
+    }
+}
+
 void GrGpuGL::onResetContext() {
     if (gPrintStartupSpew && !fPrintedCaps) {
         fPrintedCaps = true;
@@ -1036,40 +1044,6 @@
 }
 #endif
 
-namespace {
-void set_tex_swizzle(GrPixelConfig config, const GrGLInterface* gl) {
-    // Today we always use GL_ALPHA for kAlpha_8_GrPixelConfig. However,
-    // this format is deprecated sometimes isn't a renderable format. If we
-    // were to spoof it in the future with GL_RED we'd want to notice that
-    // here.
-    // This isn't recorded in our tex params struct becauase we infer it
-    // from the pixel config.
-    const GrGLint* swiz;
-    if (GrPixelConfigIsAlphaOnly(config)) {
-        static const GrGLint gAlphaSwiz[] = {GR_GL_ALPHA, GR_GL_ALPHA,
-                                             GR_GL_ALPHA, GR_GL_ALPHA};
-        swiz = gAlphaSwiz;
-    } else {
-        static const GrGLint gColorSwiz[] = {GR_GL_RED,  GR_GL_GREEN,
-                                             GR_GL_BLUE, GR_GL_ALPHA};
-        swiz = gColorSwiz;
-    }
-    // should add texparameteri to interface to make 1 instead of 4 calls here
-    GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D,
-                                 GR_GL_TEXTURE_SWIZZLE_R,
-                                 swiz[0]));
-    GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D,
-                                 GR_GL_TEXTURE_SWIZZLE_G,
-                                 swiz[1]));
-    GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D,
-                                 GR_GL_TEXTURE_SWIZZLE_B,
-                                 swiz[2]));
-    GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D,
-                                 GR_GL_TEXTURE_SWIZZLE_A,
-                                 swiz[3]));
-}
-}
-
 GrTexture* GrGpuGL::onCreateTexture(const GrTextureDesc& desc,
                                     const void* srcData,
                                     size_t rowBytes) {
@@ -1149,29 +1123,27 @@
     this->setSpareTextureUnit();
     GL_CALL(BindTexture(GR_GL_TEXTURE_2D, glTexDesc.fTextureID));
 
-    // Some drivers like to know these before seeing glTexImage2D. Some drivers
-    // have a bug where an FBO won't be complete if it includes a texture that
-    // is not complete (i.e. has mip levels or non-mip min filter).
-    static const GrGLTexture::TexParams DEFAULT_TEX_PARAMS = {
-        GR_GL_NEAREST,
-        GR_GL_CLAMP_TO_EDGE,
-        GR_GL_CLAMP_TO_EDGE
-    };
+    // Some drivers like to know filter/wrap before seeing glTexImage2D. Some
+    // drivers have a bug where an FBO won't be complete if it includes a
+    // texture that is not mipmap complete (considering the filter in use).
+    GrGLTexture::TexParams initialTexParams;
+    // we only set a subset here so invalidate first
+    initialTexParams.invalidate();
+    initialTexParams.fFilter = GR_GL_NEAREST;
+    initialTexParams.fWrapS = GR_GL_CLAMP_TO_EDGE;
+    initialTexParams.fWrapT = GR_GL_CLAMP_TO_EDGE;
     GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
                           GR_GL_TEXTURE_MAG_FILTER,
-                          DEFAULT_TEX_PARAMS.fFilter));
+                          initialTexParams.fFilter));
     GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
                           GR_GL_TEXTURE_MIN_FILTER,
-                          DEFAULT_TEX_PARAMS.fFilter));
+                          initialTexParams.fFilter));
     GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
                           GR_GL_TEXTURE_WRAP_S,
-                          DEFAULT_TEX_PARAMS.fWrapS));
+                          initialTexParams.fWrapS));
     GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
                           GR_GL_TEXTURE_WRAP_T,
-                          DEFAULT_TEX_PARAMS.fWrapT));
-    if (fGLCaps.fTextureSwizzle) {
-        set_tex_swizzle(desc.fConfig, this->glInterface());
-    }
+                          initialTexParams.fWrapT));
     this->allocateAndUploadTexData(glTexDesc, internalFormat,srcData, rowBytes);
 
     GrGLTexture* tex;
@@ -1190,7 +1162,7 @@
     } else {
         tex = new GrGLTexture(this, glTexDesc);
     }
-    tex->setCachedTexParams(DEFAULT_TEX_PARAMS, this->getResetTimestamp());
+    tex->setCachedTexParams(initialTexParams, this->getResetTimestamp());
 #ifdef TRACE_TEXTURE_CREATION
     GrPrintf("--- new texture [%d] size=(%d %d) config=%d\n",
              glTexDesc.fTextureID, desc.fWidth, desc.fHeight, desc.fConfig);
@@ -2057,7 +2029,9 @@
     }
 }
 
-static unsigned grToGLFilter(GrSamplerState::Filter filter) {
+namespace {
+
+unsigned gr_to_gl_filter(GrSamplerState::Filter filter) {
     switch (filter) {
         case GrSamplerState::kBilinear_Filter:
         case GrSamplerState::k4x4Downsample_Filter:
@@ -2071,6 +2045,40 @@
     }
 }
 
+const GrGLenum* get_swizzle(GrPixelConfig config,
+                            const GrSamplerState& sampler) {
+    if (GrPixelConfigIsAlphaOnly(config)) {
+        static const GrGLenum gAlphaSmear[] = { GR_GL_ALPHA, GR_GL_ALPHA,
+                                                GR_GL_ALPHA, GR_GL_ALPHA };
+        return gAlphaSmear;
+    } else if (sampler.swapsRAndB()) {
+        static const GrGLenum gRedBlueSwap[] = { GR_GL_BLUE, GR_GL_GREEN,
+                                                 GR_GL_RED,  GR_GL_ALPHA };
+        return gRedBlueSwap;
+    } else {
+        static const GrGLenum gStraight[] = { GR_GL_RED, GR_GL_GREEN,
+                                              GR_GL_BLUE,  GR_GL_ALPHA };
+        return gStraight;
+    }
+}
+
+void set_tex_swizzle(GrGLenum swizzle[4], const GrGLInterface* gl) {
+    // should add texparameteri to interface to make 1 instead of 4 calls here
+    GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D,
+                                 GR_GL_TEXTURE_SWIZZLE_R,
+                                 swizzle[0]));
+    GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D,
+                                 GR_GL_TEXTURE_SWIZZLE_G,
+                                 swizzle[1]));
+    GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D,
+                                 GR_GL_TEXTURE_SWIZZLE_B,
+                                 swizzle[2]));
+    GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D,
+                                 GR_GL_TEXTURE_SWIZZLE_A,
+                                 swizzle[3]));
+}
+}
+
 bool GrGpuGL::flushGLStateCommon(GrPrimitiveType type) {
 
     // GrGpu::setupClipAndFlushState should have already checked this
@@ -2114,51 +2122,44 @@
             bool setAll = timestamp < this->getResetTimestamp();
             GrGLTexture::TexParams newTexParams;
 
-            newTexParams.fFilter = grToGLFilter(sampler.getFilter());
+            newTexParams.fFilter = gr_to_gl_filter(sampler.getFilter());
 
             const GrGLenum* wraps = 
                                 GrGLTexture::WrapMode2GLWrap(this->glBinding());
             newTexParams.fWrapS = wraps[sampler.getWrapX()];
             newTexParams.fWrapT = wraps[sampler.getWrapY()];
-            if (setAll) {
+            memcpy(newTexParams.fSwizzleRGBA,
+                   get_swizzle(nextTexture->config(), sampler),
+                   sizeof(newTexParams.fSwizzleRGBA));
+            if (setAll || newTexParams.fFilter != oldTexParams.fFilter) {
                 setTextureUnit(s);
                 GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
-                                      GR_GL_TEXTURE_MAG_FILTER,
-                                      newTexParams.fFilter));
+                                        GR_GL_TEXTURE_MAG_FILTER,
+                                        newTexParams.fFilter));
                 GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
-                                      GR_GL_TEXTURE_MIN_FILTER,
-                                      newTexParams.fFilter));
+                                        GR_GL_TEXTURE_MIN_FILTER,
+                                        newTexParams.fFilter));
+            }
+            if (setAll || newTexParams.fWrapS != oldTexParams.fWrapS) {
+                setTextureUnit(s);
                 GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
-                                      GR_GL_TEXTURE_WRAP_S,
-                                      newTexParams.fWrapS));
+                                        GR_GL_TEXTURE_WRAP_S,
+                                        newTexParams.fWrapS));
+            }
+            if (setAll || newTexParams.fWrapT != oldTexParams.fWrapT) {
+                setTextureUnit(s);
                 GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
-                                      GR_GL_TEXTURE_WRAP_T,
-                                      newTexParams.fWrapT));
-                if (this->glCaps().fTextureSwizzle) {
-                    set_tex_swizzle(nextTexture->config(), this->glInterface());
-                }
-            } else {
-                if (newTexParams.fFilter != oldTexParams.fFilter) {
-                    setTextureUnit(s);
-                    GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
-                                          GR_GL_TEXTURE_MAG_FILTER,
-                                          newTexParams.fFilter));
-                    GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
-                                          GR_GL_TEXTURE_MIN_FILTER,
-                                          newTexParams.fFilter));
-                }
-                if (newTexParams.fWrapS != oldTexParams.fWrapS) {
-                    setTextureUnit(s);
-                    GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
-                                          GR_GL_TEXTURE_WRAP_S,
-                                          newTexParams.fWrapS));
-                }
-                if (newTexParams.fWrapT != oldTexParams.fWrapT) {
-                    setTextureUnit(s);
-                    GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
-                                          GR_GL_TEXTURE_WRAP_T,
-                                          newTexParams.fWrapT));
-                }
+                                        GR_GL_TEXTURE_WRAP_T,
+                                        newTexParams.fWrapT));
+            }
+            if (this->glCaps().fTextureSwizzle &&
+                (setAll ||
+                 memcmp(newTexParams.fSwizzleRGBA,
+                        oldTexParams.fSwizzleRGBA,
+                        sizeof(newTexParams.fSwizzleRGBA)))) {
+                setTextureUnit(s);
+                set_tex_swizzle(newTexParams.fSwizzleRGBA,
+                                this->glInterface());
             }
             nextTexture->setCachedTexParams(newTexParams,
                                             this->getResetTimestamp());