From 7f861927fcd4f9fdef958b5ed9d50b1362ee3232 Mon Sep 17 00:00:00 2001 From: Robert Phillips Date: Tue, 30 Jan 2018 13:13:42 +0000 Subject: Revert "Drop support for unused MSAA extensions" This reverts commit 7df27465c4ecc8a4a0cdd95e9785c342903c2de9. Reason for revert: experimental revert to see if this is the cause of the tree redness Original change's description: > Drop support for unused MSAA extensions > > Bug: skia: > Change-Id: I113b80e3f991f195155148625ceb29242ea82776 > Reviewed-on: https://skia-review.googlesource.com/101403 > Reviewed-by: Brian Salomon > Commit-Queue: Chris Dalton TBR=bsalomon@google.com,csmartdalton@google.com,ethannicholas@google.com Change-Id: I4fa4123e2d176bef88cd76a09a14053d9ac5809f No-Presubmit: true No-Tree-Checks: true No-Try: true Bug: skia: Reviewed-on: https://skia-review.googlesource.com/101680 Reviewed-by: Robert Phillips Commit-Queue: Robert Phillips --- gn/tests.gni | 1 + include/gpu/GrCaps.h | 2 + include/gpu/GrRenderTarget.h | 1 + include/gpu/GrShaderCaps.h | 21 +++ src/gpu/GrCaps.cpp | 2 + src/gpu/GrDefaultGeoProcFactory.cpp | 2 +- src/gpu/GrFragmentProcessor.cpp | 2 + src/gpu/GrGpu.cpp | 43 ++++++ src/gpu/GrGpu.h | 36 +++++ src/gpu/GrPathProcessor.cpp | 2 +- src/gpu/GrProcessor.h | 31 ++++- src/gpu/GrProgramDesc.cpp | 13 ++ src/gpu/GrProgramDesc.h | 25 ++-- src/gpu/GrRenderTarget.cpp | 14 ++ src/gpu/GrRenderTargetPriv.h | 5 + src/gpu/GrShaderCaps.cpp | 8 ++ src/gpu/ccpr/GrCCCoverageProcessor.cpp | 4 +- src/gpu/ccpr/GrCCCoverageProcessor.h | 8 +- src/gpu/ccpr/GrCCCubicShader.cpp | 4 +- src/gpu/ccpr/GrCCCubicShader.h | 4 +- src/gpu/ccpr/GrCCPathProcessor.cpp | 2 +- src/gpu/ccpr/GrCCQuadraticShader.cpp | 4 +- src/gpu/ccpr/GrCCQuadraticShader.h | 4 +- src/gpu/ccpr/GrCCTriangleShader.cpp | 4 +- src/gpu/ccpr/GrCCTriangleShader.h | 4 +- src/gpu/ddl/GrDDLGpu.h | 6 + src/gpu/effects/GrBezierEffect.cpp | 6 +- src/gpu/effects/GrBitmapTextGeoProc.cpp | 2 +- src/gpu/effects/GrDistanceFieldGeoProc.cpp | 6 +- src/gpu/effects/GrShadowGeoProc.cpp | 2 +- src/gpu/gl/GrGLCaps.cpp | 42 ++++++ src/gpu/gl/GrGLGpu.cpp | 32 +++++ src/gpu/gl/GrGLGpu.h | 3 + src/gpu/gl/GrGLGpuProgramCache.cpp | 2 +- src/gpu/gl/builders/GrGLProgramBuilder.cpp | 3 +- src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp | 118 ++++++++++++++++ src/gpu/glsl/GrGLSLFragmentShaderBuilder.h | 81 ++++++++++- src/gpu/glsl/GrGLSLPrimitiveProcessor.cpp | 2 +- src/gpu/glsl/GrGLSLPrimitiveProcessor.h | 8 +- src/gpu/glsl/GrGLSLProgramBuilder.cpp | 3 + src/gpu/glsl/GrGLSLShaderBuilder.h | 4 +- src/gpu/mock/GrMockGpu.h | 5 + src/gpu/mtl/GrMtlCaps.mm | 1 + src/gpu/mtl/GrMtlGpu.h | 3 + src/gpu/ops/GrAAConvexPathRenderer.cpp | 2 +- src/gpu/ops/GrDashOp.cpp | 4 +- src/gpu/ops/GrMSAAPathRenderer.cpp | 2 +- src/gpu/ops/GrOvalOpFactory.cpp | 6 +- src/gpu/vk/GrVkGpu.cpp | 7 + src/gpu/vk/GrVkGpu.h | 3 + src/gpu/vk/GrVkPipelineStateBuilder.cpp | 3 +- src/gpu/vk/GrVkPipelineStateCache.cpp | 2 +- src/sksl/SkSLIRGenerator.cpp | 3 + src/sksl/SkSLUtil.h | 12 ++ tests/GpuSampleLocationsTest.cpp | 199 +++++++++++++++++++++++++++ tests/GrMeshTest.cpp | 2 +- tests/GrPipelineDynamicStateTest.cpp | 2 +- tests/PrimitiveProcessorTest.cpp | 2 +- 58 files changed, 759 insertions(+), 65 deletions(-) create mode 100644 tests/GpuSampleLocationsTest.cpp diff --git a/gn/tests.gni b/gn/tests.gni index 36eebf3054..e4519d9678 100644 --- a/gn/tests.gni +++ b/gn/tests.gni @@ -89,6 +89,7 @@ tests_sources = [ "$_tests/GpuDrawPathTest.cpp", "$_tests/GpuLayerCacheTest.cpp", "$_tests/GpuRectanizerTest.cpp", + "$_tests/GpuSampleLocationsTest.cpp", "$_tests/GradientTest.cpp", "$_tests/GrAllocatorTest.cpp", "$_tests/GrCCPRTest.cpp", diff --git a/include/gpu/GrCaps.h b/include/gpu/GrCaps.h index c828922148..f4d6e06280 100644 --- a/include/gpu/GrCaps.h +++ b/include/gpu/GrCaps.h @@ -52,6 +52,7 @@ public: bool gpuTracingSupport() const { return fGpuTracingSupport; } bool oversizedStencilSupport() const { return fOversizedStencilSupport; } bool textureBarrierSupport() const { return fTextureBarrierSupport; } + bool sampleLocationsSupport() const { return fSampleLocationsSupport; } bool multisampleDisableSupport() const { return fMultisampleDisableSupport; } bool instanceAttribSupport() const { return fInstanceAttribSupport; } bool usesMixedSamples() const { return fUsesMixedSamples; } @@ -206,6 +207,7 @@ protected: bool fGpuTracingSupport : 1; bool fOversizedStencilSupport : 1; bool fTextureBarrierSupport : 1; + bool fSampleLocationsSupport : 1; bool fMultisampleDisableSupport : 1; bool fInstanceAttribSupport : 1; bool fUsesMixedSamples : 1; diff --git a/include/gpu/GrRenderTarget.h b/include/gpu/GrRenderTarget.h index ee43dd3f75..4eee7f63ce 100644 --- a/include/gpu/GrRenderTarget.h +++ b/include/gpu/GrRenderTarget.h @@ -134,6 +134,7 @@ private: int fSampleCnt; GrStencilAttachment* fStencilAttachment; + uint8_t fMultisampleSpecsID; GrRenderTargetFlags fFlags; SkIRect fResolveRect; diff --git a/include/gpu/GrShaderCaps.h b/include/gpu/GrShaderCaps.h index 62100c1387..9dd2f96d89 100644 --- a/include/gpu/GrShaderCaps.h +++ b/include/gpu/GrShaderCaps.h @@ -72,6 +72,12 @@ public: bool noperspectiveInterpolationSupport() const { return fNoPerspectiveInterpolationSupport; } + bool multisampleInterpolationSupport() const { return fMultisampleInterpolationSupport; } + + bool sampleVariablesSupport() const { return fSampleVariablesSupport; } + + bool sampleMaskOverrideCoverageSupport() const { return fSampleMaskOverrideCoverageSupport; } + bool externalTextureSupport() const { return fExternalTextureSupport; } bool texelFetchSupport() const { return fTexelFetchSupport; } @@ -186,6 +192,16 @@ public: return fNoPerspectiveInterpolationExtensionString; } + const char* multisampleInterpolationExtensionString() const { + SkASSERT(this->multisampleInterpolationSupport()); + return fMultisampleInterpolationExtensionString; + } + + const char* sampleVariablesExtensionString() const { + SkASSERT(this->sampleVariablesSupport()); + return fSampleVariablesExtensionString; + } + const char* imageLoadStoreExtensionString() const { SkASSERT(this->imageLoadStoreSupport()); return fImageLoadStoreExtensionString; @@ -246,6 +262,9 @@ private: bool fFlatInterpolationSupport : 1; bool fPreferFlatInterpolation : 1; bool fNoPerspectiveInterpolationSupport : 1; + bool fMultisampleInterpolationSupport : 1; + bool fSampleVariablesSupport : 1; + bool fSampleMaskOverrideCoverageSupport : 1; bool fExternalTextureSupport : 1; bool fTexelFetchSupport : 1; bool fVertexIDSupport : 1; @@ -275,6 +294,8 @@ private: const char* fExternalTextureExtensionString; const char* fTexelBufferExtensionString; const char* fNoPerspectiveInterpolationExtensionString; + const char* fMultisampleInterpolationExtensionString; + const char* fSampleVariablesExtensionString; const char* fImageLoadStoreExtensionString; const char* fFBFetchColorName; diff --git a/src/gpu/GrCaps.cpp b/src/gpu/GrCaps.cpp index 7f075503b3..427b20425a 100644 --- a/src/gpu/GrCaps.cpp +++ b/src/gpu/GrCaps.cpp @@ -50,6 +50,7 @@ GrCaps::GrCaps(const GrContextOptions& options) { fGpuTracingSupport = false; fOversizedStencilSupport = false; fTextureBarrierSupport = false; + fSampleLocationsSupport = false; fMultisampleDisableSupport = false; fInstanceAttribSupport = false; fUsesMixedSamples = false; @@ -154,6 +155,7 @@ void GrCaps::dumpJSON(SkJSONWriter* writer) const { writer->appendBool("Gpu Tracing Support", fGpuTracingSupport); writer->appendBool("Oversized Stencil Support", fOversizedStencilSupport); writer->appendBool("Texture Barrier Support", fTextureBarrierSupport); + writer->appendBool("Sample Locations Support", fSampleLocationsSupport); writer->appendBool("Multisample disable support", fMultisampleDisableSupport); writer->appendBool("Instance Attrib Support", fInstanceAttribSupport); writer->appendBool("Uses Mixed Samples", fUsesMixedSamples); diff --git a/src/gpu/GrDefaultGeoProcFactory.cpp b/src/gpu/GrDefaultGeoProcFactory.cpp index 8f4b9592a5..37967e4d2a 100644 --- a/src/gpu/GrDefaultGeoProcFactory.cpp +++ b/src/gpu/GrDefaultGeoProcFactory.cpp @@ -73,7 +73,7 @@ public: void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { const DefaultGeoProc& gp = args.fGP.cast(); GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; - GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; + GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; diff --git a/src/gpu/GrFragmentProcessor.cpp b/src/gpu/GrFragmentProcessor.cpp index 12ae2b1ee9..0c7c06fd6a 100644 --- a/src/gpu/GrFragmentProcessor.cpp +++ b/src/gpu/GrFragmentProcessor.cpp @@ -78,6 +78,8 @@ void GrFragmentProcessor::markPendingExecution() const { } int GrFragmentProcessor::registerChildProcessor(std::unique_ptr child) { + this->combineRequiredFeatures(*child); + if (child->usesLocalCoords()) { fFlags |= kUsesLocalCoords_Flag; } diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp index a8b022a36d..eb005d110a 100644 --- a/src/gpu/GrGpu.cpp +++ b/src/gpu/GrGpu.cpp @@ -36,6 +36,7 @@ GrGpu::GrGpu(GrContext* context) : fResetTimestamp(kExpiredTimestamp+1) , fResetBits(kAll_GrBackendState) , fContext(context) { + fMultisampleSpecs.emplace_back(0, 0, nullptr); // Index 0 is an invalid unique id. } GrGpu::~GrGpu() {} @@ -422,6 +423,48 @@ void GrGpu::didWriteToSurface(GrSurface* surface, const SkIRect* bounds, uint32_ } } +const GrGpu::MultisampleSpecs& GrGpu::queryMultisampleSpecs(const GrPipeline& pipeline) { + GrRenderTarget* rt = pipeline.renderTarget(); + SkASSERT(rt->numStencilSamples() > 1); + + GrStencilSettings stencil; + if (pipeline.isStencilEnabled()) { + // TODO: attach stencil and create settings during render target flush. + SkASSERT(rt->renderTargetPriv().getStencilAttachment()); + stencil.reset(*pipeline.getUserStencil(), pipeline.hasStencilClip(), + rt->renderTargetPriv().numStencilBits()); + } + + int effectiveSampleCnt; + SkSTArray<16, SkPoint, true> pattern; + this->onQueryMultisampleSpecs(rt, pipeline.proxy()->origin(), stencil, + &effectiveSampleCnt, &pattern); + SkASSERT(effectiveSampleCnt >= rt->numStencilSamples()); + + uint8_t id; + if (this->caps()->sampleLocationsSupport()) { + SkASSERT(pattern.count() == effectiveSampleCnt); + const auto& insertResult = fMultisampleSpecsIdMap.insert( + MultisampleSpecsIdMap::value_type(pattern, SkTMin(fMultisampleSpecs.count(), 255))); + id = insertResult.first->second; + if (insertResult.second) { + // This means the insert did not find the pattern in the map already, and therefore an + // actual insertion took place. (We don't expect to see many unique sample patterns.) + const SkPoint* sampleLocations = insertResult.first->first.begin(); + SkASSERT(id == fMultisampleSpecs.count()); + fMultisampleSpecs.emplace_back(id, effectiveSampleCnt, sampleLocations); + } + } else { + id = effectiveSampleCnt; + for (int i = fMultisampleSpecs.count(); i <= id; ++i) { + fMultisampleSpecs.emplace_back(i, i, nullptr); + } + } + SkASSERT(id > 0); + + return fMultisampleSpecs[id]; +} + bool GrGpu::SamplePatternComparator::operator()(const SamplePattern& a, const SamplePattern& b) const { if (a.count() != b.count()) { diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h index d03c0811c9..2f12073f8a 100644 --- a/src/gpu/GrGpu.h +++ b/src/gpu/GrGpu.h @@ -328,6 +328,33 @@ public: const SkIRect& srcRect, const SkIPoint& dstPoint); + struct MultisampleSpecs { + MultisampleSpecs(uint8_t uniqueID, int effectiveSampleCnt, const SkPoint* locations) + : fUniqueID(uniqueID), + fEffectiveSampleCnt(effectiveSampleCnt), + fSampleLocations(locations) {} + + // Nonzero ID that uniquely identifies these multisample specs. + uint8_t fUniqueID; + // The actual number of samples the GPU will run. NOTE: this value can be greater than the + // the render target's sample count. + int fEffectiveSampleCnt; + // If sample locations are supported, points to the subpixel locations at which the GPU will + // sample. Pixel center is at (.5, .5), and (0, 0) indicates the top left corner. + const SkPoint* fSampleLocations; + }; + + // Finds a render target's multisample specs. The pipeline is only needed in case we need to + // flush the draw state prior to querying multisample info. The pipeline is not expected to + // affect the multisample information itself. + const MultisampleSpecs& queryMultisampleSpecs(const GrPipeline&); + + // Finds the multisample specs with a given unique id. + const MultisampleSpecs& getMultisampleSpecs(uint8_t uniqueID) { + SkASSERT(uniqueID > 0 && uniqueID < fMultisampleSpecs.count()); + return fMultisampleSpecs[uniqueID]; + } + // Creates a GrGpuRTCommandBuffer which GrOpLists send draw commands to instead of directly // to the Gpu object. virtual GrGpuRTCommandBuffer* createCommandBuffer( @@ -572,6 +599,11 @@ private: GrSurface* src, GrSurfaceOrigin srcOrigin, const SkIRect& srcRect, const SkIPoint& dstPoint) = 0; + // overridden by backend specific derived class to perform the multisample queries + virtual void onQueryMultisampleSpecs(GrRenderTarget*, GrSurfaceOrigin rtOrigin, + const GrStencilSettings&, + int* effectiveSampleCnt, SamplePattern*) = 0; + virtual void onFinishFlush(bool insertedSemaphores) = 0; virtual void onDumpJSON(SkJSONWriter*) const {} @@ -586,8 +618,12 @@ private: bool operator()(const SamplePattern&, const SamplePattern&) const; }; + typedef std::map MultisampleSpecsIdMap; + ResetTimestamp fResetTimestamp; uint32_t fResetBits; + MultisampleSpecsIdMap fMultisampleSpecsIdMap; + SkSTArray<1, MultisampleSpecs, true> fMultisampleSpecs; // The context owns us, not vice-versa, so this ptr is not ref'ed by Gpu. GrContext* fContext; diff --git a/src/gpu/GrPathProcessor.cpp b/src/gpu/GrPathProcessor.cpp index bae3e8029a..d75ac735c1 100644 --- a/src/gpu/GrPathProcessor.cpp +++ b/src/gpu/GrPathProcessor.cpp @@ -24,7 +24,7 @@ public: } void emitCode(EmitArgs& args) override { - GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; + GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; const GrPathProcessor& pathProc = args.fGP.cast(); if (!pathProc.viewMatrix().hasPerspective()) { diff --git a/src/gpu/GrProcessor.h b/src/gpu/GrProcessor.h index 690a1f6d75..9fae1b01ef 100644 --- a/src/gpu/GrProcessor.h +++ b/src/gpu/GrProcessor.h @@ -166,6 +166,18 @@ public: return str; } + /** + * Platform specific built-in features that a processor can request for the fragment shader. + */ + enum RequiredFeatures { + kNone_RequiredFeatures = 0, + kSampleLocations_RequiredFeature = 1 << 0 + }; + + GR_DECL_BITFIELD_OPS_FRIENDS(RequiredFeatures); + + RequiredFeatures requiredFeatures() const { return fRequiredFeatures; } + void* operator new(size_t size); void operator delete(void* target); @@ -183,15 +195,30 @@ public: protected: GrProcessor(ClassID classID) - : fClassID(classID) {} + : fClassID(classID) + , fRequiredFeatures(kNone_RequiredFeatures) {} + + /** + * If the prcoessor will generate code that uses platform specific built-in features, then it + * must call these methods from its constructor. Otherwise, requests to use these features will + * be denied. + */ + void setWillUseSampleLocations() { fRequiredFeatures |= kSampleLocations_RequiredFeature; } + + void combineRequiredFeatures(const GrProcessor& other) { + fRequiredFeatures |= other.fRequiredFeatures; + } private: GrProcessor(const GrProcessor&) = delete; GrProcessor& operator=(const GrProcessor&) = delete; - ClassID fClassID; + ClassID fClassID; + RequiredFeatures fRequiredFeatures; }; +GR_MAKE_BITFIELD_OPS(GrProcessor::RequiredFeatures); + /** A GrProcessor with the ability to access textures, buffers, and image storages. */ class GrResourceIOProcessor : public GrProcessor { public: diff --git a/src/gpu/GrProgramDesc.cpp b/src/gpu/GrProgramDesc.cpp index c3d61985de..9c0add66e6 100644 --- a/src/gpu/GrProgramDesc.cpp +++ b/src/gpu/GrProgramDesc.cpp @@ -169,6 +169,7 @@ bool GrProgramDesc::Build(GrProgramDesc* desc, desc->key().reset(); return false; } + GrProcessor::RequiredFeatures requiredFeatures = primProc.requiredFeatures(); for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) { const GrFragmentProcessor& fp = pipeline.getFragmentProcessor(i); @@ -176,6 +177,7 @@ bool GrProgramDesc::Build(GrProgramDesc* desc, desc->key().reset(); return false; } + requiredFeatures |= fp.requiredFeatures(); } const GrXferProcessor& xp = pipeline.getXferProcessor(); @@ -190,6 +192,7 @@ bool GrProgramDesc::Build(GrProgramDesc* desc, desc->key().reset(); return false; } + requiredFeatures |= xp.requiredFeatures(); // --------DO NOT MOVE HEADER ABOVE THIS LINE-------------------------------------------------- // Because header is a pointer into the dynamic array, we can't push any new data into the key @@ -201,6 +204,16 @@ bool GrProgramDesc::Build(GrProgramDesc* desc, GrRenderTargetProxy* proxy = pipeline.proxy(); + if (requiredFeatures & GrProcessor::kSampleLocations_RequiredFeature) { + SkASSERT(pipeline.isHWAntialiasState()); + + GrRenderTarget* rt = pipeline.renderTarget(); + header->fSamplePatternKey = + rt->renderTargetPriv().getMultisampleSpecs(pipeline).fUniqueID; + } else { + header->fSamplePatternKey = 0; + } + header->fOutputSwizzle = shaderCaps.configOutputSwizzle(proxy->config()).asKey(); header->fSnapVerticesToPixelCenters = pipeline.snapVerticesToPixelCenters(); diff --git a/src/gpu/GrProgramDesc.h b/src/gpu/GrProgramDesc.h index fc7a54e7ee..a20cdfc56b 100644 --- a/src/gpu/GrProgramDesc.h +++ b/src/gpu/GrProgramDesc.h @@ -81,13 +81,9 @@ public: return !(*this == other); } - void setSurfaceOriginKey(GrSurfaceOrigin origin) { - SkASSERT(kTopLeft_GrSurfaceOrigin == origin || kBottomLeft_GrSurfaceOrigin == origin); + void setSurfaceOriginKey(int key) { KeyHeader* header = this->atOffset(); - header->fSurfaceOriginKey = origin; - - GR_STATIC_ASSERT(0 == kTopLeft_GrSurfaceOrigin); - GR_STATIC_ASSERT(1 == kBottomLeft_GrSurfaceOrigin); + header->fSurfaceOriginKey = key; } static bool Less(const GrProgramDesc& a, const GrProgramDesc& b) { @@ -104,15 +100,18 @@ public: } struct KeyHeader { + // Set to uniquely identify the sample pattern, or 0 if the shader doesn't use sample + // locations. + uint8_t fSamplePatternKey; // Set to uniquely idenitify any swizzling of the shader's output color(s). - uint8_t fOutputSwizzle; - uint8_t fColorFragmentProcessorCnt; // Can be packed to 4 bits if required. - uint8_t fCoverageFragmentProcessorCnt; + uint8_t fOutputSwizzle; + uint8_t fColorFragmentProcessorCnt : 4; + uint8_t fCoverageFragmentProcessorCnt : 4; // Set to uniquely identify the rt's origin, or 0 if the shader does not require this info. - bool fSurfaceOriginKey : 1; // Can be packed to 2 bits if required. - bool fSnapVerticesToPixelCenters : 1; - bool fHasPointSize : 1; - uint8_t fPad : 5; + uint8_t fSurfaceOriginKey : 2; + uint8_t fSnapVerticesToPixelCenters : 1; + uint8_t fHasPointSize : 1; + uint8_t fPad : 4; }; GR_STATIC_ASSERT(sizeof(KeyHeader) == 4); diff --git a/src/gpu/GrRenderTarget.cpp b/src/gpu/GrRenderTarget.cpp index fa56ae74b2..3090219751 100644 --- a/src/gpu/GrRenderTarget.cpp +++ b/src/gpu/GrRenderTarget.cpp @@ -24,6 +24,7 @@ GrRenderTarget::GrRenderTarget(GrGpu* gpu, const GrSurfaceDesc& desc, : INHERITED(gpu, desc) , fSampleCnt(desc.fSampleCnt) , fStencilAttachment(stencil) + , fMultisampleSpecsID(0) , fFlags(flags) { SkASSERT(desc.fFlags & kRenderTarget_GrSurfaceFlag); SkASSERT(!(fFlags & GrRenderTargetFlags::kMixedSampled) || fSampleCnt > 0); @@ -93,3 +94,16 @@ int GrRenderTargetPriv::numStencilBits() const { return this->getStencilAttachment()->bits(); } +const GrGpu::MultisampleSpecs& +GrRenderTargetPriv::getMultisampleSpecs(const GrPipeline& pipeline) const { + SkASSERT(fRenderTarget == pipeline.renderTarget()); // TODO: remove RT from pipeline. + GrGpu* gpu = fRenderTarget->getGpu(); + if (auto id = fRenderTarget->fMultisampleSpecsID) { + SkASSERT(gpu->queryMultisampleSpecs(pipeline).fUniqueID == id); + return gpu->getMultisampleSpecs(id); + } + const GrGpu::MultisampleSpecs& specs = gpu->queryMultisampleSpecs(pipeline); + fRenderTarget->fMultisampleSpecsID = specs.fUniqueID; + return specs; +} + diff --git a/src/gpu/GrRenderTargetPriv.h b/src/gpu/GrRenderTargetPriv.h index 9822e7a09f..e2285185a8 100644 --- a/src/gpu/GrRenderTargetPriv.h +++ b/src/gpu/GrRenderTargetPriv.h @@ -32,6 +32,11 @@ public: int numStencilBits() const; + // Finds a render target's multisample specs. The pipeline is only needed in case the info isn't + // cached and we need to flush the draw state in order to query it. The pipeline is not expected + // to affect the multisample information itself. + const GrGpu::MultisampleSpecs& getMultisampleSpecs(const GrPipeline&) const; + GrRenderTargetFlags flags() const { return fRenderTarget->fFlags; } private: diff --git a/src/gpu/GrShaderCaps.cpp b/src/gpu/GrShaderCaps.cpp index 9c82c21309..a53ea9254b 100644 --- a/src/gpu/GrShaderCaps.cpp +++ b/src/gpu/GrShaderCaps.cpp @@ -43,6 +43,9 @@ GrShaderCaps::GrShaderCaps(const GrContextOptions& options) { fFlatInterpolationSupport = false; fPreferFlatInterpolation = false; fNoPerspectiveInterpolationSupport = false; + fMultisampleInterpolationSupport = false; + fSampleVariablesSupport = false; + fSampleMaskOverrideCoverageSupport = false; fExternalTextureSupport = false; fTexelFetchSupport = false; fVertexIDSupport = false; @@ -58,6 +61,8 @@ GrShaderCaps::GrShaderCaps(const GrContextOptions& options) { fExternalTextureExtensionString = nullptr; fTexelBufferExtensionString = nullptr; fNoPerspectiveInterpolationExtensionString = nullptr; + fMultisampleInterpolationExtensionString = nullptr; + fSampleVariablesExtensionString = nullptr; fFBFetchColorName = nullptr; fFBFetchExtensionString = nullptr; fImageLoadStoreExtensionString = nullptr; @@ -115,6 +120,9 @@ void GrShaderCaps::dumpJSON(SkJSONWriter* writer) const { writer->appendBool("Flat interpolation support", fFlatInterpolationSupport); writer->appendBool("Prefer flat interpolation", fPreferFlatInterpolation); writer->appendBool("No perspective interpolation support", fNoPerspectiveInterpolationSupport); + writer->appendBool("Multisample interpolation support", fMultisampleInterpolationSupport); + writer->appendBool("Sample variables support", fSampleVariablesSupport); + writer->appendBool("Sample mask override coverage support", fSampleMaskOverrideCoverageSupport); writer->appendBool("External texture support", fExternalTextureSupport); writer->appendBool("texelFetch support", fTexelFetchSupport); writer->appendBool("sk_VertexID support", fVertexIDSupport); diff --git a/src/gpu/ccpr/GrCCCoverageProcessor.cpp b/src/gpu/ccpr/GrCCCoverageProcessor.cpp index b81952ff98..032d177c3b 100644 --- a/src/gpu/ccpr/GrCCCoverageProcessor.cpp +++ b/src/gpu/ccpr/GrCCCoverageProcessor.cpp @@ -30,7 +30,7 @@ void GrCCCoverageProcessor::Shader::emitVaryings(GrGLSLVaryingHandler* varyingHa } void GrCCCoverageProcessor::Shader::emitFragmentCode(const GrCCCoverageProcessor& proc, - GrGLSLFragmentBuilder* f, + GrGLSLPPFragmentBuilder* f, const char* skOutputColor, const char* skOutputCoverage) const { f->codeAppendf("half coverage = 0;"); @@ -62,7 +62,7 @@ void GrCCCoverageProcessor::Shader::EmitEdgeDistanceEquation(GrGLSLVertexGeoBuil s->codeAppendf("%s = float3(-n, dot(n, %s) - .5);", outputDistanceEquation, leftPt); } -int GrCCCoverageProcessor::Shader::DefineSoftSampleLocations(GrGLSLFragmentBuilder* f, +int GrCCCoverageProcessor::Shader::DefineSoftSampleLocations(GrGLSLPPFragmentBuilder* f, const char* samplesName) { // Standard DX11 sample locations. #if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_IOS) diff --git a/src/gpu/ccpr/GrCCCoverageProcessor.h b/src/gpu/ccpr/GrCCCoverageProcessor.h index d3183e8fc7..eeb2ace60d 100644 --- a/src/gpu/ccpr/GrCCCoverageProcessor.h +++ b/src/gpu/ccpr/GrCCCoverageProcessor.h @@ -15,7 +15,7 @@ #include "glsl/GrGLSLGeometryProcessor.h" #include "glsl/GrGLSLVarying.h" -class GrGLSLFragmentBuilder; +class GrGLSLPPFragmentBuilder; class GrGLSLVertexGeoBuilder; class GrMesh; @@ -165,7 +165,7 @@ public: void emitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code, const char* position, const char* coverage, const char* wind); - void emitFragmentCode(const GrCCCoverageProcessor& proc, GrGLSLFragmentBuilder*, + void emitFragmentCode(const GrCCCoverageProcessor& proc, GrGLSLPPFragmentBuilder*, const char* skOutputColor, const char* skOutputCoverage) const; // Defines an equation ("dot(float3(pt, 1), distance_equation)") that is -1 on the outside @@ -197,7 +197,7 @@ public: // Emits the fragment code that calculates a pixel's coverage value. If using // WindHandling::kHandled, this value must be signed appropriately. - virtual void onEmitFragmentCode(GrGLSLFragmentBuilder*, + virtual void onEmitFragmentCode(GrGLSLPPFragmentBuilder*, const char* outputCoverage) const = 0; // Returns the name of a Shader's internal varying at the point where where its value is @@ -212,7 +212,7 @@ public: // center. Subclasses can use this for software multisampling. // // Returns the number of samples. - static int DefineSoftSampleLocations(GrGLSLFragmentBuilder* f, const char* samplesName); + static int DefineSoftSampleLocations(GrGLSLPPFragmentBuilder* f, const char* samplesName); private: GrGLSLVarying fWind; diff --git a/src/gpu/ccpr/GrCCCubicShader.cpp b/src/gpu/ccpr/GrCCCubicShader.cpp index f952ef06a2..295de0ca6c 100644 --- a/src/gpu/ccpr/GrCCCubicShader.cpp +++ b/src/gpu/ccpr/GrCCCubicShader.cpp @@ -101,7 +101,7 @@ void GrCCCubicHullShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler, OutName(fGradMatrix), fKLMMatrix.c_str(), fKLMMatrix.c_str()); } -void GrCCCubicHullShader::onEmitFragmentCode(GrGLSLFragmentBuilder* f, +void GrCCCubicHullShader::onEmitFragmentCode(GrGLSLPPFragmentBuilder* f, const char* outputCoverage) const { f->codeAppendf("float k = %s.x, l = %s.y, m = %s.z, d = %s.w;", fKLMD.fsIn(), fKLMD.fsIn(), fKLMD.fsIn(), fKLMD.fsIn()); @@ -132,7 +132,7 @@ void GrCCCubicCornerShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler, fKLMMatrix.c_str(), fEdgeDistanceEquation.c_str()); } -void GrCCCubicCornerShader::onEmitFragmentCode(GrGLSLFragmentBuilder* f, +void GrCCCubicCornerShader::onEmitFragmentCode(GrGLSLPPFragmentBuilder* f, const char* outputCoverage) const { f->codeAppendf("float2x4 grad_klmd = float2x4(%s, %s);", fdKLMDdx.fsIn(), fdKLMDdy.fsIn()); diff --git a/src/gpu/ccpr/GrCCCubicShader.h b/src/gpu/ccpr/GrCCCubicShader.h index 836781a2b2..a9875b6a4c 100644 --- a/src/gpu/ccpr/GrCCCubicShader.h +++ b/src/gpu/ccpr/GrCCCubicShader.h @@ -41,7 +41,7 @@ protected: class GrCCCubicHullShader : public GrCCCubicShader { void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code) override; - void onEmitFragmentCode(GrGLSLFragmentBuilder*, const char* outputCoverage) const override; + void onEmitFragmentCode(GrGLSLPPFragmentBuilder*, const char* outputCoverage) const override; GrGLSLVarying fGradMatrix; }; @@ -50,7 +50,7 @@ class GrCCCubicCornerShader : public GrCCCubicShader { void onEmitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts, const char* repetitionID, GeometryVars*) const override; void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code) override; - void onEmitFragmentCode(GrGLSLFragmentBuilder*, const char* outputCoverage) const override; + void onEmitFragmentCode(GrGLSLPPFragmentBuilder*, const char* outputCoverage) const override; GrGLSLVarying fdKLMDdx; GrGLSLVarying fdKLMDdy; diff --git a/src/gpu/ccpr/GrCCPathProcessor.cpp b/src/gpu/ccpr/GrCCPathProcessor.cpp index 62aa36ec2f..f93a0bd631 100644 --- a/src/gpu/ccpr/GrCCPathProcessor.cpp +++ b/src/gpu/ccpr/GrCCPathProcessor.cpp @@ -217,7 +217,7 @@ void GLSLPathProcessor::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { args.fFPCoordTransformHandler); // Fragment shader. - GrGLSLFragmentBuilder* f = args.fFragBuilder; + GrGLSLPPFragmentBuilder* f = args.fFragBuilder; f->codeAppend ("half coverage_count = "); f->appendTextureLookup(args.fTexSamplers[0], texcoord.fsIn(), kFloat2_GrSLType); diff --git a/src/gpu/ccpr/GrCCQuadraticShader.cpp b/src/gpu/ccpr/GrCCQuadraticShader.cpp index 3b6a62de0f..d08026ad19 100644 --- a/src/gpu/ccpr/GrCCQuadraticShader.cpp +++ b/src/gpu/ccpr/GrCCQuadraticShader.cpp @@ -79,7 +79,7 @@ void GrCCQuadraticHullShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandle OutName(fGrad), OutName(fXYD), fCanonicalMatrix.c_str()); } -void GrCCQuadraticHullShader::onEmitFragmentCode(GrGLSLFragmentBuilder* f, +void GrCCQuadraticHullShader::onEmitFragmentCode(GrGLSLPPFragmentBuilder* f, const char* outputCoverage) const { f->codeAppendf("float d = (%s.x * %s.x - %s.y) * inversesqrt(dot(%s, %s));", fXYD.fsIn(), fXYD.fsIn(), fXYD.fsIn(), fGrad.fsIn(), fGrad.fsIn()); @@ -109,7 +109,7 @@ void GrCCQuadraticCornerShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHand fEdgeDistanceEquation.c_str()); } -void GrCCQuadraticCornerShader::onEmitFragmentCode(GrGLSLFragmentBuilder* f, +void GrCCQuadraticCornerShader::onEmitFragmentCode(GrGLSLPPFragmentBuilder* f, const char* outputCoverage) const { f->codeAppendf("float x = %s.x, y = %s.y, d = %s.z;", fXYD.fsIn(), fXYD.fsIn(), fXYD.fsIn()); diff --git a/src/gpu/ccpr/GrCCQuadraticShader.h b/src/gpu/ccpr/GrCCQuadraticShader.h index 91c2fa1832..09fe01c1b4 100644 --- a/src/gpu/ccpr/GrCCQuadraticShader.h +++ b/src/gpu/ccpr/GrCCQuadraticShader.h @@ -48,7 +48,7 @@ class GrCCQuadraticHullShader : public GrCCQuadraticShader { void onEmitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts, const char* repetitionID, GeometryVars*) const override; void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code) override; - void onEmitFragmentCode(GrGLSLFragmentBuilder*, const char* outputCoverage) const override; + void onEmitFragmentCode(GrGLSLPPFragmentBuilder*, const char* outputCoverage) const override; GrGLSLVarying fGrad; }; @@ -60,7 +60,7 @@ class GrCCQuadraticCornerShader : public GrCCQuadraticShader { void onEmitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts, const char* repetitionID, GeometryVars*) const override; void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code) override; - void onEmitFragmentCode(GrGLSLFragmentBuilder*, const char* outputCoverage) const override; + void onEmitFragmentCode(GrGLSLPPFragmentBuilder*, const char* outputCoverage) const override; GrGLSLVarying fdXYDdx; GrGLSLVarying fdXYDdy; diff --git a/src/gpu/ccpr/GrCCTriangleShader.cpp b/src/gpu/ccpr/GrCCTriangleShader.cpp index 5aa74135d1..b507b3747c 100644 --- a/src/gpu/ccpr/GrCCTriangleShader.cpp +++ b/src/gpu/ccpr/GrCCTriangleShader.cpp @@ -27,7 +27,7 @@ Shader::WindHandling GrCCTriangleShader::onEmitVaryings(GrGLSLVaryingHandler* va return WindHandling::kHandled; } -void GrCCTriangleShader::onEmitFragmentCode(GrGLSLFragmentBuilder* f, +void GrCCTriangleShader::onEmitFragmentCode(GrGLSLPPFragmentBuilder* f, const char* outputCoverage) const { f->codeAppendf("%s = %s;", outputCoverage, fCoverageTimesWind.fsIn()); } @@ -109,7 +109,7 @@ GrCCTriangleCornerShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler, return WindHandling::kNotHandled; } -void GrCCTriangleCornerShader::onEmitFragmentCode(GrGLSLFragmentBuilder* f, +void GrCCTriangleCornerShader::onEmitFragmentCode(GrGLSLPPFragmentBuilder* f, const char* outputCoverage) const { // By the time we reach this shader, the pixel is in the following state: // diff --git a/src/gpu/ccpr/GrCCTriangleShader.h b/src/gpu/ccpr/GrCCTriangleShader.h index d86f860ffd..d40c2361f3 100644 --- a/src/gpu/ccpr/GrCCTriangleShader.h +++ b/src/gpu/ccpr/GrCCTriangleShader.h @@ -20,7 +20,7 @@ class GrCCTriangleShader : public GrCCCoverageProcessor::Shader { WindHandling onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code, const char* position, const char* coverage, const char* wind) override; - void onEmitFragmentCode(GrGLSLFragmentBuilder*, const char* outputCoverage) const override; + void onEmitFragmentCode(GrGLSLPPFragmentBuilder*, const char* outputCoverage) const override; GrGLSLVarying fCoverageTimesWind; }; @@ -36,7 +36,7 @@ class GrCCTriangleCornerShader : public GrCCCoverageProcessor::Shader { WindHandling onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code, const char* position, const char* coverage, const char* wind) override; - void onEmitFragmentCode(GrGLSLFragmentBuilder* f, const char* outputCoverage) const override; + void onEmitFragmentCode(GrGLSLPPFragmentBuilder* f, const char* outputCoverage) const override; GrShaderVar fAABoxMatrices{"aa_box_matrices", kFloat2x2_GrSLType, 2}; GrShaderVar fAABoxTranslates{"aa_box_translates", kFloat2_GrSLType, 2}; diff --git a/src/gpu/ddl/GrDDLGpu.h b/src/gpu/ddl/GrDDLGpu.h index 36c4f046ef..16deab0353 100644 --- a/src/gpu/ddl/GrDDLGpu.h +++ b/src/gpu/ddl/GrDDLGpu.h @@ -43,6 +43,12 @@ public: return true; } + void onQueryMultisampleSpecs(GrRenderTarget* rt, GrSurfaceOrigin, const GrStencilSettings&, + int* effectiveSampleCnt, SamplePattern*) override { + SkASSERT(0); + *effectiveSampleCnt = 0; // ?? + } + GrGpuRTCommandBuffer* createCommandBuffer( GrRenderTarget*, GrSurfaceOrigin, const GrGpuRTCommandBuffer::LoadAndStoreInfo&, diff --git a/src/gpu/effects/GrBezierEffect.cpp b/src/gpu/effects/GrBezierEffect.cpp index 4cc8770206..25148cde1b 100644 --- a/src/gpu/effects/GrBezierEffect.cpp +++ b/src/gpu/effects/GrBezierEffect.cpp @@ -81,7 +81,7 @@ void GrGLConicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { varyingHandler->addVarying("ConicCoeffs", &v); vertBuilder->codeAppendf("%s = %s;", v.vsOut(), gp.inConicCoeffs()->fName); - GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; + GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; // Setup pass through color this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform); @@ -333,7 +333,7 @@ void GrGLQuadEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { varyingHandler->addVarying("HairQuadEdge", &v); vertBuilder->codeAppendf("%s = %s;", v.vsOut(), gp.inHairQuadEdge()->fName); - GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; + GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; // Setup pass through color this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform); @@ -534,7 +534,7 @@ void GrGLCubicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { // emit attributes varyingHandler->emitAttributes(gp); - GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; + GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; // Setup pass through color if (!gp.colorIgnored()) { this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform); diff --git a/src/gpu/effects/GrBitmapTextGeoProc.cpp b/src/gpu/effects/GrBitmapTextGeoProc.cpp index 3d822e0a2e..a9ebdca89f 100644 --- a/src/gpu/effects/GrBitmapTextGeoProc.cpp +++ b/src/gpu/effects/GrBitmapTextGeoProc.cpp @@ -43,7 +43,7 @@ public: append_index_uv_varyings(args, btgp.inTextureCoords()->fName, atlasSizeInvName, &uv, &texIdx, nullptr); - GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; + GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; // Setup pass through color if (btgp.hasVertexColor()) { varyingHandler->addPassThroughAttribute(btgp.inColor(), args.fOutputColor); diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.cpp b/src/gpu/effects/GrDistanceFieldGeoProc.cpp index 092750ea45..8a1a4de2d1 100644 --- a/src/gpu/effects/GrDistanceFieldGeoProc.cpp +++ b/src/gpu/effects/GrDistanceFieldGeoProc.cpp @@ -27,7 +27,7 @@ public: void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ const GrDistanceFieldA8TextGeoProc& dfTexEffect = args.fGP.cast(); - GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; + GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; @@ -309,7 +309,7 @@ public: const GrDistanceFieldPathGeoProc& dfPathEffect = args.fGP.cast(); - GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; + GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; @@ -592,7 +592,7 @@ public: "AtlasSizeInv", &atlasSizeInvName); - GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; + GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; // setup pass through color varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor); diff --git a/src/gpu/effects/GrShadowGeoProc.cpp b/src/gpu/effects/GrShadowGeoProc.cpp index 3312610492..507101d87b 100644 --- a/src/gpu/effects/GrShadowGeoProc.cpp +++ b/src/gpu/effects/GrShadowGeoProc.cpp @@ -22,7 +22,7 @@ public: GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; - GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; + GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; // emit attributes varyingHandler->emitAttributes(rsgp); diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp index 2c72d18c79..3b90676be1 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -117,6 +117,13 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, fTextureBarrierSupport = ctxInfo.hasExtension("GL_NV_texture_barrier"); } + if (kGL_GrGLStandard == standard) { + fSampleLocationsSupport = version >= GR_GL_VER(3,2) || + ctxInfo.hasExtension("GL_ARB_texture_multisample"); + } else { + fSampleLocationsSupport = version >= GR_GL_VER(3,1); + } + fImagingSupport = kGL_GrGLStandard == standard && ctxInfo.hasExtension("GL_ARB_imaging"); @@ -723,6 +730,35 @@ void GrGLCaps::initGLSL(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli } } + if (kGL_GrGLStandard == standard) { + shaderCaps->fMultisampleInterpolationSupport = + ctxInfo.glslGeneration() >= k400_GrGLSLGeneration; + } else { + if (ctxInfo.glslGeneration() >= k320es_GrGLSLGeneration) { + shaderCaps->fMultisampleInterpolationSupport = true; + } else if (ctxInfo.hasExtension("GL_OES_shader_multisample_interpolation")) { + shaderCaps->fMultisampleInterpolationSupport = true; + shaderCaps->fMultisampleInterpolationExtensionString = + "GL_OES_shader_multisample_interpolation"; + } + } + + if (kGL_GrGLStandard == standard) { + shaderCaps->fSampleVariablesSupport = ctxInfo.glslGeneration() >= k400_GrGLSLGeneration; + } else { + if (ctxInfo.glslGeneration() >= k320es_GrGLSLGeneration) { + shaderCaps->fSampleVariablesSupport = true; + } else if (ctxInfo.hasExtension("GL_OES_sample_variables")) { + shaderCaps->fSampleVariablesSupport = true; + shaderCaps->fSampleVariablesExtensionString = "GL_OES_sample_variables"; + } + } + + if (shaderCaps->fSampleVariablesSupport && + ctxInfo.hasExtension("GL_NV_sample_mask_override_coverage")) { + shaderCaps->fSampleMaskOverrideCoverageSupport = true; + } + shaderCaps->fVersionDeclString = get_glsl_version_decl_string(standard, shaderCaps->fGLSLGeneration, fIsCoreProfile); @@ -2262,6 +2298,12 @@ void GrGLCaps::applyDriverCorrectnessWorkarounds(const GrGLContextInfo& ctxInfo, shaderCaps->fFBFetchSupport = false; } + // Pre-361 NVIDIA has a bug with NV_sample_mask_override_coverage. + if (kNVIDIA_GrGLDriver == ctxInfo.driver() && + ctxInfo.driverVersion() < GR_GL_DRIVER_VER(361,00)) { + shaderCaps->fSampleMaskOverrideCoverageSupport = false; + } + // Adreno GPUs have a tendency to drop tiles when there is a divide-by-zero in a shader shaderCaps->fDropsTileOnZeroDivide = kQualcomm_GrGLVendor == ctxInfo.vendor(); diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index c666da97e1..ae31495b06 100644 --- a/src/gpu/gl/GrGLGpu.cpp +++ b/src/gpu/gl/GrGLGpu.cpp @@ -4343,6 +4343,38 @@ bool GrGLGpu::generateMipmap(GrGLTexture* texture, GrSurfaceOrigin textureOrigin return true; } +void GrGLGpu::onQueryMultisampleSpecs(GrRenderTarget* rt, GrSurfaceOrigin rtOrigin, + const GrStencilSettings& stencil, + int* effectiveSampleCnt, SamplePattern* samplePattern) { + SkASSERT(GrFSAAType::kMixedSamples != rt->fsaaType() || + rt->renderTargetPriv().getStencilAttachment() || stencil.isDisabled()); + + this->flushStencil(stencil); + this->flushHWAAState(rt, true, !stencil.isDisabled()); + this->flushRenderTarget(static_cast(rt), &SkIRect::EmptyIRect()); + + if (0 != this->caps()->maxRasterSamples()) { + GR_GL_GetIntegerv(this->glInterface(), GR_GL_EFFECTIVE_RASTER_SAMPLES, effectiveSampleCnt); + } else { + GR_GL_GetIntegerv(this->glInterface(), GR_GL_SAMPLES, effectiveSampleCnt); + } + + SkASSERT(*effectiveSampleCnt >= rt->numStencilSamples()); + + if (this->caps()->sampleLocationsSupport()) { + samplePattern->reset(*effectiveSampleCnt); + for (int i = 0; i < *effectiveSampleCnt; ++i) { + GrGLfloat pos[2]; + GL_CALL(GetMultisamplefv(GR_GL_SAMPLE_POSITION, i, pos)); + if (kTopLeft_GrSurfaceOrigin == rtOrigin) { + (*samplePattern)[i].set(pos[0], pos[1]); + } else { + (*samplePattern)[i].set(pos[0], 1 - pos[1]); + } + } + } +} + void GrGLGpu::xferBarrier(GrRenderTarget* rt, GrXferBarrierType type) { SkASSERT(type); switch (type) { diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h index 95fdc60ce6..9ac86ba123 100644 --- a/src/gpu/gl/GrGLGpu.h +++ b/src/gpu/gl/GrGLGpu.h @@ -267,6 +267,9 @@ private: GrSurface* src, GrSurfaceOrigin srcOrigin, const SkIRect& srcRect, const SkIPoint& dstPoint) override; + void onQueryMultisampleSpecs(GrRenderTarget*, GrSurfaceOrigin, const GrStencilSettings&, + int* effectiveSampleCnt, SamplePattern*) override; + // binds texture unit in GL void setTextureUnit(int unitIdx); diff --git a/src/gpu/gl/GrGLGpuProgramCache.cpp b/src/gpu/gl/GrGLGpuProgramCache.cpp index 0dde6bfa4a..b79c17feaa 100644 --- a/src/gpu/gl/GrGLGpuProgramCache.cpp +++ b/src/gpu/gl/GrGLGpuProgramCache.cpp @@ -83,7 +83,7 @@ GrGLProgram* GrGLGpu::ProgramCache::refProgram(const GrGLGpu* gpu, if (!entry) { // Didn't find an origin-independent version, check with the specific origin GrSurfaceOrigin origin = pipeline.proxy()->origin(); - desc.setSurfaceOriginKey(origin); + desc.setSurfaceOriginKey(GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(origin)); desc.finalize(); entry = fMap.find(desc); } diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp index 1597a09b1e..7ae63a262c 100644 --- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp +++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp @@ -98,7 +98,8 @@ bool GrGLProgramBuilder::compileAndAttachShaders(const char* glsl, *shaderIds->append() = shaderId; if (inputs.fFlipY) { GrProgramDesc* d = this->desc(); - d->setSurfaceOriginKey(this->pipeline().proxy()->origin()); + d->setSurfaceOriginKey(GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin( + this->pipeline().proxy()->origin())); d->finalize(); } diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp index db252e3fff..6de545b0c4 100644 --- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp +++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp @@ -17,6 +17,18 @@ const char* GrGLSLFragmentShaderBuilder::kDstColorName = "_dstColor"; +static const char* sample_offset_array_name(GrGLSLFPFragmentBuilder::Coordinates coords) { + static const char* kArrayNames[] = { + "deviceSpaceSampleOffsets", + "windowSpaceSampleOffsets" + }; + return kArrayNames[coords]; + + GR_STATIC_ASSERT(0 == GrGLSLFPFragmentBuilder::kSkiaDevice_Coordinates); + GR_STATIC_ASSERT(1 == GrGLSLFPFragmentBuilder::kGLSLWindow_Coordinates); + GR_STATIC_ASSERT(SK_ARRAY_COUNT(kArrayNames) == GrGLSLFPFragmentBuilder::kLast_Coordinates + 1); +} + static const char* specific_layout_qualifier_name(GrBlendEquation equation) { SkASSERT(GrBlendEquationIsAdvanced(equation)); @@ -58,19 +70,47 @@ static const char* specific_layout_qualifier_name(GrBlendEquation equation) { kGrBlendEquationCnt - kFirstAdvancedGrBlendEquation); } +uint8_t GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(GrSurfaceOrigin origin) { + SkASSERT(kTopLeft_GrSurfaceOrigin == origin || kBottomLeft_GrSurfaceOrigin == origin); + return origin + 1; + + GR_STATIC_ASSERT(0 == kTopLeft_GrSurfaceOrigin); + GR_STATIC_ASSERT(1 == kBottomLeft_GrSurfaceOrigin); +} + GrGLSLFragmentShaderBuilder::GrGLSLFragmentShaderBuilder(GrGLSLProgramBuilder* program) : GrGLSLFragmentBuilder(program) , fSetupFragPosition(false) , fHasCustomColorOutput(false) , fCustomColorOutputIndex(-1) , fHasSecondaryOutput(false) + , fUsedSampleOffsetArrays(0) + , fHasInitializedSampleMask(false) , fForceHighPrecision(false) { fSubstageIndices.push_back(0); #ifdef SK_DEBUG + fUsedProcessorFeatures = GrProcessor::kNone_RequiredFeatures; fHasReadDstColor = false; #endif } +bool GrGLSLFragmentShaderBuilder::enableFeature(GLSLFeature feature) { + const GrShaderCaps& shaderCaps = *fProgramBuilder->shaderCaps(); + switch (feature) { + case kMultisampleInterpolation_GLSLFeature: + if (!shaderCaps.multisampleInterpolationSupport()) { + return false; + } + if (const char* extension = shaderCaps.multisampleInterpolationExtensionString()) { + this->addFeature(1 << kMultisampleInterpolation_GLSLFeature, extension); + } + return true; + default: + SK_ABORT("Unexpected GLSLFeature requested."); + return false; + } +} + SkString GrGLSLFragmentShaderBuilder::ensureCoords2D(const GrShaderVar& coords) { if (kFloat3_GrSLType != coords.getType() && kHalf3_GrSLType != coords.getType()) { SkASSERT(kFloat2_GrSLType == coords.getType() || kHalf2_GrSLType == coords.getType()); @@ -84,6 +124,57 @@ SkString GrGLSLFragmentShaderBuilder::ensureCoords2D(const GrShaderVar& coords) return coords2D; } +void GrGLSLFragmentShaderBuilder::appendOffsetToSample(const char* sampleIdx, Coordinates coords) { + SkASSERT(fProgramBuilder->header().fSamplePatternKey); + SkDEBUGCODE(fUsedProcessorFeatures |= GrProcessor::kSampleLocations_RequiredFeature); + if (kTopLeft_GrSurfaceOrigin == this->getSurfaceOrigin()) { + // With a top left origin, device and window space are equal, so we only use device coords. + coords = kSkiaDevice_Coordinates; + } + this->codeAppendf("%s[%s]", sample_offset_array_name(coords), sampleIdx); + fUsedSampleOffsetArrays |= (1 << coords); +} + +void GrGLSLFragmentShaderBuilder::maskSampleCoverage(const char* mask, bool invert) { + const GrShaderCaps& shaderCaps = *fProgramBuilder->shaderCaps(); + if (!shaderCaps.sampleVariablesSupport()) { + SkDEBUGFAIL("Attempted to mask sample coverage without support."); + return; + } + if (const char* extension = shaderCaps.sampleVariablesExtensionString()) { + this->addFeature(1 << kSampleVariables_GLSLPrivateFeature, extension); + } + if (!fHasInitializedSampleMask) { + this->codePrependf("gl_SampleMask[0] = -1;"); + fHasInitializedSampleMask = true; + } + if (invert) { + this->codeAppendf("gl_SampleMask[0] &= ~(%s);", mask); + } else { + this->codeAppendf("gl_SampleMask[0] &= %s;", mask); + } +} + +void GrGLSLFragmentShaderBuilder::overrideSampleCoverage(const char* mask) { + const GrShaderCaps& shaderCaps = *fProgramBuilder->shaderCaps(); + if (!shaderCaps.sampleMaskOverrideCoverageSupport()) { + SkDEBUGFAIL("Attempted to override sample coverage without support."); + return; + } + SkASSERT(shaderCaps.sampleVariablesSupport()); + if (const char* extension = shaderCaps.sampleVariablesExtensionString()) { + this->addFeature(1 << kSampleVariables_GLSLPrivateFeature, extension); + } + if (this->addFeature(1 << kSampleMaskOverrideCoverage_GLSLPrivateFeature, + "GL_NV_sample_mask_override_coverage")) { + // Redeclare gl_SampleMask with layout(override_coverage) if we haven't already. + fOutputs.push_back().set(kInt_GrSLType, "gl_SampleMask", 1, GrShaderVar::kOut_TypeModifier, + kHigh_GrSLPrecision, "override_coverage"); + } + this->codeAppendf("gl_SampleMask[0] = %s;", mask); + fHasInitializedSampleMask = true; +} + const char* GrGLSLFragmentShaderBuilder::dstColor() { SkDEBUGCODE(fHasReadDstColor = true;) @@ -185,6 +276,33 @@ GrSurfaceOrigin GrGLSLFragmentShaderBuilder::getSurfaceOrigin() const { void GrGLSLFragmentShaderBuilder::onFinalize() { fProgramBuilder->varyingHandler()->getFragDecls(&this->inputs(), &this->outputs()); + if (fUsedSampleOffsetArrays & (1 << kSkiaDevice_Coordinates)) { + this->defineSampleOffsetArray(sample_offset_array_name(kSkiaDevice_Coordinates), + SkMatrix::MakeTrans(-0.5f, -0.5f)); + } + if (fUsedSampleOffsetArrays & (1 << kGLSLWindow_Coordinates)) { + // With a top left origin, device and window space are equal, so we only use device coords. + SkASSERT(kBottomLeft_GrSurfaceOrigin == this->getSurfaceOrigin()); + SkMatrix m; + m.setScale(1, -1); + m.preTranslate(-0.5f, -0.5f); + this->defineSampleOffsetArray(sample_offset_array_name(kGLSLWindow_Coordinates), m); + } +} + +void GrGLSLFragmentShaderBuilder::defineSampleOffsetArray(const char* name, const SkMatrix& m) { + SkASSERT(fProgramBuilder->caps()->sampleLocationsSupport()); + const GrPipeline& pipeline = fProgramBuilder->pipeline(); + const GrRenderTargetPriv& rtp = pipeline.renderTarget()->renderTargetPriv(); + const GrGpu::MultisampleSpecs& specs = rtp.getMultisampleSpecs(pipeline); + SkSTArray<16, SkPoint, true> offsets; + offsets.push_back_n(specs.fEffectiveSampleCnt); + m.mapPoints(offsets.begin(), specs.fSampleLocations, specs.fEffectiveSampleCnt); + this->definitions().appendf("const float2 %s[] = float2[](", name); + for (int i = 0; i < specs.fEffectiveSampleCnt; ++i) { + this->definitions().appendf("float2(%f, %f)", offsets[i].x(), offsets[i].y()); + this->definitions().append(i + 1 != specs.fEffectiveSampleCnt ? ", " : ");\n"); + } } void GrGLSLFragmentShaderBuilder::onBeforeChildProcEmitCode() { diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h index f5ed024568..f124a449e6 100644 --- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h +++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h @@ -24,6 +24,20 @@ public: GrGLSLFragmentBuilder(GrGLSLProgramBuilder* program) : INHERITED(program) {} virtual ~GrGLSLFragmentBuilder() {} + /** + * Use of these features may require a GLSL extension to be enabled. Shaders may not compile + * if code is added that uses one of these features without calling enableFeature() + */ + enum GLSLFeature { + kMultisampleInterpolation_GLSLFeature + }; + + /** + * If the feature is supported then true is returned and any necessary #extension declarations + * are added to the shaders. If the feature is not supported then false will be returned. + */ + virtual bool enableFeature(GLSLFeature) = 0; + /** * This returns a variable name to access the 2D, perspective correct version of the coords in * the fragment shader. The passed in coordinates must either be of type kHalf2 or kHalf3. If @@ -47,6 +61,34 @@ public: /** Appease the compiler; the derived class initializes GrGLSLFragmentBuilder. */ GrGLSLFPFragmentBuilder() : GrGLSLFragmentBuilder(nullptr) {} + enum Coordinates { + kSkiaDevice_Coordinates, + kGLSLWindow_Coordinates, + + kLast_Coordinates = kGLSLWindow_Coordinates + }; + + /** + * Appends the offset from the center of the pixel to a specified sample. + * + * @param sampleIdx GLSL expression of the sample index. + * @param Coordinates Coordinate space in which to emit the offset. + * + * A processor must call setWillUseSampleLocations in its constructor before using this method. + */ + virtual void appendOffsetToSample(const char* sampleIdx, Coordinates) = 0; + + /** + * Subtracts sample coverage from the fragment. Any sample whose corresponding bit is not found + * in the mask will not be written out to the framebuffer. + * + * @param mask int that contains the sample mask. Bit N corresponds to the Nth sample. + * @param invert perform a bit-wise NOT on the provided mask before applying it? + * + * Requires GLSL support for sample variables. + */ + virtual void maskSampleCoverage(const char* mask, bool invert = false) = 0; + /** * Fragment procs with child procs should call these functions before/after calling emitCode * on a child proc. @@ -59,6 +101,29 @@ public: virtual void forceHighPrecision() = 0; }; +/* + * This class is used by primitive processors to build their fragment code. + */ +class GrGLSLPPFragmentBuilder : public GrGLSLFPFragmentBuilder { +public: + /** Appease the compiler; the derived class initializes GrGLSLFragmentBuilder. */ + GrGLSLPPFragmentBuilder() : GrGLSLFragmentBuilder(nullptr) {} + + /** + * Overrides the fragment's sample coverage. The provided mask determines which samples will now + * be written out to the framebuffer. Note that this mask can be reduced by a future call to + * maskSampleCoverage. + * + * If a primitive processor uses this method, it must guarantee that every codepath through the + * shader overrides the sample mask at some point. + * + * @param mask int that contains the new coverage mask. Bit N corresponds to the Nth sample. + * + * Requires NV_sample_mask_override_coverage. + */ + virtual void overrideSampleCoverage(const char* mask) = 0; +}; + /* * This class is used by Xfer processors to build their fragment code. */ @@ -83,14 +148,22 @@ public: /* * This class implements the various fragment builder interfaces. */ -class GrGLSLFragmentShaderBuilder : public GrGLSLFPFragmentBuilder, public GrGLSLXPFragmentBuilder { +class GrGLSLFragmentShaderBuilder : public GrGLSLPPFragmentBuilder, public GrGLSLXPFragmentBuilder { public: + /** Returns a nonzero key for a surface's origin. This should only be called if a processor will + use the fragment position and/or sample locations. */ + static uint8_t KeyForSurfaceOrigin(GrSurfaceOrigin); + GrGLSLFragmentShaderBuilder(GrGLSLProgramBuilder* program); // Shared GrGLSLFragmentBuilder interface. + bool enableFeature(GLSLFeature) override; virtual SkString ensureCoords2D(const GrShaderVar&) override; // GrGLSLFPFragmentBuilder interface. + void appendOffsetToSample(const char* sampleIdx, Coordinates) override; + void maskSampleCoverage(const char* mask, bool invert = false) override; + void overrideSampleCoverage(const char* mask) override; const SkString& getMangleString() const override { return fMangleString; } void onBeforeChildProcEmitCode() override; void onAfterChildProcEmitCode() override; @@ -112,8 +185,10 @@ private: #ifdef SK_DEBUG // As GLSLProcessors emit code, there are some conditions we need to verify. We use the below // state to track this. The reset call is called per processor emitted. + GrProcessor::RequiredFeatures usedProcessorFeatures() const { return fUsedProcessorFeatures; } bool hasReadDstColor() const { return fHasReadDstColor; } void resetVerification() { + fUsedProcessorFeatures = GrProcessor::kNone_RequiredFeatures; fHasReadDstColor = false; } #endif @@ -124,6 +199,7 @@ private: GrSurfaceOrigin getSurfaceOrigin() const; void onFinalize() override; + void defineSampleOffsetArray(const char* name, const SkMatrix&); static const char* kDstColorName; @@ -151,11 +227,14 @@ private: bool fHasCustomColorOutput; int fCustomColorOutputIndex; bool fHasSecondaryOutput; + uint8_t fUsedSampleOffsetArrays; + bool fHasInitializedSampleMask; bool fForceHighPrecision; #ifdef SK_DEBUG // some state to verify shaders and effects are consistent, this is reset between effects by // the program creator + GrProcessor::RequiredFeatures fUsedProcessorFeatures; bool fHasReadDstColor; #endif diff --git a/src/gpu/glsl/GrGLSLPrimitiveProcessor.cpp b/src/gpu/glsl/GrGLSLPrimitiveProcessor.cpp index e31f7c20a2..02fa2e7532 100644 --- a/src/gpu/glsl/GrGLSLPrimitiveProcessor.cpp +++ b/src/gpu/glsl/GrGLSLPrimitiveProcessor.cpp @@ -36,7 +36,7 @@ SkMatrix GrGLSLPrimitiveProcessor::GetTransformMatrix(const SkMatrix& localMatri return combined; } -void GrGLSLPrimitiveProcessor::setupUniformColor(GrGLSLFragmentBuilder* fragBuilder, +void GrGLSLPrimitiveProcessor::setupUniformColor(GrGLSLPPFragmentBuilder* fragBuilder, GrGLSLUniformHandler* uniformHandler, const char* outputName, UniformHandle* colorUniform) { diff --git a/src/gpu/glsl/GrGLSLPrimitiveProcessor.h b/src/gpu/glsl/GrGLSLPrimitiveProcessor.h index dc398a4728..30ca14387d 100644 --- a/src/gpu/glsl/GrGLSLPrimitiveProcessor.h +++ b/src/gpu/glsl/GrGLSLPrimitiveProcessor.h @@ -14,7 +14,7 @@ #include "glsl/GrGLSLUniformHandler.h" class GrPrimitiveProcessor; -class GrGLSLFragmentBuilder; +class GrGLSLPPFragmentBuilder; class GrGLSLGeometryBuilder; class GrGLSLGPBuilder; class GrGLSLVaryingHandler; @@ -67,7 +67,7 @@ public: struct EmitArgs { EmitArgs(GrGLSLVertexBuilder* vertBuilder, GrGLSLGeometryBuilder* geomBuilder, - GrGLSLFragmentBuilder* fragBuilder, + GrGLSLPPFragmentBuilder* fragBuilder, GrGLSLVaryingHandler* varyingHandler, GrGLSLUniformHandler* uniformHandler, const GrShaderCaps* caps, @@ -93,7 +93,7 @@ public: , fFPCoordTransformHandler(transformHandler) {} GrGLSLVertexBuilder* fVertBuilder; GrGLSLGeometryBuilder* fGeomBuilder; - GrGLSLFragmentBuilder* fFragBuilder; + GrGLSLPPFragmentBuilder* fFragBuilder; GrGLSLVaryingHandler* fVaryingHandler; GrGLSLUniformHandler* fUniformHandler; const GrShaderCaps* fShaderCaps; @@ -129,7 +129,7 @@ public: static SkMatrix GetTransformMatrix(const SkMatrix& localMatrix, const GrCoordTransform&); protected: - void setupUniformColor(GrGLSLFragmentBuilder* fragBuilder, + void setupUniformColor(GrGLSLPPFragmentBuilder* fragBuilder, GrGLSLUniformHandler* uniformHandler, const char* outputName, UniformHandle* colorUniform); diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/src/gpu/glsl/GrGLSLProgramBuilder.cpp index 914a958a22..04ebc6ad8e 100644 --- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp +++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp @@ -360,13 +360,16 @@ bool GrGLSLProgramBuilder::checkSamplerCounts() { #ifdef SK_DEBUG void GrGLSLProgramBuilder::verify(const GrPrimitiveProcessor& gp) { + SkASSERT(fFS.usedProcessorFeatures() == gp.requiredFeatures()); } void GrGLSLProgramBuilder::verify(const GrXferProcessor& xp) { + SkASSERT(fFS.usedProcessorFeatures() == xp.requiredFeatures()); SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor()); } void GrGLSLProgramBuilder::verify(const GrFragmentProcessor& fp) { + SkASSERT(fFS.usedProcessorFeatures() == fp.requiredFeatures()); } #endif diff --git a/src/gpu/glsl/GrGLSLShaderBuilder.h b/src/gpu/glsl/GrGLSLShaderBuilder.h index 8459218059..070862547d 100644 --- a/src/gpu/glsl/GrGLSLShaderBuilder.h +++ b/src/gpu/glsl/GrGLSLShaderBuilder.h @@ -173,7 +173,9 @@ protected: kTexelBuffer_GLSLPrivateFeature, kFramebufferFetch_GLSLPrivateFeature, kNoPerspectiveInterpolation_GLSLPrivateFeature, - kLastGLSLPrivateFeature = kNoPerspectiveInterpolation_GLSLPrivateFeature + kSampleVariables_GLSLPrivateFeature, + kSampleMaskOverrideCoverage_GLSLPrivateFeature, + kLastGLSLPrivateFeature = kSampleMaskOverrideCoverage_GLSLPrivateFeature }; /* diff --git a/src/gpu/mock/GrMockGpu.h b/src/gpu/mock/GrMockGpu.h index 4c3b0625b9..5185ce28f0 100644 --- a/src/gpu/mock/GrMockGpu.h +++ b/src/gpu/mock/GrMockGpu.h @@ -39,6 +39,11 @@ public: GrSurface* src, GrSurfaceOrigin srcOrigin, const SkIRect& srcRect, const SkIPoint& dstPoint) override { return true; } + void onQueryMultisampleSpecs(GrRenderTarget* rt, GrSurfaceOrigin, const GrStencilSettings&, + int* effectiveSampleCnt, SamplePattern*) override { + *effectiveSampleCnt = rt->numStencilSamples(); + } + GrGpuRTCommandBuffer* createCommandBuffer( GrRenderTarget*, GrSurfaceOrigin, const GrGpuRTCommandBuffer::LoadAndStoreInfo&, diff --git a/src/gpu/mtl/GrMtlCaps.mm b/src/gpu/mtl/GrMtlCaps.mm index 22001fd4f5..2bce74a261 100644 --- a/src/gpu/mtl/GrMtlCaps.mm +++ b/src/gpu/mtl/GrMtlCaps.mm @@ -150,6 +150,7 @@ void GrMtlCaps::initGrCaps(const id device) { fTextureBarrierSupport = false; // Need to figure out if we can do this + fSampleLocationsSupport = false; fMultisampleDisableSupport = false; if (this->isMac() || 3 == fFamilyGroup) { diff --git a/src/gpu/mtl/GrMtlGpu.h b/src/gpu/mtl/GrMtlGpu.h index 7372f8e61b..5a5289b6e1 100644 --- a/src/gpu/mtl/GrMtlGpu.h +++ b/src/gpu/mtl/GrMtlGpu.h @@ -46,6 +46,9 @@ public: const SkIRect& srcRect, const SkIPoint& dstPoint) override { return false; } + void onQueryMultisampleSpecs(GrRenderTarget*, GrSurfaceOrigin, const GrStencilSettings&, + int* effectiveSampleCnt, SamplePattern*) override {} + GrGpuRTCommandBuffer* createCommandBuffer( GrRenderTarget*, GrSurfaceOrigin, const GrGpuRTCommandBuffer::LoadAndStoreInfo&, diff --git a/src/gpu/ops/GrAAConvexPathRenderer.cpp b/src/gpu/ops/GrAAConvexPathRenderer.cpp index a5cc8aa59b..badaadd329 100644 --- a/src/gpu/ops/GrAAConvexPathRenderer.cpp +++ b/src/gpu/ops/GrAAConvexPathRenderer.cpp @@ -573,7 +573,7 @@ public: // Setup pass through color varyingHandler->addPassThroughAttribute(qe.fInColor, args.fOutputColor); - GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; + GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; // Setup position this->writeOutputPosition(vertBuilder, gpArgs, qe.fInPosition->fName); diff --git a/src/gpu/ops/GrDashOp.cpp b/src/gpu/ops/GrDashOp.cpp index 0cd087f96b..9728aa98b5 100644 --- a/src/gpu/ops/GrDashOp.cpp +++ b/src/gpu/ops/GrDashOp.cpp @@ -919,7 +919,7 @@ void GLDashingCircleEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { varyingHandler->addVarying("CircleParams", &circleParams); vertBuilder->codeAppendf("%s = %s;", circleParams.vsOut(), dce.inCircleParams()->fName); - GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; + GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; // Setup pass through color this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform); @@ -1122,7 +1122,7 @@ void GLDashingLineEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { varyingHandler->addVarying("RectParams", &inRectParams); vertBuilder->codeAppendf("%s = %s;", inRectParams.vsOut(), de.inRectParams()->fName); - GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; + GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; // Setup pass through color this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform); diff --git a/src/gpu/ops/GrMSAAPathRenderer.cpp b/src/gpu/ops/GrMSAAPathRenderer.cpp index 306feb504a..842d710269 100644 --- a/src/gpu/ops/GrMSAAPathRenderer.cpp +++ b/src/gpu/ops/GrMSAAPathRenderer.cpp @@ -153,7 +153,7 @@ public: qp.inPosition()->asShaderVar(), SkMatrix::I(), args.fFPCoordTransformHandler); - GrGLSLFragmentBuilder* fsBuilder = args.fFragBuilder; + GrGLSLPPFragmentBuilder* fsBuilder = args.fFragBuilder; fsBuilder->codeAppendf("if (%s.x * %s.x >= %s.y) discard;", uv.fsIn(), uv.fsIn(), uv.fsIn()); fsBuilder->codeAppendf("%s = half4(1.0);", args.fOutputCoverage); diff --git a/src/gpu/ops/GrOvalOpFactory.cpp b/src/gpu/ops/GrOvalOpFactory.cpp index e727047b1a..9194f673e6 100644 --- a/src/gpu/ops/GrOvalOpFactory.cpp +++ b/src/gpu/ops/GrOvalOpFactory.cpp @@ -113,7 +113,7 @@ private: GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; - GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; + GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; // emit attributes varyingHandler->emitAttributes(cgp); @@ -281,7 +281,7 @@ private: varyingHandler->addVarying("EllipseRadii", &ellipseRadii); vertBuilder->codeAppendf("%s = %s;", ellipseRadii.vsOut(), egp.fInEllipseRadii->fName); - GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; + GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; // setup pass through color varyingHandler->addPassThroughAttribute(egp.fInColor, args.fOutputColor); @@ -420,7 +420,7 @@ private: varyingHandler->addVarying("EllipseOffsets1", &offsets1); vertBuilder->codeAppendf("%s = %s;", offsets1.vsOut(), diegp.fInEllipseOffsets1->fName); - GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; + GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; varyingHandler->addPassThroughAttribute(diegp.fInColor, args.fOutputColor); // Setup position diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp index 9a93dc574f..f7e3d47dd9 100644 --- a/src/gpu/vk/GrVkGpu.cpp +++ b/src/gpu/vk/GrVkGpu.cpp @@ -1879,6 +1879,13 @@ bool GrVkGpu::onCopySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin, return false; } +void GrVkGpu::onQueryMultisampleSpecs(GrRenderTarget* rt, GrSurfaceOrigin, const GrStencilSettings&, + int* effectiveSampleCnt, SamplePattern*) { + // TODO: stub. + SkASSERT(!this->caps()->sampleLocationsSupport()); + *effectiveSampleCnt = rt->numStencilSamples(); +} + bool GrVkGpu::onGetReadPixelsInfo(GrSurface* srcSurface, GrSurfaceOrigin srcOrigin, int width, int height, size_t rowBytes, GrPixelConfig readConfig, DrawPreference* drawPreference, diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h index 59e7cd04c3..8cc98d9da1 100644 --- a/src/gpu/vk/GrVkGpu.h +++ b/src/gpu/vk/GrVkGpu.h @@ -78,6 +78,9 @@ public: GrSurface* src, GrSurfaceOrigin srcOrigin, const SkIRect& srcRect, const SkIPoint& dstPoint) override; + void onQueryMultisampleSpecs(GrRenderTarget*, GrSurfaceOrigin, const GrStencilSettings&, + int* effectiveSampleCnt, SamplePattern*) override; + void xferBarrier(GrRenderTarget*, GrXferBarrierType) override {} GrBackendTexture createTestingOnlyBackendTexture(void* pixels, int w, int h, diff --git a/src/gpu/vk/GrVkPipelineStateBuilder.cpp b/src/gpu/vk/GrVkPipelineStateBuilder.cpp index 7ba9f32441..9b9b070073 100644 --- a/src/gpu/vk/GrVkPipelineStateBuilder.cpp +++ b/src/gpu/vk/GrVkPipelineStateBuilder.cpp @@ -79,7 +79,8 @@ bool GrVkPipelineStateBuilder::createVkShaderModule(VkShaderStageFlagBits stage, this->addRTHeightUniform(SKSL_RTHEIGHT_NAME); } if (inputs.fFlipY) { - desc->setSurfaceOriginKey(this->pipeline().proxy()->origin()); + desc->setSurfaceOriginKey(GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin( + this->pipeline().proxy()->origin())); desc->finalize(); } return result; diff --git a/src/gpu/vk/GrVkPipelineStateCache.cpp b/src/gpu/vk/GrVkPipelineStateCache.cpp index 0aee9852ff..caffe05bd5 100644 --- a/src/gpu/vk/GrVkPipelineStateCache.cpp +++ b/src/gpu/vk/GrVkPipelineStateCache.cpp @@ -103,7 +103,7 @@ GrVkPipelineState* GrVkResourceProvider::PipelineStateCache::refPipelineState( if (!entry) { // Didn't find an origin-independent version, check with the specific origin GrSurfaceOrigin origin = pipeline.proxy()->origin(); - desc.setSurfaceOriginKey(origin); + desc.setSurfaceOriginKey(GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(origin)); desc.finalize(); entry = fMap.find(desc); } diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp index 54a62cc276..3388a4758d 100644 --- a/src/sksl/SkSLIRGenerator.cpp +++ b/src/sksl/SkSLIRGenerator.cpp @@ -130,6 +130,9 @@ static void fill_caps(const SKSL_CAPS_CLASS& caps, CAP(dropsTileOnZeroDivide); CAP(flatInterpolationSupport); CAP(noperspectiveInterpolationSupport); + CAP(multisampleInterpolationSupport); + CAP(sampleVariablesSupport); + CAP(sampleMaskOverrideCoverageSupport); CAP(externalTextureSupport); CAP(texelFetchSupport); CAP(imageLoadStoreSupport); diff --git a/src/sksl/SkSLUtil.h b/src/sksl/SkSLUtil.h index 6eb4bbad3e..787698f2c6 100644 --- a/src/sksl/SkSLUtil.h +++ b/src/sksl/SkSLUtil.h @@ -99,6 +99,18 @@ public: return true; } + bool multisampleInterpolationSupport() const { + return true; + } + + bool sampleVariablesSupport() const { + return true; + } + + bool sampleMaskOverrideCoverageSupport() const { + return true; + } + bool externalTextureSupport() const { return true; } diff --git a/tests/GpuSampleLocationsTest.cpp b/tests/GpuSampleLocationsTest.cpp new file mode 100644 index 0000000000..de15e03389 --- /dev/null +++ b/tests/GpuSampleLocationsTest.cpp @@ -0,0 +1,199 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkTypes.h" +#include "SkPoint.h" +#include "Test.h" +#include + +#if SK_SUPPORT_GPU + +#include "GrAppliedClip.h" +#include "GrRenderTargetContext.h" +#include "GrRenderTargetPriv.h" +#include "GrTypesPriv.h" +#include "gl/GrGLGpu.h" +#include "gl/debug/DebugGLTestContext.h" + +typedef std::vector SamplePattern; + +static const SamplePattern kTestPatterns[] = { + SamplePattern{ // Intel on mac, msaa8, offscreen. + {0.562500, 0.312500}, + {0.437500, 0.687500}, + {0.812500, 0.562500}, + {0.312500, 0.187500}, + {0.187500, 0.812500}, + {0.062500, 0.437500}, + {0.687500, 0.937500}, + {0.937500, 0.062500} + }, + + SamplePattern{ // Intel on mac, msaa8, on-screen. + {0.562500, 0.687500}, + {0.437500, 0.312500}, + {0.812500, 0.437500}, + {0.312500, 0.812500}, + {0.187500, 0.187500}, + {0.062500, 0.562500}, + {0.687500, 0.062500}, + {0.937500, 0.937500} + }, + + SamplePattern{ // NVIDIA, msaa16. + {0.062500, 0.000000}, + {0.250000, 0.125000}, + {0.187500, 0.375000}, + {0.437500, 0.312500}, + {0.500000, 0.062500}, + {0.687500, 0.187500}, + {0.750000, 0.437500}, + {0.937500, 0.250000}, + {0.000000, 0.500000}, + {0.312500, 0.625000}, + {0.125000, 0.750000}, + {0.375000, 0.875000}, + {0.562500, 0.562500}, + {0.812500, 0.687500}, + {0.625000, 0.812500}, + {0.875000, 0.937500} + }, + + SamplePattern{ // NVIDIA, mixed samples, 16:1. + {0.250000, 0.125000}, + {0.625000, 0.812500}, + {0.500000, 0.062500}, + {0.812500, 0.687500}, + {0.187500, 0.375000}, + {0.875000, 0.937500}, + {0.125000, 0.750000}, + {0.750000, 0.437500}, + {0.937500, 0.250000}, + {0.312500, 0.625000}, + {0.437500, 0.312500}, + {0.000000, 0.500000}, + {0.375000, 0.875000}, + {0.687500, 0.187500}, + {0.062500, 0.000000}, + {0.562500, 0.562500} + } +}; +constexpr int numTestPatterns = SK_ARRAY_COUNT(kTestPatterns); + +class TestSampleLocationsInterface : public SkNoncopyable { +public: + virtual void overrideSamplePattern(const SamplePattern&) = 0; + virtual ~TestSampleLocationsInterface() {} +}; + +void assert_equal(skiatest::Reporter* reporter, const SamplePattern& pattern, + const GrGpu::MultisampleSpecs& specs, bool flipY) { + GrAlwaysAssert(specs.fSampleLocations); + if ((int)pattern.size() != specs.fEffectiveSampleCnt) { + REPORT_FAILURE(reporter, "", SkString("Sample pattern has wrong number of samples.")); + return; + } + for (int i = 0; i < specs.fEffectiveSampleCnt; ++i) { + SkPoint expectedLocation = specs.fSampleLocations[i]; + if (flipY) { + expectedLocation.fY = 1 - expectedLocation.fY; + } + if (pattern[i] != expectedLocation) { + REPORT_FAILURE(reporter, "", SkString("Sample pattern has wrong sample location.")); + return; + } + } +} + +void test_sampleLocations(skiatest::Reporter* reporter, TestSampleLocationsInterface* testInterface, + GrContext* ctx) { + SkRandom rand; + sk_sp bottomUps[numTestPatterns]; + sk_sp topDowns[numTestPatterns]; + for (int i = 0; i < numTestPatterns; ++i) { + int numSamples = (int)kTestPatterns[i].size(); + GrAlwaysAssert(numSamples > 1 && SkIsPow2(numSamples)); + bottomUps[i] = ctx->makeDeferredRenderTargetContext( + SkBackingFit::kExact, 100, 100, kRGBA_8888_GrPixelConfig, nullptr, + rand.nextRangeU(1 + numSamples / 2, numSamples), GrMipMapped::kNo, + kBottomLeft_GrSurfaceOrigin); + topDowns[i] = ctx->makeDeferredRenderTargetContext( + SkBackingFit::kExact, 100, 100, kRGBA_8888_GrPixelConfig, nullptr, + rand.nextRangeU(1 + numSamples / 2, numSamples), GrMipMapped::kNo, + kTopLeft_GrSurfaceOrigin); + } + + // Ensure all sample locations get queried and/or cached properly. + for (int repeat = 0; repeat < 2; ++repeat) { + for (int i = 0; i < numTestPatterns; ++i) { + testInterface->overrideSamplePattern(kTestPatterns[i]); + for (GrRenderTargetContext* rtc : {bottomUps[i].get(), topDowns[i].get()}) { + GrPipeline dummyPipeline(rtc->asRenderTargetProxy(), + GrPipeline::ScissorState::kDisabled, + SkBlendMode::kSrcOver); + GrRenderTarget* rt = rtc->accessRenderTarget(); + assert_equal(reporter, kTestPatterns[i], + rt->renderTargetPriv().getMultisampleSpecs(dummyPipeline), + kBottomLeft_GrSurfaceOrigin == rtc->asSurfaceProxy()->origin()); + } + } + } + +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +class GLTestSampleLocationsInterface : public TestSampleLocationsInterface, public GrGLInterface { +public: + GLTestSampleLocationsInterface() : fTestContext(sk_gpu_test::CreateDebugGLTestContext()) { + fStandard = fTestContext->gl()->fStandard; + fExtensions = fTestContext->gl()->fExtensions; + fFunctions = fTestContext->gl()->fFunctions; + + fFunctions.fGetIntegerv = [&](GrGLenum pname, GrGLint* params) { + GrAlwaysAssert(GR_GL_EFFECTIVE_RASTER_SAMPLES != pname); + if (GR_GL_SAMPLES == pname) { + GrAlwaysAssert(!fSamplePattern.empty()); + *params = (int)fSamplePattern.size(); + } else { + fTestContext->gl()->fFunctions.fGetIntegerv(pname, params); + } + }; + + fFunctions.fGetMultisamplefv = [&](GrGLenum pname, GrGLuint index, GrGLfloat* val) { + GrAlwaysAssert(GR_GL_SAMPLE_POSITION == pname); + val[0] = fSamplePattern[index].fX; + val[1] = fSamplePattern[index].fY; + }; + } + + operator GrBackendContext() { + return reinterpret_cast(static_cast(this)); + } + + void overrideSamplePattern(const SamplePattern& newPattern) override { + fSamplePattern = newPattern; + } + +private: + std::unique_ptr fTestContext; + SamplePattern fSamplePattern; +}; + +DEF_GPUTEST(GLSampleLocations, reporter, /* options */) { + auto testInterface = sk_make_sp(); + sk_sp ctx(GrContext::MakeGL(testInterface)); + + // This test relies on at least 2 samples. + int supportedSample = ctx->caps()->getSampleCount(2, kRGBA_8888_GrPixelConfig); + if (supportedSample < 2) { + return; + } + test_sampleLocations(reporter, testInterface.get(), ctx.get()); +} + +#endif diff --git a/tests/GrMeshTest.cpp b/tests/GrMeshTest.cpp index 86437d5dfb..ccc9a73e8f 100644 --- a/tests/GrMeshTest.cpp +++ b/tests/GrMeshTest.cpp @@ -341,7 +341,7 @@ class GLSLMeshTestProcessor : public GrGLSLGeometryProcessor { } gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertex"); - GrGLSLFragmentBuilder* f = args.fFragBuilder; + GrGLSLPPFragmentBuilder* f = args.fFragBuilder; f->codeAppendf("%s = half4(1);", args.fOutputCoverage); } }; diff --git a/tests/GrPipelineDynamicStateTest.cpp b/tests/GrPipelineDynamicStateTest.cpp index 00da84e1a9..cd1ce1e053 100644 --- a/tests/GrPipelineDynamicStateTest.cpp +++ b/tests/GrPipelineDynamicStateTest.cpp @@ -93,7 +93,7 @@ class GLSLPipelineDynamicStateTestProcessor : public GrGLSLGeometryProcessor { v->codeAppendf("float2 vertex = %s;", mp.fVertex.fName); gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertex"); - GrGLSLFragmentBuilder* f = args.fFragBuilder; + GrGLSLPPFragmentBuilder* f = args.fFragBuilder; f->codeAppendf("%s = half4(1);", args.fOutputCoverage); } }; diff --git a/tests/PrimitiveProcessorTest.cpp b/tests/PrimitiveProcessorTest.cpp index ffe8175ba7..406d5e2104 100644 --- a/tests/PrimitiveProcessorTest.cpp +++ b/tests/PrimitiveProcessorTest.cpp @@ -73,7 +73,7 @@ private: const GP& gp = args.fGP.cast(); args.fVaryingHandler->emitAttributes(gp); this->writeOutputPosition(args.fVertBuilder, gpArgs, gp.getAttrib(0).fName); - GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; + GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; fragBuilder->codeAppendf("%s = half4(1);", args.fOutputColor); fragBuilder->codeAppendf("%s = half4(1);", args.fOutputCoverage); } -- cgit v1.2.3