Bug 1207672 - Add support for APPLE_framebuffer_multisample r=snorp
authorJeff Gilbert <jgilbert@mozilla.com>
Fri, 25 Sep 2015 09:29:53 -0500
changeset 305241 2ff6d5250364999dd51bccf8d2e5468d551978e7
parent 305240 b5e9434723267baa67f3526564e9be843c97af70
child 305242 ae59369ae4f0f278cefd3d3d5d02973c7a58a3ce
push id1001
push userraliiev@mozilla.com
push dateMon, 18 Jan 2016 19:06:03 +0000
treeherdermozilla-release@8b89261f3ac4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssnorp
bugs1207672
milestone44.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1207672 - Add support for APPLE_framebuffer_multisample r=snorp
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/gl/GLContextFeatures.cpp
gfx/gl/GLContextSymbols.h
gfx/gl/GLScreenBuffer.cpp
gfx/gl/ScopedGLHelpers.cpp
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -778,17 +778,16 @@ GLContext::InitWithPrefix(const char *pr
 
             if (!LoadSymbols(coreSymbols, trygl, prefix)) {
                 NS_ERROR("GL supports framebuffer_object without supplying its functions.");
                 MarkUnsupported(GLFeature::framebuffer_object);
             }
         }
 
         if (!IsSupported(GLFeature::framebuffer_object)) {
-
             // Check for aux symbols based on extensions
             if (IsSupported(GLFeature::framebuffer_object_EXT_OES))
             {
                 SymLoadStruct extSymbols[] = {
                     CORE_EXT_SYMBOL2(IsRenderbuffer, EXT, OES),
                     CORE_EXT_SYMBOL2(BindRenderbuffer, EXT, OES),
                     CORE_EXT_SYMBOL2(DeleteRenderbuffers, EXT, OES),
                     CORE_EXT_SYMBOL2(GenRenderbuffers, EXT, OES),
@@ -806,36 +805,28 @@ GLContext::InitWithPrefix(const char *pr
                     END_SYMBOLS
                 };
 
                 if (!LoadSymbols(extSymbols, trygl, prefix)) {
                     NS_ERROR("GL supports framebuffer_object without supplying its functions.");
                 }
             }
 
-            if (IsExtensionSupported(GLContext::ANGLE_framebuffer_blit) ||
-                IsExtensionSupported(GLContext::EXT_framebuffer_blit) ||
-                IsExtensionSupported(GLContext::NV_framebuffer_blit))
-
-            {
+            if (IsSupported(GLFeature::framebuffer_blit)) {
                 SymLoadStruct extSymbols[] = {
                     EXT_SYMBOL3(BlitFramebuffer, ANGLE, EXT, NV),
                     END_SYMBOLS
                 };
 
                 if (!LoadSymbols(extSymbols, trygl, prefix)) {
                     NS_ERROR("GL supports framebuffer_blit without supplying its functions.");
                 }
             }
 
-            if (IsExtensionSupported(GLContext::ANGLE_framebuffer_multisample) ||
-                IsExtensionSupported(GLContext::APPLE_framebuffer_multisample) ||
-                IsExtensionSupported(GLContext::EXT_framebuffer_multisample) ||
-                IsExtensionSupported(GLContext::EXT_multisampled_render_to_texture))
-            {
+            if (IsSupported(GLFeature::framebuffer_multisample)) {
                 SymLoadStruct extSymbols[] = {
                     EXT_SYMBOL3(RenderbufferStorageMultisample, ANGLE, APPLE, EXT),
                     END_SYMBOLS
                 };
 
                 if (!LoadSymbols(extSymbols, trygl, prefix)) {
                     NS_ERROR("GL supports framebuffer_multisample without supplying its functions.");
                 }
@@ -1541,28 +1532,42 @@ GLContext::InitWithPrefix(const char *pr
 
                 MarkExtensionUnsupported(NV_fence);
                 ClearSymbols(extSymbols);
             }
         }
 
         if (IsSupported(GLFeature::read_buffer)) {
             SymLoadStruct extSymbols[] = {
-                { (PRFuncPtr*) &mSymbols.fReadBuffer, { "ReadBuffer",    nullptr } },
+                { (PRFuncPtr*) &mSymbols.fReadBuffer, { "ReadBuffer", nullptr } },
                 END_SYMBOLS
             };
 
             if (!LoadSymbols(&extSymbols[0], trygl, prefix)) {
                 NS_ERROR("GL supports read_buffer without supplying its functions.");
 
                 MarkUnsupported(GLFeature::read_buffer);
                 ClearSymbols(extSymbols);
             }
         }
 
+        if (IsExtensionSupported(APPLE_framebuffer_multisample)) {
+            SymLoadStruct extSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fResolveMultisampleFramebufferAPPLE, { "ResolveMultisampleFramebufferAPPLE", nullptr } },
+                END_SYMBOLS
+            };
+
+            if (!LoadSymbols(&extSymbols[0], trygl, prefix)) {
+                NS_ERROR("GL supports APPLE_framebuffer_multisample without supplying its functions.");
+
+                MarkExtensionUnsupported(APPLE_framebuffer_multisample);
+                ClearSymbols(extSymbols);
+            }
+        }
+
         // Load developer symbols, don't fail if we can't find them.
         SymLoadStruct auxSymbols[] = {
                 { (PRFuncPtr*) &mSymbols.fGetTexImage, { "GetTexImage", nullptr } },
                 { (PRFuncPtr*) &mSymbols.fGetTexLevelParameteriv, { "GetTexLevelParameteriv", nullptr } },
                 END_SYMBOLS
         };
         bool warnOnFailures = DebugMode();
         LoadSymbols(&auxSymbols[0], trygl, prefix, warnOnFailures);
@@ -2908,17 +2913,17 @@ GLContext::GetDrawFB()
 }
 
 GLuint
 GLContext::GetReadFB()
 {
     if (mScreen)
         return mScreen->GetReadFB();
 
-    GLenum bindEnum = IsSupported(GLFeature::framebuffer_blit)
+    GLenum bindEnum = IsSupported(GLFeature::split_framebuffer)
                         ? LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT
                         : LOCAL_GL_FRAMEBUFFER_BINDING;
 
     GLuint ret = 0;
     GetUIntegerv(bindEnum, &ret);
     return ret;
 }
 
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -119,16 +119,17 @@ enum class GLFeature {
     query_time_elapsed,
     read_buffer,
     renderbuffer_color_float,
     renderbuffer_color_half_float,
     robustness,
     sRGB_framebuffer,
     sRGB_texture,
     sampler_objects,
+    split_framebuffer,
     standard_derivatives,
     sync,
     texture_3D,
     texture_3D_compressed,
     texture_3D_copy,
     texture_float,
     texture_float_linear,
     texture_half_float,
@@ -3135,16 +3136,26 @@ public:
         BEFORE_GL_CALL;
         ASSERT_SYMBOL_PRESENT(fGetStringi);
         const GLubyte* ret = mSymbols.fGetStringi(name, index);
         AFTER_GL_CALL;
         return ret;
     }
 
 // -----------------------------------------------------------------------------
+// APPLE_framebuffer_multisample
+
+    void fResolveMultisampleFramebufferAPPLE() {
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fResolveMultisampleFramebufferAPPLE);
+        mSymbols.fResolveMultisampleFramebufferAPPLE();
+        AFTER_GL_CALL;
+    }
+
+// -----------------------------------------------------------------------------
 // Constructor
 protected:
     explicit GLContext(const SurfaceCaps& caps,
                        GLContext* sharedContext = nullptr,
                        bool isOffscreen = false);
 
 
 // -----------------------------------------------------------------------------
