From c9668ecdb7188a90b050771727da899c54dc7013 Mon Sep 17 00:00:00 2001 From: "bsalomon@google.com" Date: Wed, 11 Apr 2012 18:16:41 +0000 Subject: [PATCH] Add support for GL_NV_framebuffer_multisample_coverage Review URL: http://codereview.appspot.com/6005043 git-svn-id: http://skia.googlecode.com/svn/trunk@3651 2bbb7eff-a529-9590-31e7-b0007b416f81 --- include/gpu/gl/GrGLDefines.h | 4 ++ include/gpu/gl/GrGLInterface.h | 2 + src/gpu/gl/GrGLCaps.cpp | 70 +++++++++++++++++++++- src/gpu/gl/GrGLCaps.h | 45 ++++++++++++++ src/gpu/gl/GrGpuGL.cpp | 67 ++++++++++++++------- src/gpu/gl/unix/GrGLCreateNativeInterface_unix.cpp | 4 ++ src/gpu/gl/win/GrGLCreateNativeInterface_win.cpp | 3 + 7 files changed, 173 insertions(+), 22 deletions(-) diff --git a/include/gpu/gl/GrGLDefines.h b/include/gpu/gl/GrGLDefines.h index 2268510..0e03b55 100644 --- a/include/gpu/gl/GrGLDefines.h +++ b/include/gpu/gl/GrGLDefines.h @@ -194,6 +194,10 @@ #define GR_GL_SAMPLES 0x80A9 #define GR_GL_SAMPLE_COVERAGE_VALUE 0x80AA #define GR_GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GR_GL_RENDERBUFFER_COVERAGE_SAMPLES 0x8CAB +#define GR_GL_RENDERBUFFER_COLOR_SAMPLES 0x8E10 +#define GR_GL_MAX_MULTISAMPLE_COVERAGE_MODES 0x8E11 +#define GR_GL_MULTISAMPLE_COVERAGE_MODES 0x8E12 /* GetTextureParameter */ /* GL_TEXTURE_MAG_FILTER */ diff --git a/include/gpu/gl/GrGLInterface.h b/include/gpu/gl/GrGLInterface.h index a16b9b1..876c072 100644 --- a/include/gpu/gl/GrGLInterface.h +++ b/include/gpu/gl/GrGLInterface.h @@ -223,6 +223,7 @@ extern "C" { typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLReadPixelsProc)(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height, GrGLenum format, GrGLenum type, GrGLvoid* pixels); typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLRenderbufferStorageProc)(GrGLenum target, GrGLenum internalformat, GrGLsizei width, GrGLsizei height); typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLRenderbufferStorageMultisampleProc)(GrGLenum target, GrGLsizei samples, GrGLenum internalformat, GrGLsizei width, GrGLsizei height); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLRenderbufferStorageMultisampleCoverageProc)(GrGLenum target, GrGLsizei coverageSamples, GrGLsizei colorSamples, GrGLenum internalformat, GrGLsizei width, GrGLsizei height); typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLResolveMultisampleFramebufferProc)(); typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLScissorProc)(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height); typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLShaderSourceProc)(GrGLuint shader, GrGLsizei count, const char** str, const GrGLint* length); @@ -384,6 +385,7 @@ public: GLPtr fReadPixels; GLPtr fRenderbufferStorage; GLPtr fRenderbufferStorageMultisample; + GLPtr fRenderbufferStorageMultisampleCoverage; GLPtr fResolveMultisampleFramebuffer; GLPtr fScissor; GLPtr fShaderSource; diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp index 5361967..c7e9380 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -9,6 +9,7 @@ #include "GrGLCaps.h" #include "GrGLContextInfo.h" +#include "SkTSearch.h" GrGLCaps::GrGLCaps() { this->reset(); @@ -19,6 +20,7 @@ void GrGLCaps::reset() { fStencilFormats.reset(); fStencilVerifiedColorConfigs.reset(); fMSFBOType = kNone_MSFBOType; + fCoverageAAType = kNone_CoverageAAType; fMaxFragmentUniformVectors = 0; fRGBA8RenderbufferSupport = false; fBGRAFormatSupport = false; @@ -43,6 +45,8 @@ GrGLCaps& GrGLCaps::operator = (const GrGLCaps& caps) { fStencilVerifiedColorConfigs = caps.fStencilVerifiedColorConfigs; fMaxFragmentUniformVectors = caps.fMaxFragmentUniformVectors; fMSFBOType = caps.fMSFBOType; + fCoverageAAType = caps.fCoverageAAType; + fMSAACoverageModes = caps.fMSAACoverageModes; fRGBA8RenderbufferSupport = caps.fRGBA8RenderbufferSupport; fBGRAFormatSupport = caps.fBGRAFormatSupport; fBGRAIsInternalFormat = caps.fBGRAIsInternalFormat; @@ -143,6 +147,22 @@ void GrGLCaps::init(const GrGLContextInfo& ctxInfo) { this->initStencilFormats(ctxInfo); } +namespace { +int coverage_mode_compare(const GrGLCaps::MSAACoverageMode* left, + const GrGLCaps::MSAACoverageMode* right) { + if (left->fCoverageSampleCnt < right->fCoverageSampleCnt) { + return -1; + } else if (right->fCoverageSampleCnt < left->fCoverageSampleCnt) { + return 1; + } else if (left->fColorSampleCnt < right->fColorSampleCnt) { + return -1; + } else if (right->fColorSampleCnt < left->fColorSampleCnt) { + return 1; + } + return 0; +} +} + void GrGLCaps::initFSAASupport(const GrGLContextInfo& ctxInfo) { fMSFBOType = kNone_MSFBOType; @@ -152,8 +172,8 @@ void GrGLCaps::initFSAASupport(const GrGLContextInfo& ctxInfo) { // and fbo_blit extensions. fMSFBOType = kDesktopEXT_MSFBOType; } else if (ctxInfo.hasExtension("GL_APPLE_framebuffer_multisample")) { - fMSFBOType = kAppleES_MSFBOType; - } + fMSFBOType = kAppleES_MSFBOType; + } } else { if ((ctxInfo.version() >= GR_GL_VER(3,0)) || ctxInfo.hasExtension("GL_ARB_framebuffer_object")) { @@ -162,6 +182,52 @@ void GrGLCaps::initFSAASupport(const GrGLContextInfo& ctxInfo) { ctxInfo.hasExtension("GL_EXT_framebuffer_blit")) { fMSFBOType = GrGLCaps::kDesktopEXT_MSFBOType; } + // TODO: We could populate fMSAACoverageModes using GetInternalformativ + // on GL 4.2+. It's format-specific, though. See also + // http://code.google.com/p/skia/issues/detail?id=470 about using actual + // rather than requested sample counts in cache key. + if (ctxInfo.hasExtension("GL_NV_framebuffer_multisample_coverage")) { + fCoverageAAType = kNVDesktop_CoverageAAType; + GrGLint count; + GR_GL_GetIntegerv(ctxInfo.interface(), + GR_GL_MAX_MULTISAMPLE_COVERAGE_MODES, + &count); + fMSAACoverageModes.setCount(count); + GR_GL_GetIntegerv(ctxInfo.interface(), + GR_GL_MULTISAMPLE_COVERAGE_MODES, + (int*)&fMSAACoverageModes[0]); + // The NV driver seems to return the modes already sorted but the + // spec doesn't require this. So we sort. + SkQSortCompareProc compareProc = + reinterpret_cast(&coverage_mode_compare); + SkQSort(&fMSAACoverageModes[0], + count, + sizeof(MSAACoverageMode), + compareProc); + } + } +} + +const GrGLCaps::MSAACoverageMode& GrGLCaps::getMSAACoverageMode( + int desiredSampleCount) const { + static const MSAACoverageMode kNoneMode = {0, 0}; + if (0 == fMSAACoverageModes.count()) { + return kNoneMode; + } else { + GrAssert(kNone_CoverageAAType != fCoverageAAType); + int max = (fMSAACoverageModes.end() - 1)->fCoverageSampleCnt; + desiredSampleCount = GrMin(desiredSampleCount, max); + MSAACoverageMode desiredMode = {desiredSampleCount, 0}; + int idx = SkTSearch(&fMSAACoverageModes[0], + fMSAACoverageModes.count(), + desiredMode, + sizeof(MSAACoverageMode), + &coverage_mode_compare); + if (idx < 0) { + idx = ~idx; + } + GrAssert(idx >= 0 && idx < fMSAACoverageModes.count()); + return fMSAACoverageModes[idx]; } } diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h index 8b3f9e7..31c4392 100644 --- a/src/gpu/gl/GrGLCaps.h +++ b/src/gpu/gl/GrGLCaps.h @@ -24,6 +24,23 @@ public: typedef GrGLStencilBuffer::Format StencilFormat; /** + * Represents a supported multisampling/coverage-sampling mode. + */ + struct MSAACoverageMode { + // "Coverage samples" includes samples that actually have color, depth, + // stencil, ... as well as those that don't (coverage only). All samples + // are coverage samples. (We're using the word "coverage sample" to + // match the NV extension language.) + int fCoverageSampleCnt; + + // Color samples are samples that store data values (color, stencil, + // depth) rather than just representing coverage. They are a subset + // of coverage samples. (Again the wording was chosen to match the + // extension.) + int fColorSampleCnt; + }; + + /** * The type of MSAA for FBOs supported. Different extensions have different * semantics of how / when a resolve is performed. */ @@ -46,6 +63,18 @@ public: kAppleES_MSFBOType, }; + enum CoverageAAType { + /** + * No coverage sample support + */ + kNone_CoverageAAType, + + /** + * GL_NV_framebuffer_multisample_coverage + */ + kNVDesktop_CoverageAAType, + }; + /** * Creates a GrGLCaps that advertises no support for any extensions, * formats, etc. Call init to initialize from a GrGLContextInfo. @@ -108,6 +137,20 @@ public: MSFBOType msFBOType() const { return fMSFBOType; } /** + * Reports the type of coverage sample AA support. + */ + CoverageAAType coverageAAType() const { return fCoverageAAType; } + + /** + * Chooses a supported coverage mode based on a desired sample count. The + * desired sample count is rounded up the next supported coverage sample + * count unless a it is larger than the max in which case it is rounded + * down. Once a coverage sample count is decided, the supported mode with + * the fewest color samples is chosen. + */ + const MSAACoverageMode& getMSAACoverageMode(int desiredSampleCount) const; + + /** * Prints the caps info using GrPrintf. */ void print() const; @@ -214,6 +257,8 @@ private: int fMaxFragmentUniformVectors; MSFBOType fMSFBOType; + CoverageAAType fCoverageAAType; + SkTDArray fMSAACoverageModes; bool fRGBA8RenderbufferSupport : 1; bool fBGRAFormatSupport : 1; diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp index dcde84e..9114a0e 100644 --- a/src/gpu/gl/GrGpuGL.cpp +++ b/src/gpu/gl/GrGpuGL.cpp @@ -845,6 +845,38 @@ bool GrGpuGL::uploadTexData(const GrGLTexture::Desc& desc, return succeeded; } +namespace { +bool renderbuffer_storage_msaa(GrGLContextInfo& ctxInfo, + int sampleCount, + GrGLenum format, + int width, int height) { + CLEAR_ERROR_BEFORE_ALLOC(ctxInfo.interface()); + GrAssert(GrGLCaps::kNone_MSFBOType != ctxInfo.caps().msFBOType()); + bool created = false; + if (GrGLCaps::kNVDesktop_CoverageAAType == + ctxInfo.caps().coverageAAType()) { + const GrGLCaps::MSAACoverageMode& mode = + ctxInfo.caps().getMSAACoverageMode(sampleCount); + GL_ALLOC_CALL(ctxInfo.interface(), + RenderbufferStorageMultisampleCoverage(GR_GL_RENDERBUFFER, + mode.fCoverageSampleCnt, + mode.fColorSampleCnt, + format, + width, height)); + created = (GR_GL_NO_ERROR == CHECK_ALLOC_ERROR(ctxInfo.interface())); + } + if (!created) { + GL_ALLOC_CALL(ctxInfo.interface(), + RenderbufferStorageMultisample(GR_GL_RENDERBUFFER, + sampleCount, + format, + width, height)); + created = (GR_GL_NO_ERROR == CHECK_ALLOC_ERROR(ctxInfo.interface())); + } + return created; +} +} + bool GrGpuGL::createRenderTargetObjects(int width, int height, GrGLuint texID, GrGLRenderTarget::Desc* desc) { @@ -854,7 +886,6 @@ bool GrGpuGL::createRenderTargetObjects(int width, int height, desc->fOwnIDs = true; GrGLenum status; - GrGLint err; GrGLenum msColorFormat = 0; // suppress warning @@ -890,14 +921,10 @@ bool GrGpuGL::createRenderTargetObjects(int width, int height, GrAssert(desc->fSampleCnt > 1); GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, desc->fMSColorRenderbufferID)); - CLEAR_ERROR_BEFORE_ALLOC(this->glInterface()); - GL_ALLOC_CALL(this->glInterface(), - RenderbufferStorageMultisample(GR_GL_RENDERBUFFER, - desc->fSampleCnt, - msColorFormat, - width, height)); - err = CHECK_ALLOC_ERROR(this->glInterface()); - if (err != GR_GL_NO_ERROR) { + if (!renderbuffer_storage_msaa(fGLContextInfo, + desc->fSampleCnt, + msColorFormat, + width, height)) { goto FAILED; } GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, desc->fRTFBOID)); @@ -1128,23 +1155,23 @@ bool GrGpuGL::createStencilBufferForRenderTarget(GrRenderTarget* rt, CLEAR_ERROR_BEFORE_ALLOC(this->glInterface()); // we do this "if" so that we don't call the multisample // version on a GL that doesn't have an MSAA extension. - if (samples > 1) { - GL_ALLOC_CALL(this->glInterface(), - RenderbufferStorageMultisample(GR_GL_RENDERBUFFER, - samples, - sFmt.fInternalFormat, - width, height)); + bool created; + if (samples > 0) { + created = renderbuffer_storage_msaa(fGLContextInfo, + samples, + sFmt.fInternalFormat, + width, height); } else { GL_ALLOC_CALL(this->glInterface(), RenderbufferStorage(GR_GL_RENDERBUFFER, sFmt.fInternalFormat, width, height)); + created = + (GR_GL_NO_ERROR == CHECK_ALLOC_ERROR(this->glInterface())); } - - GrGLenum err = CHECK_ALLOC_ERROR(this->glInterface()); - if (err == GR_GL_NO_ERROR) { - // After sized formats we attempt an unsized format and take whatever - // sizes GL gives us. In that case we query for the size. + if (created) { + // After sized formats we attempt an unsized format and take + // whatever sizes GL gives us. In that case we query for the size. GrGLStencilBuffer::Format format = sFmt; get_stencil_rb_sizes(this->glInterface(), sbID, &format); sb = new GrGLStencilBuffer(this, sbID, width, height, diff --git a/src/gpu/gl/unix/GrGLCreateNativeInterface_unix.cpp b/src/gpu/gl/unix/GrGLCreateNativeInterface_unix.cpp index 1e9f2e0..be915ac 100644 --- a/src/gpu/gl/unix/GrGLCreateNativeInterface_unix.cpp +++ b/src/gpu/gl/unix/GrGLCreateNativeInterface_unix.cpp @@ -102,6 +102,10 @@ const GrGLInterface* GrGLCreateNativeInterface() { interface->fPixelStorei = glPixelStorei; interface->fReadBuffer = glReadBuffer; interface->fReadPixels = glReadPixels; + if (GrGLHasExtensionFromString("GL_NV_framebuffer_multisample_coverage", + extString)) { + GR_GL_GET_PROC_SUFFIX(RenderbufferStorageMultisampleCoverage, NV); + } interface->fScissor = glScissor; GR_GL_GET_PROC(ShaderSource); interface->fStencilFunc = glStencilFunc; diff --git a/src/gpu/gl/win/GrGLCreateNativeInterface_win.cpp b/src/gpu/gl/win/GrGLCreateNativeInterface_win.cpp index f050a6f..2048974 100644 --- a/src/gpu/gl/win/GrGLCreateNativeInterface_win.cpp +++ b/src/gpu/gl/win/GrGLCreateNativeInterface_win.cpp @@ -123,6 +123,9 @@ const GrGLInterface* GrGLCreateNativeInterface() { GR_GL_GET_PROC(GetShaderiv); GR_GL_GET_PROC(GetUniformLocation); GR_GL_GET_PROC(LinkProgram); + if (GrGLHasExtensionFromString("GL_NV_framebuffer_multisample_coverage", extString)) { + GR_GL_GET_PROC_SUFFIX(RenderbufferStorageMultisampleCoverage, NV); + } GR_GL_GET_PROC(ShaderSource); GR_GL_GET_PROC(StencilFuncSeparate); GR_GL_GET_PROC(StencilMaskSeparate); -- 2.7.4