FBO probing at Context startup is very expensive. This patch removes the
authortomhudson@google.com <tomhudson@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 14 Jun 2011 18:16:52 +0000 (18:16 +0000)
committertomhudson@google.com <tomhudson@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 14 Jun 2011 18:16:52 +0000 (18:16 +0000)
test of whether FBOs work at all, and adds parameters to the GrGLInterface
so that values can be passed into the Context creation routines instead
of executing the probes.

The GrGLInterface now defaults to run FBO tests on Android (since hardware
varies), but assumes success on desktop and software platforms.

git-svn-id: http://skia.googlecode.com/svn/trunk@1582 2bbb7eff-a529-9590-31e7-b0007b416f81

gpu/include/GrGLInterface.h
gpu/src/GrGpuGL.cpp
gpu/src/android/GrGLDefaultInterface_android.cpp
gpu/src/mac/GrGLDefaultInterface_mac.cpp
gpu/src/mesa/GrGLDefaultInterface_mesa.cpp
gpu/src/unix/GrGLDefaultInterface_unix.cpp
gpu/src/win/GrGLDefaultInterface_win.cpp

index 150e8e4..1a3dade 100644 (file)
@@ -50,11 +50,11 @@ GR_API GrGLInterface* GrGLGetGLInterface();
 GR_API void GrGLSetGLInterface(GrGLInterface* gl_interface);
 
 /*
- * This is called when GrGLSetGLInterface() hasn't been called before creating a 
- * GrGpuGL object. It provides a default implementation. The actual implementation 
- * depends on which GrGLDefaultInterface_*.cpp has been linked. There are some 
- * platform-specific implementations provided as well as 
- * GrGLDefaultInterface_none.cpp which does nothing (effectively requiring an 
+ * This is called when GrGLSetGLInterface() hasn't been called before creating
+ * a GrGpuGL object. It provides a default implementation. The actual
+ * implementation depends on which GrGLDefaultInterface_*.cpp has been linked.
+ * There are some platform-specific implementations provided as well as
+ * GrGLDefaultInterface_none.cpp which does nothing (effectively requiring an
  * explicit GrGLSetGLInterface call by the host).
  */
 void GrGLSetDefaultGLInterface();