--- a/gfx/gl/GLContextFeatures.cpp
+++ b/gfx/gl/GLContextFeatures.cpp
@@ -543,16 +543,30 @@ static const FeatureInfo sFeatureInfoArr
         GLVersion::GL3_3,
         GLESVersion::ES3,
         GLContext::ARB_sampler_objects,
         {
             GLContext::Extensions_End
         }
     },
     {
+        // Do we have separate DRAW and READ framebuffer bind points?
+        "split_framebuffer",
+        GLVersion::GL3,
+        GLESVersion::ES3,
+        GLContext::ARB_framebuffer_object,
+        {
+            GLContext::ANGLE_framebuffer_blit,
+            GLContext::APPLE_framebuffer_multisample,
+            GLContext::EXT_framebuffer_blit,
+            GLContext::NV_framebuffer_blit,
+            GLContext::Extensions_End
+        }
+    },
+    {
         "standard_derivatives",
         GLVersion::GL2,
         GLESVersion::ES3,
         GLContext::Extension_None,
         {
             GLContext::OES_standard_derivatives,
             GLContext::Extensions_End
         }
--- a/gfx/gl/GLContextSymbols.h
+++ b/gfx/gl/GLContextSymbols.h
@@ -681,14 +681,18 @@ struct GLContextSymbols
                                                                   GLint xoffset, GLint yoffset, GLint zoffset,
                                                                   GLsizei width, GLsizei height, GLsizei depth,
                                                                   GLenum format, GLsizei imageSize, const GLvoid* data);
     PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC fCompressedTexSubImage3D;
 
     // get_string_indexed
     typedef const GLubyte* (GLAPIENTRY * PFNGLGETSTRINGIPROC)(GLenum name, GLuint index);
     PFNGLGETSTRINGIPROC fGetStringi;
