diff --git a/include/gpu/GrCaps.h b/include/gpu/GrCaps.h index 248135d691..0f376f9e5a 100644 --- a/include/gpu/GrCaps.h +++ b/include/gpu/GrCaps.h @@ -63,6 +63,7 @@ public: bool dstReadInShaderSupport() const { return fDstReadInShaderSupport; } bool dualSourceBlendingSupport() const { return fDualSourceBlendingSupport; } bool mixedSamplesSupport() const { return fMixedSamplesSupport; } + bool programmableSampleLocationsSupport() const { return fProgrammableSampleLocationsSupport; } /** * Get the precision info for a variable of type kFloat_GrSLType, kVec2f_GrSLType, etc in a @@ -93,6 +94,7 @@ protected: bool fDstReadInShaderSupport : 1; bool fDualSourceBlendingSupport : 1; bool fMixedSamplesSupport : 1; + bool fProgrammableSampleLocationsSupport : 1; bool fShaderPrecisionVaries; PrecisionInfo fFloatPrecisions[kGrShaderTypeCount][kGrSLPrecisionCount]; diff --git a/include/gpu/gl/GrGLFunctions.h b/include/gpu/gl/GrGLFunctions.h index aea6d2c22e..7fe82d671e 100644 --- a/include/gpu/gl/GrGLFunctions.h +++ b/include/gpu/gl/GrGLFunctions.h @@ -390,6 +390,8 @@ typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetVertexArrayIntegeri_vProc)(GrGLuin typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetVertexArrayPointeri_vProc)(GrGLuint vaobj, GrGLuint index, GrGLenum pname, GrGLvoid **param); typedef GrGLvoid* (GR_GL_FUNCTION_TYPE* GrGLMapNamedBufferRangeProc)(GrGLuint buffer, GrGLintptr offset, GrGLsizeiptr length, GrGLbitfield access); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLFlushMappedNamedBufferRangeProc)(GrGLuint buffer, GrGLintptr offset, GrGLsizeiptr length); +// OpenGL 4.5 +typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLNamedFramebufferParameteriProc)(GrGLuint framebuffer, GrGLenum pname, GrGLint param); /* KHR_debug */ typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDebugMessageControlProc)(GrGLenum source, GrGLenum type, GrGLenum severity, GrGLsizei count, const GrGLuint* ids, GrGLboolean enabled); diff --git a/include/gpu/gl/GrGLInterface.h b/include/gpu/gl/GrGLInterface.h index bdbedd969b..c4748c776a 100644 --- a/include/gpu/gl/GrGLInterface.h +++ b/include/gpu/gl/GrGLInterface.h @@ -490,6 +490,8 @@ public: GLPtr fGetVertexArrayPointeri_v; GLPtr fMapNamedBufferRange; GLPtr fFlushMappedNamedBufferRange; + // OpenGL 4.5 + GLPtr fNamedFramebufferParameteri; /* KHR_debug */ GLPtr fDebugMessageControl; diff --git a/src/gpu/GrCaps.cpp b/src/gpu/GrCaps.cpp index 1bcdb20383..cab44b97ce 100644 --- a/src/gpu/GrCaps.cpp +++ b/src/gpu/GrCaps.cpp @@ -16,6 +16,7 @@ GrShaderCaps::GrShaderCaps() { fDstReadInShaderSupport = false; fDualSourceBlendingSupport = false; fMixedSamplesSupport = false; + fProgrammableSampleLocationsSupport = false; fShaderPrecisionVaries = false; } @@ -46,14 +47,15 @@ static const char* precision_to_string(GrSLPrecision p) { SkString GrShaderCaps::dump() const { SkString r; static const char* gNY[] = { "NO", "YES" }; - r.appendf("Shader Derivative Support : %s\n", gNY[fShaderDerivativeSupport]); - r.appendf("Geometry Shader Support : %s\n", gNY[fGeometryShaderSupport]); - r.appendf("Path Rendering Support : %s\n", gNY[fPathRenderingSupport]); - r.appendf("Dst Read In Shader Support : %s\n", gNY[fDstReadInShaderSupport]); - r.appendf("Dual Source Blending Support : %s\n", gNY[fDualSourceBlendingSupport]); - r.appendf("Mixed Samples Support : %s\n", gNY[fMixedSamplesSupport]); + r.appendf("Shader Derivative Support : %s\n", gNY[fShaderDerivativeSupport]); + r.appendf("Geometry Shader Support : %s\n", gNY[fGeometryShaderSupport]); + r.appendf("Path Rendering Support : %s\n", gNY[fPathRenderingSupport]); + r.appendf("Dst Read In Shader Support : %s\n", gNY[fDstReadInShaderSupport]); + r.appendf("Dual Source Blending Support : %s\n", gNY[fDualSourceBlendingSupport]); + r.appendf("Mixed Samples Support : %s\n", gNY[fMixedSamplesSupport]); + r.appendf("Programmable Sample Locations Support : %s\n", gNY[fProgrammableSampleLocationsSupport]); - r.appendf("Shader Float Precisions (varies: %s):\n", gNY[fShaderPrecisionVaries]); + r.appendf("Shader Float Precisions (varies: %s) :\n", gNY[fShaderPrecisionVaries]); for (int s = 0; s < kGrShaderTypeCount; ++s) { GrShaderType shaderType = static_cast(s); diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp index 0ab1600b7d..0df74a6c28 100644 --- a/src/gpu/GrClipMaskManager.cpp +++ b/src/gpu/GrClipMaskManager.cpp @@ -306,7 +306,7 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder, } // If MSAA is enabled we can do everything in the stencil buffer. - if (0 == rt->numColorSamples() && requiresAA) { + if (0 == rt->numStencilSamples() && requiresAA) { GrTexture* result = nullptr; // The top-left of the mask corresponds to the top-left corner of the bounds. @@ -757,7 +757,7 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, pipelineBuilder.setDisableColorXPFactory(); // if the target is MSAA then we want MSAA enabled when the clip is soft - if (rt->isUnifiedMultisampled()) { + if (rt->isStencilBufferMultisampled()) { pipelineBuilder.setState(GrPipelineBuilder::kHWAntialias_Flag, element->isAA()); } diff --git a/src/gpu/gl/GrGLAssembleInterface.cpp b/src/gpu/gl/GrGLAssembleInterface.cpp index f19a1cb075..d7a0af8024 100644 --- a/src/gpu/gl/GrGLAssembleInterface.cpp +++ b/src/gpu/gl/GrGLAssembleInterface.cpp @@ -450,6 +450,10 @@ const GrGLInterface* GrGLAssembleGLInterface(void* ctx, GrGLGetProc get) { } } + if (glVer >= GR_GL_VER(4,5)) { + GET_PROC(NamedFramebufferParameteri); + } + if (glVer >= GR_GL_VER(4,3) || extensions.has("GL_KHR_debug")) { // KHR_debug defines these methods to have no suffix in an OpenGL (not ES) context. GET_PROC(DebugMessageControl); diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp index 6522e1b14b..b97022f2d7 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -355,6 +355,10 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, fDiscardRenderTargetSupport = false; fInvalidateFBType = kNone_InvalidateFBType; } + glslCaps->fProgrammableSampleLocationsSupport = + ctxInfo.hasExtension("GL_NV_sample_locations") || + ctxInfo.hasExtension("GL_ARB_sample_locations"); + /************************************************************************** * GrCaps fields diff --git a/src/gpu/gl/GrGLDefines.h b/src/gpu/gl/GrGLDefines.h index cc588b93b7..89ff56b885 100644 --- a/src/gpu/gl/GrGLDefines.h +++ b/src/gpu/gl/GrGLDefines.h @@ -889,6 +889,9 @@ #define GR_GL_MULTISAMPLE_RASTERIZATION_ALLOWED 0x932B #define GR_GL_EFFECTIVE_RASTER_SAMPLES 0x932C +/* GL_NV_sample_locations and GL_ARB_sample_locations */ +#define GR_GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS 0x9342 + /* GL_KHR_debug */ #define GR_GL_DEBUG_OUTPUT 0x92E0 #define GR_GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index 5388387c3b..cd6bf39adc 100644 --- a/src/gpu/gl/GrGLGpu.cpp +++ b/src/gpu/gl/GrGLGpu.cpp @@ -1476,7 +1476,7 @@ bool GrGLGpu::flushGLState(const DrawArgs& args) { GrGLRenderTarget* glRT = static_cast(pipeline.getRenderTarget()); this->flushStencil(pipeline.getStencil()); this->flushScissor(pipeline.getScissorState(), glRT->getViewport(), glRT->origin()); - this->flushHWAAState(glRT, pipeline.isHWAntialiasState()); + this->flushHWAAState(glRT, pipeline.isHWAntialiasState(), !pipeline.getStencil().isDisabled()); // This must come after textures are flushed because a texture may need // to be msaa-resolved (which will modify bound FBO state). @@ -1899,6 +1899,22 @@ bool GrGLGpu::onReadPixels(GrSurface* surface, return true; } +void GrGLGpu::setColocatedSampleLocations(GrRenderTarget* rt, bool useColocatedSampleLocations) { + GrGLRenderTarget* target = static_cast(rt->asRenderTarget()); + SkASSERT(0 != target->renderFBOID()); + + if (!rt->isStencilBufferMultisampled() || + useColocatedSampleLocations == target->usesColocatedSampleLocations()) { + return; + } + + GL_CALL(NamedFramebufferParameteri(target->renderFBOID(), + GR_GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS, + useColocatedSampleLocations)); + + target->flagAsUsingColocatedSampleLocations(useColocatedSampleLocations); +} + void GrGLGpu::flushRenderTarget(GrGLRenderTarget* target, const SkIRect* bound) { SkASSERT(target); @@ -2146,9 +2162,19 @@ void GrGLGpu::flushStencil(const GrStencilSettings& stencilSettings) { } } -void GrGLGpu::flushHWAAState(GrRenderTarget* rt, bool useHWAA) { +void GrGLGpu::flushHWAAState(GrRenderTarget* rt, bool useHWAA, bool stencilEnabled) { SkASSERT(!useHWAA || rt->isStencilBufferMultisampled()); + if (rt->hasMixedSamples() && stencilEnabled && + this->glCaps().glslCaps()->programmableSampleLocationsSupport()) { + if (useHWAA) { + this->setColocatedSampleLocations(rt, false); + } else { + this->setColocatedSampleLocations(rt, true); + } + useHWAA = true; + } + if (this->glCaps().multisampleDisableSupport()) { if (useHWAA) { if (kYes_TriState != fMSAAEnabled) { @@ -2928,7 +2954,7 @@ void GrGLGpu::copySurfaceAsDraw(GrSurface* dst, this->flushBlend(blendInfo); this->flushColorWrite(true); this->flushDrawFace(GrPipelineBuilder::kBoth_DrawFace); - this->flushHWAAState(dstRT, false); + this->flushHWAAState(dstRT, false, false); this->disableScissor(); GrStencilSettings stencil; stencil.setDisabled(); diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h index 2387b44af6..dee201292e 100644 --- a/src/gpu/gl/GrGLGpu.h +++ b/src/gpu/gl/GrGLGpu.h @@ -255,12 +255,16 @@ private: // ensures that such operations don't negatively interact with tracking bound textures. void setScratchTextureUnit(); + // colocates all samples at pixel center for render target, if MSAA. + // allows drawing coverage based AA shapes in MSAA mode. + void setColocatedSampleLocations(GrRenderTarget* rt, bool useColocatedSampleLocations); + // bounds is region that may be modified and therefore has to be resolved. // nullptr means whole target. Can be an empty rect. void flushRenderTarget(GrGLRenderTarget*, const SkIRect* bounds); void flushStencil(const GrStencilSettings&); - void flushHWAAState(GrRenderTarget* rt, bool useHWAA); + void flushHWAAState(GrRenderTarget* rt, bool useHWAA, bool stencilEnabled); bool configToGLFormats(GrPixelConfig config, bool getSizedInternal, diff --git a/src/gpu/gl/GrGLInterface.cpp b/src/gpu/gl/GrGLInterface.cpp index ec51797c7e..ecd400387a 100644 --- a/src/gpu/gl/GrGLInterface.cpp +++ b/src/gpu/gl/GrGLInterface.cpp @@ -701,6 +701,12 @@ bool GrGLInterface::validate() const { } } + if (kGL_GrGLStandard == fStandard && glVer >= GR_GL_VER(4,5)) { + if (nullptr == fFunctions.fNamedFramebufferParameteri) { + RETURN_FALSE_INTERFACE + } + } + if ((kGL_GrGLStandard == fStandard && glVer >= GR_GL_VER(4,3)) || fExtensions.has("GL_KHR_debug")) { if (nullptr == fFunctions.fDebugMessageControl || diff --git a/src/gpu/gl/GrGLPathRendering.cpp b/src/gpu/gl/GrGLPathRendering.cpp index 78f78baf9d..a74014b96b 100644 --- a/src/gpu/gl/GrGLPathRendering.cpp +++ b/src/gpu/gl/GrGLPathRendering.cpp @@ -100,7 +100,7 @@ void GrGLPathRendering::onStencilPath(const StencilPathArgs& args, const GrPath* SkISize size = SkISize::Make(rt->width(), rt->height()); this->setProjectionMatrix(*args.fViewMatrix, size, rt->origin()); gpu->flushScissor(*args.fScissor, rt->getViewport(), rt->origin()); - gpu->flushHWAAState(rt, args.fUseHWAA); + gpu->flushHWAAState(rt, args.fUseHWAA, true); gpu->flushRenderTarget(rt, nullptr); const GrGLPath* glPath = static_cast(path); diff --git a/src/gpu/gl/GrGLRenderTarget.h b/src/gpu/gl/GrGLRenderTarget.h index d1365efd42..ce04ae017d 100644 --- a/src/gpu/gl/GrGLRenderTarget.h +++ b/src/gpu/gl/GrGLRenderTarget.h @@ -70,6 +70,21 @@ public: // components seperately. void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const override; + /** + * @return true if sample locations colocated at pixel center have been set for this + * render target. Requires support for NV_sample_locations. + */ + bool usesColocatedSampleLocations() const { + return fUsesColocatedSampleLocations; + } + + /** + * Flag render target as using or not using sample locations colocated at pixel center. + */ + void flagAsUsingColocatedSampleLocations(bool useColocatedSampleLocations) { + fUsesColocatedSampleLocations = useColocatedSampleLocations; + } + protected: // The public constructor registers this object with the cache. However, only the most derived // class should register with the cache. This constructor does not do the registration and @@ -116,6 +131,10 @@ private: // release zero out the IDs and the cache needs to know the size even after those actions. size_t fGpuMemorySize; + // True if sample locations colocated at pixel center are currently in use, false if default + // sample locations are currently in use. + bool fUsesColocatedSampleLocations; + typedef GrRenderTarget INHERITED; };