Add support for GL_EXT_multisampled_render_to_texture.
authorbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 1 May 2013 20:10:01 +0000 (20:10 +0000)
committerbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 1 May 2013 20:10:01 +0000 (20:10 +0000)
R=robertphillips@google.com

Review URL: https://codereview.chromium.org/14091008

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

src/gpu/gl/GrGLCaps.cpp
src/gpu/gl/GrGLCaps.h
src/gpu/gl/GrGLInterface.cpp
src/gpu/gl/GrGpuGL.cpp
src/gpu/gl/android/GrGLCreateNativeInterface_android.cpp

index 716989e..8ec76a8 100644 (file)
@@ -286,7 +286,7 @@ void GrGLCaps::init(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) {
         fShaderDerivativeSupport = ctxInfo.hasExtension("GL_OES_standard_derivatives");
     }
 
-    if (GrGLCaps::kImaginationES_MSFBOType == fMSFBOType) {
+    if (GrGLCaps::kES_IMG_MsToTexture_MSFBOType == fMSFBOType) {
         GR_GL_GetIntegerv(gli, GR_GL_MAX_SAMPLES_IMG, &fMaxSampleCount);
     } else if (GrGLCaps::kNone_MSFBOType != fMSFBOType) {
         GR_GL_GetIntegerv(gli, GR_GL_MAX_SAMPLES, &fMaxSampleCount);
@@ -345,19 +345,21 @@ void GrGLCaps::initFSAASupport(const GrGLContextInfo& ctxInfo, const GrGLInterfa
        if (ctxInfo.hasExtension("GL_CHROMIUM_framebuffer_multisample")) {
            // chrome's extension is equivalent to the EXT msaa
            // and fbo_blit extensions.
-           fMSFBOType = kDesktopEXT_MSFBOType;
+           fMSFBOType = kDesktop_EXT_MSFBOType;
        } else if (ctxInfo.hasExtension("GL_APPLE_framebuffer_multisample")) {
-           fMSFBOType = kAppleES_MSFBOType;
+           fMSFBOType = kES_Apple_MSFBOType;
+       } else if (ctxInfo.hasExtension("GL_EXT_multisampled_render_to_texture")) {
+           fMSFBOType = kES_EXT_MsToTexture_MSFBOType;
        } else if (ctxInfo.hasExtension("GL_IMG_multisampled_render_to_texture")) {
-           fMSFBOType = kImaginationES_MSFBOType;
+           fMSFBOType = kES_IMG_MsToTexture_MSFBOType;
        }
     } else {
         if ((ctxInfo.version() >= GR_GL_VER(3,0)) ||
             ctxInfo.hasExtension("GL_ARB_framebuffer_object")) {
-            fMSFBOType = GrGLCaps::kDesktopARB_MSFBOType;
+            fMSFBOType = GrGLCaps::kDesktop_ARB_MSFBOType;
         } else if (ctxInfo.hasExtension("GL_EXT_framebuffer_multisample") &&
                    ctxInfo.hasExtension("GL_EXT_framebuffer_blit")) {
-            fMSFBOType = GrGLCaps::kDesktopEXT_MSFBOType;
+            fMSFBOType = GrGLCaps::kDesktop_EXT_MSFBOType;
         }
         // TODO: We could populate fMSAACoverageModes using GetInternalformativ
         // on GL 4.2+. It's format-specific, though. See also
@@ -520,16 +522,18 @@ void GrGLCaps::print() const {
     }
 
     GR_STATIC_ASSERT(0 == kNone_MSFBOType);
-    GR_STATIC_ASSERT(1 == kDesktopARB_MSFBOType);
-    GR_STATIC_ASSERT(2 == kDesktopEXT_MSFBOType);
-    GR_STATIC_ASSERT(3 == kAppleES_MSFBOType);
-    GR_STATIC_ASSERT(4 == kImaginationES_MSFBOType);
+    GR_STATIC_ASSERT(1 == kDesktop_ARB_MSFBOType);
+    GR_STATIC_ASSERT(2 == kDesktop_EXT_MSFBOType);
+    GR_STATIC_ASSERT(3 == kES_Apple_MSFBOType);
+    GR_STATIC_ASSERT(4 == kES_IMG_MsToTexture_MSFBOType);
+    GR_STATIC_ASSERT(5 == kES_EXT_MsToTexture_MSFBOType);
     static const char* gMSFBOExtStr[] = {
         "None",
         "ARB",
         "EXT",
         "Apple",
-        "IMG",
+        "IMG MS To Texture",
+        "EXT MS To Texture",
     };
     GrPrintf("MSAA Type: %s\n", gMSFBOExtStr[fMSFBOType]);
     GrPrintf("Max FS Uniform Vectors: %d\n", fMaxFragmentUniformVectors);
index 4aff025..1ce5fa6 100644 (file)
@@ -56,19 +56,27 @@ public:
         /**
          * GL3.0-style MSAA FBO (GL_ARB_framebuffer_object)
          */
-        kDesktopARB_MSFBOType,
+        kDesktop_ARB_MSFBOType,
         /**
          * earlier GL_EXT_framebuffer* extensions
          */
-        kDesktopEXT_MSFBOType,
+        kDesktop_EXT_MSFBOType,
         /**
          * GL_APPLE_framebuffer_multisample ES extension
          */
-        kAppleES_MSFBOType,
+        kES_Apple_MSFBOType,
         /**
-         * GL_IMG_multisampled_render_to_texture
+         * GL_IMG_multisampled_render_to_texture. This variation does not have MSAA renderbuffers.
+         * Instead the texture is multisampled when bound to the FBO and then resolved automatically
+         * when read. It also defines an alternate value for GL_MAX_SAMPLES (which we call
+         * GR_GL_MAX_SAMPLES_IMG).
          */
-        kImaginationES_MSFBOType,
+        kES_IMG_MsToTexture_MSFBOType,
+        /**
+         * GL_EXT_multisampled_render_to_texture. Same as the IMG one above but uses the standard
+         * GL_MAX_SAMPLES value.
+         */
+        kES_EXT_MsToTexture_MSFBOType,
     };
 
     enum CoverageAAType {
@@ -145,6 +153,24 @@ public:
     MSFBOType msFBOType() const { return fMSFBOType; }
 
     /**
+     * Does the supported MSAA FBO extension have MSAA renderbuffers?
+     */
+    bool usesMSAARenderBuffers() const {
+        return kNone_MSFBOType != fMSFBOType &&
+               kES_IMG_MsToTexture_MSFBOType != fMSFBOType &&
+               kES_EXT_MsToTexture_MSFBOType != fMSFBOType;
+    }
+
+    /**
+     * Is the MSAA FBO extension one where the texture is multisampled when bound to an FBO and
+     * then implicitly resolved when read.
+     */
+    bool usesImplicitMSAAResolve() const {
+        return kES_IMG_MsToTexture_MSFBOType == fMSFBOType ||
+               kES_EXT_MsToTexture_MSFBOType == fMSFBOType;
+    }
+
+    /**
      * Reports the type of coverage sample AA support.
      */
     CoverageAAType coverageAAType() const { return fCoverageAAType; }
index 94bb54d..f5cef11 100644 (file)
@@ -333,7 +333,8 @@ bool GrGLInterface::validate(GrGLBinding binding) const {
                 return false;
             }
         }
-        if (extensions.has("GL_IMG_multisampled_render_to_texture")) {
+        if (extensions.has("GL_IMG_multisampled_render_to_texture") ||
+            extensions.has("GL_EXT_multisampled_render_to_texture")) {
             if (NULL == fRenderbufferStorageMultisample ||
                 NULL == fFramebufferTexture2DMultisample) {
                 return false;
index de7746f..a0121d7 100644 (file)
@@ -781,6 +781,10 @@ bool GrGpuGL::createRenderTargetObjects(int width, int height,
 
     GrGLenum msColorFormat = 0; // suppress warning
 
+    if (desc->fSampleCnt > 0 && GrGLCaps::kNone_MSFBOType == this->glCaps().msFBOType()) {
+        goto FAILED;
+    }
+
     GL_CALL(GenFramebuffers(1, &desc->fTexFBOID));
     if (!desc->fTexFBOID) {
         goto FAILED;
@@ -791,10 +795,7 @@ bool GrGpuGL::createRenderTargetObjects(int width, int height,
     // the texture bound to the other. The exception is the IMG multisample extension. With this
     // extension the texture is multisampled when rendered to and then auto-resolves it when it is
     // rendered from.
-    if (desc->fSampleCnt > 0 && GrGLCaps::kImaginationES_MSFBOType != this->glCaps().msFBOType()) {
-        if (GrGLCaps::kNone_MSFBOType == this->glCaps().msFBOType()) {
-            goto FAILED;
-        }
+    if (desc->fSampleCnt > 0 && this->glCaps().usesMSAARenderBuffers()) {
         GL_CALL(GenFramebuffers(1, &desc->fRTFBOID));
         GL_CALL(GenRenderbuffers(1, &desc->fMSColorRenderbufferID));
         if (!desc->fRTFBOID ||
@@ -802,7 +803,9 @@ bool GrGpuGL::createRenderTargetObjects(int width, int height,
             !this->configToGLFormats(desc->fConfig,
                                      // GLES requires sized internal formats
                                      kES2_GrGLBinding == this->glBinding(),
-                                     &msColorFormat, NULL, NULL)) {
+                                     &msColorFormat,
+                                     NULL,
+                                     NULL)) {
             goto FAILED;
         }
     } else {
@@ -836,7 +839,7 @@ bool GrGpuGL::createRenderTargetObjects(int width, int height,
     }
     GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, desc->fTexFBOID));
 
-    if (GrGLCaps::kImaginationES_MSFBOType == this->glCaps().msFBOType() && desc->fSampleCnt > 0) {
+    if (this->glCaps().usesImplicitMSAAResolve() && desc->fSampleCnt > 0) {
         GL_CALL(FramebufferTexture2DMultisample(GR_GL_FRAMEBUFFER,
                                                 GR_GL_COLOR_ATTACHMENT0,
                                                 GR_GL_TEXTURE_2D,
@@ -1681,9 +1684,8 @@ void GrGpuGL::onGpuStencilPath(const GrPath* path, SkPath::FillType fill) {
 void GrGpuGL::onResolveRenderTarget(GrRenderTarget* target) {
     GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(target);
     if (rt->needsResolve()) {
-        // The IMG extension automatically resolves the texture when it is read.
-        if (GrGLCaps::kImaginationES_MSFBOType != this->glCaps().msFBOType()) {
-            GrAssert(GrGLCaps::kNone_MSFBOType != this->glCaps().msFBOType());
+        // Some extensions automatically resolves the texture when it is read.
+        if (this->glCaps().usesMSAARenderBuffers()) {
             GrAssert(rt->textureFBOID() != rt->renderFBOID());
             GL_CALL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER, rt->renderFBOID()));
             GL_CALL(BindFramebuffer(GR_GL_DRAW_FRAMEBUFFER, rt->textureFBOID()));
@@ -1697,7 +1699,7 @@ void GrGpuGL::onResolveRenderTarget(GrRenderTarget* target) {
                             dirtyRect.width(), dirtyRect.height(), target->origin());
 
             GrAutoTRestore<ScissorState> asr;
-            if (GrGLCaps::kAppleES_MSFBOType == this->glCaps().msFBOType()) {
+            if (GrGLCaps::kES_Apple_MSFBOType == this->glCaps().msFBOType()) {
                 // Apple's extension uses the scissor as the blit bounds.
                 asr.reset(&fScissorState);
                 fScissorState.fEnabled = true;
@@ -1705,9 +1707,8 @@ void GrGpuGL::onResolveRenderTarget(GrRenderTarget* target) {
                 this->flushScissor();
                 GL_CALL(ResolveMultisampleFramebuffer());
             } else {
-                if (GrGLCaps::kDesktopARB_MSFBOType != this->glCaps().msFBOType()) {
+                if (GrGLCaps::kDesktop_EXT_MSFBOType == this->glCaps().msFBOType()) {
                     // this respects the scissor during the blit, so disable it.
-                    GrAssert(GrGLCaps::kDesktopEXT_MSFBOType == this->glCaps().msFBOType());
                     asr.reset(&fScissorState);
                     fScissorState.fEnabled = false;
                     this->flushScissor();
@@ -2233,9 +2234,9 @@ inline bool can_blit_framebuffer(const GrSurface* dst,
                                  const GrSurface* src,
                                  const GrGpuGL* gpu,
                                  bool* wouldNeedTempFBO = NULL) {
-    if (gpu->isConfigRenderable(dst->config()) && gpu->isConfigRenderable(src->config()) &&
-        (GrGLCaps::kDesktopEXT_MSFBOType == gpu->glCaps().msFBOType() ||
-         GrGLCaps::kDesktopARB_MSFBOType == gpu->glCaps().msFBOType())) {
+    if (gpu->isConfigRenderable(dst->config()) &&
+        gpu->isConfigRenderable(src->config()) &&
+        gpu->glCaps().usesMSAARenderBuffers()) {
         if (NULL != wouldNeedTempFBO) {
             *wouldNeedTempFBO = NULL == dst->asRenderTarget() || NULL == src->asRenderTarget();
         }
@@ -2411,7 +2412,7 @@ bool GrGpuGL::onCopySurface(GrSurface* dst,
                                     dst->origin());
 
             GrAutoTRestore<ScissorState> asr;
-            if (GrGLCaps::kDesktopEXT_MSFBOType == this->glCaps().msFBOType()) {
+            if (GrGLCaps::kDesktop_EXT_MSFBOType == this->glCaps().msFBOType()) {
                 // The EXT version applies the scissor during the blit, so disable it.
                 asr.reset(&fScissorState);
                 fScissorState.fEnabled = false;
index 842741c..77248a0 100644 (file)
@@ -4,6 +4,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "gl/GrGLExtensions.h"
 #include "gl/GrGLInterface.h"
 
 #ifndef GL_GLEXT_PROTOTYPES
 const GrGLInterface* GrGLCreateNativeInterface() {
     static SkAutoTUnref<GrGLInterface> glInterface;
     if (!glInterface.get()) {
+        GrGLExtensions extensions;
+        if (!extensions.init(kES2_GrGLBinding, glGetString, NULL, glGetIntegerv)) {
+            return NULL;
+        }
         GrGLInterface* interface = new GrGLInterface;
         glInterface.reset(interface);
         interface->fBindingsExported = kES2_GrGLBinding;
@@ -128,10 +133,23 @@ const GrGLInterface* GrGLCreateNativeInterface() {
         interface->fDeleteRenderbuffers = glDeleteRenderbuffers;
         interface->fFramebufferRenderbuffer = glFramebufferRenderbuffer;
         interface->fFramebufferTexture2D = glFramebufferTexture2D;
+        if (extensions.has("GL_EXT_multisampled_render_to_texture")) {
+#if GL_EXT_multisampled_render_to_texture
+            interface->fFramebufferTexture2DMultisample = glFramebufferTexture2DMultisampleEXT;
+            interface->fRenderbufferStorageMultisample = glRenderbufferStorageMultisampleEXT;
+#else
+            interface->fFramebufferTexture2DMultisample = (GrGLFramebufferTexture2DMultisampleProc) eglGetProcAddress("glFramebufferTexture2DMultisampleEXT");
+            interface->fRenderbufferStorageMultisample = (GrGLRenderbufferStorageMultisampleProc) eglGetProcAddress("glRenderbufferStorageMultisampleEXT");
+#endif
+        } else if (extensions.has("GL_IMG_multisampled_render_to_texture")) {
 #if GL_IMG_multisampled_render_to_texture
-        interface->fFramebufferTexture2DMultisample = glFramebufferTexture2DMultisampleIMG;
-        interface->fRenderbufferStorageMultisample = glRenderbufferStorageMultisampleIMG;
+            interface->fFramebufferTexture2DMultisample = glFramebufferTexture2DMultisampleIMG;
+            interface->fRenderbufferStorageMultisample = glRenderbufferStorageMultisampleIMG;
+#else
+            interface->fFramebufferTexture2DMultisample = (GrGLFramebufferTexture2DMultisampleProc) eglGetProcAddress("glFramebufferTexture2DMultisampleIMG");
+            interface->fRenderbufferStorageMultisample = (GrGLRenderbufferStorageMultisampleProc) eglGetProcAddress("glRenderbufferStorageMultisampleIMG");
 #endif
+        }
         interface->fGenFramebuffers = glGenFramebuffers;
         interface->fGenRenderbuffers = glGenRenderbuffers;
         interface->fGetFramebufferAttachmentParameteriv = glGetFramebufferAttachmentParameteriv;