@@ -221,6 +221,16 @@ struct GrGLInterface {
     // exported:  GLES{1|2} or Desktop.
     GrGLBinding fBindingsExported;
 
+    /// Does this GL support NPOT textures on FBOs?
+    /// boolean value, or -1 to probe (slowly) at context creation.
+    int fNPOTRenderTargetSupport;
+
+    /// Some GL implementations (PowerVR SGX devices like the iPhone 4)
+    /// have restrictions on the size of small render targets.
+    /// -1 to probe (slowly) at context creation.
+    int fMinRenderTargetHeight;
+    int fMinRenderTargetWidth;
+
     GrGLActiveTextureProc fActiveTexture;
     GrGLAttachShaderProc fAttachShader;
     GrGLBindAttribLocationProc fBindAttribLocation;
index cbfcc6e..aa8c6db 100644 (file)
@@ -189,6 +189,79 @@ static bool fbo_test(int w, int h) {
     return status == GR_GL_FRAMEBUFFER_COMPLETE;
 }
 
+static bool probe_for_npot_render_target_support(bool hasNPOTTextureSupport) {
+
+    /* Experimentation has found that some GLs that support NPOT textures
+       do not support FBOs with a NPOT texture. They report "unsupported" FBO
+       status. I don't know how to explicitly query for this. Do an
+       experiment. Note they may support NPOT with a renderbuffer but not a
+       texture. Presumably, the implementation bloats the renderbuffer
+       internally to the next POT.
+     */
+    if (hasNPOTTextureSupport) {
+        return fbo_test(200, 200);
+    }
+    return false;
+}
+
+static int probe_for_min_render_target_height(bool hasNPOTRenderTargetSupport,
+                                              int maxRenderTargetSize) {
+    /* The iPhone 4 has a restriction that for an FBO with texture color
+       attachment with height <= 8 then the width must be <= height. Here
+       we look for such a limitation.
+     */
+    if (gPrintStartupSpew) {
+        GrPrintf("Small height FBO texture experiments\n");
+    }
+    int minRenderTargetHeight = GR_INVAL_GLINT;
+    for (GrGLuint i = 1; i <= 256; hasNPOTRenderTargetSupport ? ++i : i *= 2) {
+        GrGLuint w = maxRenderTargetSize;
+        GrGLuint h = i;
+        if (fbo_test(w, h)) {
+            if (gPrintStartupSpew) {
+                GrPrintf("\t[%d, %d]: PASSED\n", w, h);
+            }
+            minRenderTargetHeight = i;
+            break;
+        } else {
+            if (gPrintStartupSpew) {
+                GrPrintf("\t[%d, %d]: FAILED\n", w, h);
+            }
+        }
+    }
+    GrAssert(GR_INVAL_GLINT != minRenderTargetHeight);
+
+    return minRenderTargetHeight;
+}
+
+static int probe_for_min_render_target_width(bool hasNPOTRenderTargetSupport,
+                                              int maxRenderTargetSize) {
+
+    if (gPrintStartupSpew) {
+        GrPrintf("Small width FBO texture experiments\n");
+    }
+    int minRenderTargetWidth = GR_INVAL_GLINT;
+    for (GrGLuint i = 1; i <= 256; hasNPOTRenderTargetSupport ? i *= 2 : ++i) {
+        GrGLuint w = i;
+        GrGLuint h = maxRenderTargetSize;
+        if (fbo_test(w, h)) {
+            if (gPrintStartupSpew) {
+                GrPrintf("\t[%d, %d]: PASSED\n", w, h);
+            }
+            minRenderTargetWidth = i;
+            break;
+        } else {
+            if (gPrintStartupSpew) {
+                GrPrintf("\t[%d, %d]: FAILED\n", w, h);
+            }
+        }
+    }
+    GrAssert(GR_INVAL_GLINT != minRenderTargetWidth);
+
+    return minRenderTargetWidth;
+}
+
+
 GrGpuGL::GrGpuGL() {
 
     if (gPrintStartupSpew) {
@@ -394,31 +467,14 @@ GrGpuGL::GrGpuGL() {
     fAALineSupport = GR_GL_SUPPORT_DESKTOP;
 
     ////////////////////////////////////////////////////////////////////////////
-    // Experiments to determine limitations that can't be queried. TODO: Make
-    // these a preprocess that generate some compile time constants.
-
-    // sanity check to make sure we can at least create an FBO from a POT texture
+    // Experiments to determine limitations that can't be queried.
+    // TODO: Make these a preprocess that generate some compile time constants.
+    // TODO: probe once at startup, rather than once per context creation.
 
-    bool simpleFBOSuccess = fbo_test(128, 128);
-    if (gPrintStartupSpew) {
-        if (!simpleFBOSuccess) {
-            GrPrintf("FBO Sanity Test: FAILED\n");
-        } else {
-            GrPrintf("FBO Sanity Test: PASSED\n");
-        }
-    }
-    GrAssert(simpleFBOSuccess);
-
-    /* Experimentation has found that some GLs that support NPOT textures
-       do not support FBOs with a NPOT texture. They report "unsupported" FBO
-       status. I don't know how to explicitly query for this. Do an
-       experiment. Note they may support NPOT with a renderbuffer but not a
-       texture. Presumably, the implementation bloats the renderbuffer
-       internally to the next POT.
-     */
-    bool fNPOTRenderTargetSupport = false;
-    if (fNPOTTextureSupport) {
-        fNPOTRenderTargetSupport = fbo_test(200, 200);
+    fNPOTRenderTargetSupport = GrGLGetGLInterface()->fNPOTRenderTargetSupport;
+    if (fNPOTRenderTargetSupport < 0) {
+        fNPOTRenderTargetSupport =
+            probe_for_npot_render_target_support(fNPOTTextureSupport);
     }
 
     if (gPrintStartupSpew) {
@@ -441,55 +497,24 @@ GrGpuGL::GrGpuGL() {
 
     GR_GL_GetIntegerv(GR_GL_MAX_TEXTURE_SIZE, &fMaxTextureSize);
     GR_GL_GetIntegerv(GR_GL_MAX_RENDERBUFFER_SIZE, &fMaxRenderTargetSize);
-    // Our render targets are always created with textures as the color 
+    // Our render targets are always created with textures as the color
     // attachment, hence this min:
     fMaxRenderTargetSize = GrMin(fMaxTextureSize, fMaxRenderTargetSize);
 
-    /* The iPhone 4 has a restriction that for an FBO with texture color
-       attachment with height <= 8 then the width must be <= height. Here
-       we look for such a limitation.
-     */
-    if (gPrintStartupSpew) {
-        GrPrintf("Small height FBO texture experiments\n");
+    fMinRenderTargetHeight = GrGLGetGLInterface()->fMinRenderTargetHeight;
+    if (fMinRenderTargetHeight < 0) {
+        fMinRenderTargetHeight =
+            probe_for_min_render_target_height(fNPOTRenderTargetSupport,
+                                               fMaxRenderTargetSize);
     }
-    fMinRenderTargetHeight = GR_INVAL_GLINT;
-    for (GrGLuint i = 1; i <= 256; fNPOTRenderTargetSupport ? ++i : i *= 2) {
-        GrGLuint w = fMaxRenderTargetSize;
-        GrGLuint h = i;
-        if (fbo_test(w, h)) {
-            if (gPrintStartupSpew) {
-                GrPrintf("\t[%d, %d]: PASSED\n", w, h);
-            }
-            fMinRenderTargetHeight = i;
-            break;
-        } else {
-            if (gPrintStartupSpew) {
-                GrPrintf("\t[%d, %d]: FAILED\n", w, h);
-            }
-        }
-    }
-    GrAssert(GR_INVAL_GLINT != fMinRenderTargetHeight);
 
-    if (gPrintStartupSpew) {
-        GrPrintf("Small width FBO texture experiments\n");
-    }
-    fMinRenderTargetWidth = GR_INVAL_GLINT;
-    for (GrGLuint i = 1; i <= 256; fNPOTRenderTargetSupport ? i *= 2 : ++i) {
-        GrGLuint w = i;
-        GrGLuint h = fMaxRenderTargetSize;
-        if (fbo_test(w, h)) {
-            if (gPrintStartupSpew) {
-                GrPrintf("\t[%d, %d]: PASSED\n", w, h);
-            }
-            fMinRenderTargetWidth = i;
-            break;
-        } else {
-            if (gPrintStartupSpew) {
-                GrPrintf("\t[%d, %d]: FAILED\n", w, h);
-            }
-        }
+    fMinRenderTargetWidth = GrGLGetGLInterface()->fMinRenderTargetWidth;
+    if (fMinRenderTargetWidth < 0) {
+        fMinRenderTargetWidth =
+            probe_for_min_render_target_width(fNPOTRenderTargetSupport,
+                                              fMaxRenderTargetSize);
     }
-    GrAssert(GR_INVAL_GLINT != fMinRenderTargetWidth);
+
 }
 
 GrGpuGL::~GrGpuGL() {
index e52277e..38e7708 100644 (file)
@@ -19,7 +19,9 @@
 void GrGLSetDefaultGLInterface() {
   static GrGLInterface cmd_buffer_interface = {
     kES2_GrGLBinding,
-
+    -1,  // fNPOTRenderTargetSupport
+    -1,  // fMinRenderTargetHeight
+    -1,  // fMinRenderTargetWidth
     glActiveTexture,
     glAttachShader,
     glBindAttribLocation,
@@ -135,4 +137,3 @@ void GrGLSetDefaultGLInterface() {
     host_StubGL_initialized = true;
   }
 }
-
index fb5b182..a49f238 100644 (file)
@@ -23,6 +23,10 @@ void GrGLSetDefaultGLInterface() {
     static GrGLInterface gDefaultInterface;
     static bool gDefaultInterfaceInit;
     if (!gDefaultInterfaceInit) {
+        gDefaultInterface.fNPOTRenderTargetSupport = 1;
+        gDefaultInterface.fMinRenderTargetHeight = 1;
+        gDefaultInterface.fMinRenderTargetWidth = 1;
+
         gDefaultInterface.fActiveTexture = glActiveTexture;
         gDefaultInterface.fAttachShader = glAttachShader;
         gDefaultInterface.fBindAttribLocation = glBindAttribLocation;
index 0350c30..6852eb7 100644 (file)
@@ -38,6 +38,9 @@ void GrGLSetDefaultGLInterface() {
             // We must have array and element_array buffer objects.
             return;
         }
+        gDefaultInterface.fNPOTRenderTargetSupport = 1;
+        gDefaultInterface.fMinRenderTargetHeight = 1;
+        gDefaultInterface.fMinRenderTargetWidth = 1;
 
         gDefaultInterface.fActiveTexture = glActiveTexture;
         GR_GL_GET_PROC(AttachShader);
index 3e9b975..f58b215 100644 (file)
@@ -40,6 +40,10 @@ void GrGLSetDefaultGLInterface() {
             return;
         }
 
+        gDefaultInterface.fNPOTRenderTargetSupport = 1;
+        gDefaultInterface.fMinRenderTargetHeight = 1;
+        gDefaultInterface.fMinRenderTargetWidth = 1;
+
         gDefaultInterface.fActiveTexture = glActiveTexture;
         GR_GL_GET_PROC(AttachShader);
         GR_GL_GET_PROC(BindAttribLocation);
index 428abb1..7f680a6 100644 (file)
@@ -32,7 +32,7 @@ void GrGLSetDefaultGLInterface() {
     static GrGLInterface gDefaultInterface;
     static bool gDefaultInterfaceInit;
     if (!gDefaultInterfaceInit) {
-        
+
         // wglGetProcAddress requires a context.
         if (NULL != wglGetCurrentContext()) {
             int major, minor;
@@ -45,7 +45,11 @@ void GrGLSetDefaultGLInterface() {
                 return;
             }
 
-            // Functions that are part of GL 1.1 will return NULL in 
+            gDefaultInterface.fNPOTRenderTargetSupport = 1;
+            gDefaultInterface.fMinRenderTargetHeight = 1;
+            gDefaultInterface.fMinRenderTargetWidth = 1;
+
+            // Functions that are part of GL 1.1 will return NULL in
             // wglGetProcAddress
             gDefaultInterface.fBlendFunc = glBlendFunc;
             gDefaultInterface.fClear = glClear;