+
+    // APPLE_framebuffer_multisample
+    typedef void (GLAPIENTRY * PFNRESOLVEMULTISAMPLEFRAMEBUFFERAPPLE) (void);
+    PFNRESOLVEMULTISAMPLEFRAMEBUFFERAPPLE fResolveMultisampleFramebufferAPPLE;
 };
 
 } // namespace gl
 } // namespace mozilla
 
 #endif /* GLCONTEXTSYMBOLS_H_ */
--- a/gfx/gl/GLScreenBuffer.cpp
+++ b/gfx/gl/GLScreenBuffer.cpp
@@ -141,39 +141,33 @@ GLScreenBuffer::~GLScreenBuffer()
 }
 
 void
 GLScreenBuffer::BindAsFramebuffer(GLContext* const gl, GLenum target) const
 {
     GLuint drawFB = DrawFB();
     GLuint readFB = ReadFB();
 
-    if (!gl->IsSupported(GLFeature::framebuffer_blit)) {
+    if (!gl->IsSupported(GLFeature::split_framebuffer)) {
         MOZ_ASSERT(drawFB == readFB);
         gl->raw_fBindFramebuffer(target, readFB);
         return;
     }
 
     switch (target) {
     case LOCAL_GL_FRAMEBUFFER:
         gl->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, drawFB);
         gl->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, readFB);
         break;
 
     case LOCAL_GL_DRAW_FRAMEBUFFER_EXT:
-        if (!gl->IsSupported(GLFeature::framebuffer_blit))
-            NS_WARNING("DRAW_FRAMEBUFFER requested but unavailable.");
-
         gl->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, drawFB);
         break;
 
     case LOCAL_GL_READ_FRAMEBUFFER_EXT:
-        if (!gl->IsSupported(GLFeature::framebuffer_blit))
-            NS_WARNING("READ_FRAMEBUFFER requested but unavailable.");
-
         gl->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, readFB);
         break;
 
     default:
         MOZ_CRASH("Bad `target` for BindFramebuffer.");
     }
 }
 
@@ -186,47 +180,47 @@ GLScreenBuffer::BindFB(GLuint fb)
     mUserDrawFB = fb;
     mUserReadFB = fb;
     mInternalDrawFB = (fb == 0) ? drawFB : fb;
     mInternalReadFB = (fb == 0) ? readFB : fb;
 
     if (mInternalDrawFB == mInternalReadFB) {
         mGL->raw_fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mInternalDrawFB);
     } else {
-        MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
+        MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
         mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB);
         mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB);
     }
 
 #ifdef DEBUG
     mInInternalMode_DrawFB = false;
     mInInternalMode_ReadFB = false;
 #endif
 }
 
 void
 GLScreenBuffer::BindDrawFB(GLuint fb)
 {
-    MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
+    MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
 
     GLuint drawFB = DrawFB();
     mUserDrawFB = fb;
     mInternalDrawFB = (fb == 0) ? drawFB : fb;
 
     mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB);
 
 #ifdef DEBUG
     mInInternalMode_DrawFB = false;
 #endif
 }
 
 void
 GLScreenBuffer::BindReadFB(GLuint fb)
 {
-    MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
+    MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
 
     GLuint readFB = ReadFB();
     mUserReadFB = fb;
     mInternalReadFB = (fb == 0) ? readFB : fb;
 
     mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB);
 
 #ifdef DEBUG
