aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gn/tests.gni1
-rw-r--r--include/gpu/GrCaps.h2
-rw-r--r--include/gpu/GrRenderTarget.h1
-rw-r--r--include/gpu/GrShaderCaps.h21
-rw-r--r--src/gpu/GrCaps.cpp2
-rw-r--r--src/gpu/GrDefaultGeoProcFactory.cpp2
-rw-r--r--src/gpu/GrFragmentProcessor.cpp2
-rw-r--r--src/gpu/GrGpu.cpp43
-rw-r--r--src/gpu/GrGpu.h36
-rw-r--r--src/gpu/GrPathProcessor.cpp2
-rw-r--r--src/gpu/GrProcessor.h31
-rw-r--r--src/gpu/GrProgramDesc.cpp13
-rw-r--r--src/gpu/GrProgramDesc.h25
-rw-r--r--src/gpu/GrRenderTarget.cpp14
-rw-r--r--src/gpu/GrRenderTargetPriv.h5
-rw-r--r--src/gpu/GrShaderCaps.cpp8
-rw-r--r--src/gpu/ccpr/GrCCCoverageProcessor.cpp4
-rw-r--r--src/gpu/ccpr/GrCCCoverageProcessor.h8
-rw-r--r--src/gpu/ccpr/GrCCCubicShader.cpp4
-rw-r--r--src/gpu/ccpr/GrCCCubicShader.h4
-rw-r--r--src/gpu/ccpr/GrCCPathProcessor.cpp2
-rw-r--r--src/gpu/ccpr/GrCCQuadraticShader.cpp4
-rw-r--r--src/gpu/ccpr/GrCCQuadraticShader.h4
-rw-r--r--src/gpu/ccpr/GrCCTriangleShader.cpp4
-rw-r--r--src/gpu/ccpr/GrCCTriangleShader.h4
-rw-r--r--src/gpu/ddl/GrDDLGpu.h6
-rw-r--r--src/gpu/effects/GrBezierEffect.cpp6
-rw-r--r--src/gpu/effects/GrBitmapTextGeoProc.cpp2
-rw-r--r--src/gpu/effects/GrDistanceFieldGeoProc.cpp6
-rw-r--r--src/gpu/effects/GrShadowGeoProc.cpp2
-rw-r--r--src/gpu/gl/GrGLCaps.cpp42
-rw-r--r--src/gpu/gl/GrGLGpu.cpp32
-rw-r--r--src/gpu/gl/GrGLGpu.h3
-rw-r--r--src/gpu/gl/GrGLGpuProgramCache.cpp2
-rw-r--r--src/gpu/gl/builders/GrGLProgramBuilder.cpp3
-rw-r--r--src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp118
-rw-r--r--src/gpu/glsl/GrGLSLFragmentShaderBuilder.h81
-rw-r--r--src/gpu/glsl/GrGLSLPrimitiveProcessor.cpp2
-rw-r--r--src/gpu/glsl/GrGLSLPrimitiveProcessor.h8
-rw-r--r--src/gpu/glsl/GrGLSLProgramBuilder.cpp3
-rw-r--r--src/gpu/glsl/GrGLSLShaderBuilder.h4
-rw-r--r--src/gpu/mock/GrMockGpu.h5
-rw-r--r--src/gpu/mtl/GrMtlCaps.mm1
-rw-r--r--src/gpu/mtl/GrMtlGpu.h3
-rw-r--r--src/gpu/ops/GrAAConvexPathRenderer.cpp2
-rw-r--r--src/gpu/ops/GrDashOp.cpp4
-rw-r--r--src/gpu/ops/GrMSAAPathRenderer.cpp2
-rw-r--r--src/gpu/ops/GrOvalOpFactory.cpp6
-rw-r--r--src/gpu/vk/GrVkGpu.cpp7
-rw-r--r--src/gpu/vk/GrVkGpu.h3
-rw-r--r--src/gpu/vk/GrVkPipelineStateBuilder.cpp3
-rw-r--r--src/gpu/vk/GrVkPipelineStateCache.cpp2
-rw-r--r--src/sksl/SkSLIRGenerator.cpp3
-rw-r--r--src/sksl/SkSLUtil.h12
-rw-r--r--tests/GpuSampleLocationsTest.cpp199
-rw-r--r--tests/GrMeshTest.cpp2
-rw-r--r--tests/GrPipelineDynamicStateTest.cpp2
-rw-r--r--tests/PrimitiveProcessorTest.cpp2
58 files changed, 759 insertions, 65 deletions
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<DefaultGeoProc>();
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<GrFragmentProcessor> 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<SamplePattern, uint8_t, SamplePatternComparator> 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<GrPathProcessor>();
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<KeyHeader, kHeaderOffset>();
- 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<GrDistanceFieldA8TextGeoProc>();
- 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<GrDistanceFieldPathGeoProc>();
- 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<GrGLRenderTarget*>(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
@@ -25,6 +25,20 @@ public:
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
* the coordinates are 3-dimensional, it a perspective divide into is emitted into the
@@ -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.
@@ -60,6 +102,29 @@ public:
};
/*
+ * 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.
*/
class GrGLSLXPFragmentBuilder : virtual public GrGLSLFragmentBuilder {
@@ -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<MTLDevice> 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 <vector>
+
+#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<SkPoint> 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<GrRenderTargetContext> bottomUps[numTestPatterns];
+ sk_sp<GrRenderTargetContext> 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<GrBackendContext>(static_cast<GrGLInterface*>(this));
+ }
+
+ void overrideSamplePattern(const SamplePattern& newPattern) override {
+ fSamplePattern = newPattern;
+ }
+
+private:
+ std::unique_ptr<sk_gpu_test::GLTestContext> fTestContext;
+ SamplePattern fSamplePattern;
+};
+
+DEF_GPUTEST(GLSampleLocations, reporter, /* options */) {
+ auto testInterface = sk_make_sp<GLTestSampleLocationsInterface>();
+ sk_sp<GrContext> 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<GP>();
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);
}