From 347c382d580cd1bc223e11a355b6a1c65d206e34 Mon Sep 17 00:00:00 2001 From: "bsalomon@google.com" Date: Wed, 1 May 2013 20:10:01 +0000 Subject: [PATCH] Add support for GL_EXT_multisampled_render_to_texture. 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 | 26 +++++++++------- src/gpu/gl/GrGLCaps.h | 36 +++++++++++++++++++--- src/gpu/gl/GrGLInterface.cpp | 3 +- src/gpu/gl/GrGpuGL.cpp | 33 ++++++++++---------- .../android/GrGLCreateNativeInterface_android.cpp | 22 +++++++++++-- 5 files changed, 85 insertions(+), 35 deletions(-) diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp index 716989e..8ec76a8 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -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); diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h index 4aff025..1ce5fa6 100644 --- a/src/gpu/gl/GrGLCaps.h +++ b/src/gpu/gl/GrGLCaps.h @@ -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; } diff --git a/src/gpu/gl/GrGLInterface.cpp b/src/gpu/gl/GrGLInterface.cpp index 94bb54d..f5cef11 100644 --- a/src/gpu/gl/GrGLInterface.cpp +++ b/src/gpu/gl/GrGLInterface.cpp @@ -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; diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp index de7746f..a0121d7 100644 --- a/src/gpu/gl/GrGpuGL.cpp +++ b/src/gpu/gl/GrGpuGL.cpp @@ -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(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 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 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; diff --git a/src/gpu/gl/android/GrGLCreateNativeInterface_android.cpp b/src/gpu/gl/android/GrGLCreateNativeInterface_android.cpp index 842741c..77248a0 100644 --- a/src/gpu/gl/android/GrGLCreateNativeInterface_android.cpp +++ b/src/gpu/gl/android/GrGLCreateNativeInterface_android.cpp @@ -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 @@ -18,6 +19,10 @@ const GrGLInterface* GrGLCreateNativeInterface() { static SkAutoTUnref 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; -- 2.7.4