@@ -245,30 +239,30 @@ GLScreenBuffer::BindFB_Internal(GLuint f
     mInInternalMode_DrawFB = true;
     mInInternalMode_ReadFB = true;
 #endif
 }
 
 void
 GLScreenBuffer::BindDrawFB_Internal(GLuint fb)
 {
-    MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
+    MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
 
     mInternalDrawFB = mUserDrawFB = fb;
     mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB);
 
 #ifdef DEBUG
     mInInternalMode_DrawFB = true;
 #endif
 }
 
 void
 GLScreenBuffer::BindReadFB_Internal(GLuint fb)
 {
-    MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
+    MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
 
     mInternalReadFB = mUserReadFB = fb;
     mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB);
 
 #ifdef DEBUG
     mInInternalMode_ReadFB = true;
 #endif
 }
@@ -304,17 +298,17 @@ GLScreenBuffer::GetReadFB() const
 {
 #ifdef DEBUG
     MOZ_ASSERT(mGL->IsCurrent());
     MOZ_ASSERT(!mInInternalMode_ReadFB);
 
     // We use raw_ here because this is debug code and we need to see what
     // the driver thinks.
     GLuint actual = 0;
-    if (mGL->IsSupported(GLFeature::framebuffer_blit))
+    if (mGL->IsSupported(GLFeature::split_framebuffer))
         mGL->raw_fGetIntegerv(LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT, (GLint*)&actual);
     else
         mGL->raw_fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*)&actual);
 
     GLuint predicted = mInternalReadFB;
     if (predicted != actual) {
         printf_stderr("Misprediction: Bound read FB predicted: %d. Was: %d.\n",
                       predicted, actual);
@@ -419,32 +413,38 @@ GLScreenBuffer::AssureBlitted()
         return;
 
     if (mDraw) {
         GLuint drawFB = DrawFB();
         GLuint readFB = ReadFB();
 
         MOZ_ASSERT(drawFB != 0);
         MOZ_ASSERT(drawFB != readFB);
-        MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
+        MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
         MOZ_ASSERT(mDraw->mSize == mRead->Size());
 
         ScopedBindFramebuffer boundFB(mGL);
         ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false);
 
         BindReadFB_Internal(drawFB);
         BindDrawFB_Internal(readFB);
 
-        const gfx::IntSize&  srcSize = mDraw->mSize;
-        const gfx::IntSize& destSize = mRead->Size();
+        if (mGL->IsSupported(GLFeature::framebuffer_blit)) {
+            const gfx::IntSize&  srcSize = mDraw->mSize;
+            const gfx::IntSize& destSize = mRead->Size();
 
-        mGL->raw_fBlitFramebuffer(0, 0,  srcSize.width,  srcSize.height,
-                                  0, 0, destSize.width, destSize.height,
-                                  LOCAL_GL_COLOR_BUFFER_BIT,
-                                  LOCAL_GL_NEAREST);
+            mGL->raw_fBlitFramebuffer(0, 0,  srcSize.width,  srcSize.height,
+                                      0, 0, destSize.width, destSize.height,
+                                      LOCAL_GL_COLOR_BUFFER_BIT,
+                                      LOCAL_GL_NEAREST);
+        } else if (mGL->IsExtensionSupported(GLContext::APPLE_framebuffer_multisample)) {
+            mGL->fResolveMultisampleFramebufferAPPLE();
+        } else {
+            MOZ_CRASH("No available blit methods.");
+        }
         // Done!
     }
 
     mNeedsBlit = false;
 }
 
 void
 GLScreenBuffer::Morph(UniquePtr<SurfaceFactory> newFactory)
--- a/gfx/gl/ScopedGLHelpers.cpp
+++ b/gfx/gl/ScopedGLHelpers.cpp
@@ -57,17 +57,17 @@ ScopedGLState::UnwrapImpl()
 }
 
 
 /* ScopedBindFramebuffer - Saves and restores with GetUserBoundFB and BindUserFB. */
 
 void
 ScopedBindFramebuffer::Init()
 {
-    if (mGL->IsSupported(GLFeature::framebuffer_blit)) {
+    if (mGL->IsSupported(GLFeature::split_framebuffer)) {
         mOldReadFB = mGL->GetReadFB();
         mOldDrawFB = mGL->GetDrawFB();
     } else {
         mOldReadFB = mOldDrawFB = mGL->GetFB();
     }
 }
 
 ScopedBindFramebuffer::ScopedBindFramebuffer(GLContext* aGL)