Add "sample locations" feature to GrProcessor
Adds a "sample locations" feature to GrProcessor. When enabled, this
allows a processor to know inside the shader where all the samples are
located. Also adds various infastructure to query, cache, and identify
multisample data.
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1717393002
Review URL: https://codereview.chromium.org/1717393002
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 4e0464a..c593f31 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -47,6 +47,7 @@
GrGpu::GrGpu(GrContext* context)
: fResetTimestamp(kExpiredTimestamp+1)
, fResetBits(kAll_GrBackendState)
+ , fMultisampleSpecsAllocator(1)
, fContext(context) {
}
@@ -444,6 +445,61 @@
this->onResolveRenderTarget(target);
}
+inline static uint8_t multisample_specs_id(uint8_t numSamples, GrSurfaceOrigin origin,
+ const GrCaps& caps) {
+ if (!caps.sampleLocationsSupport()) {
+ return numSamples;
+ }
+
+ SkASSERT(numSamples < 128);
+ SkASSERT(kTopLeft_GrSurfaceOrigin == origin || kBottomLeft_GrSurfaceOrigin == origin);
+ return (numSamples << 1) | (origin - 1);
+
+ GR_STATIC_ASSERT(1 == kTopLeft_GrSurfaceOrigin);
+ GR_STATIC_ASSERT(2 == kBottomLeft_GrSurfaceOrigin);
+}
+
+const GrGpu::MultisampleSpecs& GrGpu::getMultisampleSpecs(GrRenderTarget* rt,
+ const GrStencilSettings& stencil) {
+ const GrSurfaceDesc& desc = rt->desc();
+ uint8_t surfDescKey = multisample_specs_id(desc.fSampleCnt, desc.fOrigin, *this->caps());
+ if (fMultisampleSpecsMap.count() > surfDescKey && fMultisampleSpecsMap[surfDescKey]) {
+#if !defined(SK_DEBUG)
+ // In debug mode we query the multisample info every time and verify the caching is correct.
+ return *fMultisampleSpecsMap[surfDescKey];
+#endif
+ }
+ int effectiveSampleCnt;
+ SkAutoTDeleteArray<SkPoint> locations(nullptr);
+ this->onGetMultisampleSpecs(rt, stencil, &effectiveSampleCnt, &locations);
+ SkASSERT(effectiveSampleCnt && effectiveSampleCnt >= desc.fSampleCnt);
+ uint8_t effectiveKey = multisample_specs_id(effectiveSampleCnt, desc.fOrigin, *this->caps());
+ if (fMultisampleSpecsMap.count() > effectiveKey && fMultisampleSpecsMap[effectiveKey]) {
+ const MultisampleSpecs& specs = *fMultisampleSpecsMap[effectiveKey];
+ SkASSERT(effectiveKey == specs.fUniqueID);
+ SkASSERT(effectiveSampleCnt == specs.fEffectiveSampleCnt);
+ SkASSERT(!this->caps()->sampleLocationsSupport() ||
+ !memcmp(locations.get(), specs.fSampleLocations.get(),
+ effectiveSampleCnt * sizeof(SkPoint)));
+ SkASSERT(surfDescKey <= effectiveKey);
+ SkASSERT(!fMultisampleSpecsMap[surfDescKey] || fMultisampleSpecsMap[surfDescKey] == &specs);
+ fMultisampleSpecsMap[surfDescKey] = &specs;
+ return specs;
+ }
+ const MultisampleSpecs& specs = *new (&fMultisampleSpecsAllocator)
+ MultisampleSpecs{effectiveKey, effectiveSampleCnt, locations.detach()};
+ if (fMultisampleSpecsMap.count() <= effectiveKey) {
+ int n = 1 + effectiveKey - fMultisampleSpecsMap.count();
+ fMultisampleSpecsMap.push_back_n(n, (const MultisampleSpecs*) nullptr);
+ }
+ fMultisampleSpecsMap[effectiveKey] = &specs;
+ if (effectiveSampleCnt != desc.fSampleCnt) {
+ SkASSERT(surfDescKey < effectiveKey);
+ fMultisampleSpecsMap[surfDescKey] = &specs;
+ }
+ return specs;
+}
+
////////////////////////////////////////////////////////////////////////////////
void GrGpu::draw(const DrawArgs& args, const GrVertices& vertices) {
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 5d35fcf..ebe4116 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -12,6 +12,7 @@
#include "GrProgramDesc.h"
#include "GrStencil.h"
#include "GrSwizzle.h"
+#include "GrAllocator.h"
#include "GrTextureParamsAdjuster.h"
#include "GrTypes.h"
#include "GrXferProcessor.h"
@@ -365,6 +366,22 @@
const SkIRect& srcRect,
const SkIPoint& dstPoint);
+ struct MultisampleSpecs {
+ // 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, contains the subpixel locations at which the GPU will
+ // sample. Pixel center is at (.5, .5) and (0, 0) indicates the top left corner.
+ SkAutoTDeleteArray<const SkPoint> fSampleLocations;
+ };
+
+ // Finds a render target's multisample specs. The stencil settings are only needed to flush the
+ // draw state prior to querying multisample information; they should not have any effect on the
+ // multisample information itself.
+ const MultisampleSpecs& getMultisampleSpecs(GrRenderTarget*, const GrStencilSettings&);
+
struct DrawArgs {
DrawArgs(const GrPrimitiveProcessor* primProc,
const GrPipeline* pipeline,
@@ -601,6 +618,12 @@
const SkIRect& srcRect,
const SkIPoint& dstPoint) = 0;
+ // overridden by backend specific derived class to perform the multisample queries
+ virtual void onGetMultisampleSpecs(GrRenderTarget*,
+ const GrStencilSettings&,
+ int* effectiveSampleCnt,
+ SkAutoTDeleteArray<SkPoint>* sampleLocations) = 0;
+
void resetContext() {
this->onResetContext(fResetBits);
fResetBits = 0;
@@ -609,6 +632,8 @@
ResetTimestamp fResetTimestamp;
uint32_t fResetBits;
+ SkTArray<const MultisampleSpecs*, true> fMultisampleSpecsMap;
+ GrTAllocator<MultisampleSpecs> fMultisampleSpecsAllocator;
// The context owns us, not vice-versa, so this ptr is not ref'ed by Gpu.
GrContext* fContext;
diff --git a/src/gpu/GrProgramDesc.h b/src/gpu/GrProgramDesc.h
index 63e060e..ec6447d 100644
--- a/src/gpu/GrProgramDesc.h
+++ b/src/gpu/GrProgramDesc.h
@@ -70,9 +70,11 @@
}
struct KeyHeader {
- // Set by GrGLShaderBuilder if there are effects that read the fragment position. Otherwise,
- // 0.
- uint8_t fFragPosKey;
+ // Set to uniquely identify the rt's origin, or 0 if the shader does not require this info.
+ uint8_t fSurfaceOriginKey;
+ // 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 fSnapVerticesToPixelCenters;
diff --git a/src/gpu/GrRenderTarget.cpp b/src/gpu/GrRenderTarget.cpp
index e547021..41c7f10 100644
--- a/src/gpu/GrRenderTarget.cpp
+++ b/src/gpu/GrRenderTarget.cpp
@@ -105,3 +105,8 @@
}
return true;
}
+
+const GrGpu::MultisampleSpecs&
+GrRenderTargetPriv::getMultisampleSpecs(const GrStencilSettings& stencil) const {
+ return fRenderTarget->getGpu()->getMultisampleSpecs(fRenderTarget, stencil);
+}
diff --git a/src/gpu/GrRenderTargetPriv.h b/src/gpu/GrRenderTargetPriv.h
index f4931db..c6c8933 100644
--- a/src/gpu/GrRenderTargetPriv.h
+++ b/src/gpu/GrRenderTargetPriv.h
@@ -9,6 +9,9 @@
#define GrRenderTargetPriv_DEFINED
#include "GrRenderTarget.h"
+#include "GrGpu.h"
+
+class GrStencilSettings;
/** Class that adds methods to GrRenderTarget that are only intended for use internal to Skia.
This class is purely a privileged window into GrRenderTarget. It should never have additional
@@ -27,6 +30,8 @@
*/
bool attachStencilAttachment(GrStencilAttachment* stencil);
+ const GrGpu::MultisampleSpecs& getMultisampleSpecs(const GrStencilSettings& stencil) const;
+
private:
explicit GrRenderTargetPriv(GrRenderTarget* renderTarget) : fRenderTarget(renderTarget) {}
GrRenderTargetPriv(const GrRenderTargetPriv&) {} // unimpl
diff --git a/src/gpu/GrTest.cpp b/src/gpu/GrTest.cpp
index 6f2b4bf..f25455a 100644
--- a/src/gpu/GrTest.cpp
+++ b/src/gpu/GrTest.cpp
@@ -316,6 +316,13 @@
const SkIRect& srcRect,
const SkIPoint& dstPoint) override { return false; };
+ void onGetMultisampleSpecs(GrRenderTarget* rt,
+ const GrStencilSettings&,
+ int* effectiveSampleCnt,
+ SkAutoTDeleteArray<SkPoint>*) override {
+ *effectiveSampleCnt = rt->desc().fSampleCnt;
+ }
+
bool initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc) const override {
return false;
}
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index dc50c14..95f34a9 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -4141,6 +4141,39 @@
return true;
}
+void GrGLGpu::onGetMultisampleSpecs(GrRenderTarget* rt,
+ const GrStencilSettings& stencil,
+ int* effectiveSampleCnt,
+ SkAutoTDeleteArray<SkPoint>* sampleLocations) {
+ SkASSERT(!rt->hasMixedSamples() || 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->desc().fSampleCnt);
+
+ if (this->caps()->sampleLocationsSupport()) {
+ sampleLocations->reset(new SkPoint[*effectiveSampleCnt]);
+ for (int i = 0; i < *effectiveSampleCnt; ++i) {
+ GrGLfloat pos[2];
+ GL_CALL(GetMultisamplefv(GR_GL_SAMPLE_POSITION, i, pos));
+ if (kTopLeft_GrSurfaceOrigin == rt->origin()) {
+ (*sampleLocations)[i].set(pos[0], pos[1]);
+ } else {
+ (*sampleLocations)[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 56ffcb3..1ad519a 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -223,6 +223,11 @@
const SkIRect& srcRect,
const SkIPoint& dstPoint) override;
+ void onGetMultisampleSpecs(GrRenderTarget*,
+ const GrStencilSettings&,
+ int* effectiveSampleCnt,
+ SkAutoTDeleteArray<SkPoint>* sampleLocations) override;
+
// binds texture unit in GL
void setTextureUnit(int unitIdx);
diff --git a/src/gpu/gl/GrGLProgramDesc.cpp b/src/gpu/gl/GrGLProgramDesc.cpp
index 789eb62..68020a9 100644
--- a/src/gpu/gl/GrGLProgramDesc.cpp
+++ b/src/gpu/gl/GrGLProgramDesc.cpp
@@ -8,6 +8,7 @@
#include "GrProcessor.h"
#include "GrPipeline.h"
+#include "GrRenderTargetPriv.h"
#include "SkChecksum.h"
#include "gl/GrGLDefines.h"
#include "gl/GrGLTexture.h"
@@ -147,15 +148,24 @@
// make sure any padding in the header is zeroed.
memset(header, 0, kHeaderSize);
- if (requiredFeatures & GrProcessor::kFragmentPosition_RequiredFeature) {
- header->fFragPosKey =
- GrGLSLFragmentShaderBuilder::KeyForFragmentPosition(pipeline.getRenderTarget());
+ GrRenderTarget* rt = pipeline.getRenderTarget();
+
+ if (requiredFeatures & (GrProcessor::kFragmentPosition_RequiredFeature |
+ GrProcessor::kSampleLocations_RequiredFeature)) {
+ header->fSurfaceOriginKey = GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(rt->origin());
} else {
- header->fFragPosKey = 0;
+ header->fSurfaceOriginKey = 0;
}
- header->fOutputSwizzle =
- glslCaps.configOutputSwizzle(pipeline.getRenderTarget()->config()).asKey();
+ if (requiredFeatures & GrProcessor::kSampleLocations_RequiredFeature) {
+ SkASSERT(pipeline.isHWAntialiasState());
+ header->fSamplePatternKey =
+ rt->renderTargetPriv().getMultisampleSpecs(pipeline.getStencil()).fUniqueID;
+ } else {
+ header->fSamplePatternKey = 0;
+ }
+
+ header->fOutputSwizzle = glslCaps.configOutputSwizzle(rt->config()).asKey();
if (pipeline.ignoresCoverage()) {
header->fIgnoresCoverage = 1;
diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
index e6717a9..166e474 100644
--- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
@@ -7,6 +7,7 @@
#include "GrGLSLFragmentShaderBuilder.h"
#include "GrRenderTarget.h"
+#include "GrRenderTargetPriv.h"
#include "gl/GrGLGpu.h"
#include "glsl/GrGLSL.h"
#include "glsl/GrGLSLCaps.h"
@@ -16,6 +17,18 @@
const char* GrGLSLFragmentShaderBuilder::kDstTextureColorName = "_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));
@@ -57,23 +70,21 @@
kGrBlendEquationCnt - kFirstAdvancedGrBlendEquation);
}
-GrGLSLFragmentShaderBuilder::FragPosKey
-GrGLSLFragmentShaderBuilder::KeyForFragmentPosition(const GrRenderTarget* dst) {
- if (kTopLeft_GrSurfaceOrigin == dst->origin()) {
- return kTopLeftFragPosRead_FragPosKey;
- } else {
- return kBottomLeftFragPosRead_FragPosKey;
- }
+uint8_t GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(GrSurfaceOrigin origin) {
+ SkASSERT(kTopLeft_GrSurfaceOrigin == origin || kBottomLeft_GrSurfaceOrigin == origin);
+ return origin;
+
+ GR_STATIC_ASSERT(1 == kTopLeft_GrSurfaceOrigin);
+ GR_STATIC_ASSERT(2 == kBottomLeft_GrSurfaceOrigin);
}
-GrGLSLFragmentShaderBuilder::GrGLSLFragmentShaderBuilder(GrGLSLProgramBuilder* program,
- uint8_t fragPosKey)
+GrGLSLFragmentShaderBuilder::GrGLSLFragmentShaderBuilder(GrGLSLProgramBuilder* program)
: GrGLSLFragmentBuilder(program)
, fSetupFragPosition(false)
- , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == fragPosKey)
, fHasCustomColorOutput(false)
, fCustomColorOutputIndex(-1)
, fHasSecondaryOutput(false)
+ , fUsedSampleOffsetArrays(0)
, fHasInitializedSampleMask(false) {
fSubstageIndices.push_back(0);
#ifdef SK_DEBUG
@@ -82,10 +93,6 @@
#endif
}
-bool GrGLSLFragmentShaderBuilder::hasFragmentPosition() const {
- return 0 != fProgramBuilder->header().fFragPosKey;
-}
-
bool GrGLSLFragmentShaderBuilder::enableFeature(GLSLFeature feature) {
const GrGLSLCaps& glslCaps = *fProgramBuilder->glslCaps();
switch (feature) {
@@ -135,14 +142,13 @@
}
const char* GrGLSLFragmentShaderBuilder::fragmentPosition() {
- SkASSERT(this->hasFragmentPosition());
SkDEBUGCODE(fUsedProcessorFeatures |= GrProcessor::kFragmentPosition_RequiredFeature;)
const GrGLSLCaps* glslCaps = fProgramBuilder->glslCaps();
// We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
// to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
// declaration varies in earlier GLSL specs. So it is simpler to omit it.
- if (fTopLeftFragPosRead) {
+ if (kTopLeft_GrSurfaceOrigin == this->getSurfaceOrigin()) {
fSetupFragPosition = true;
return "gl_FragCoord";
} else if (const char* extension = glslCaps->fragCoordConventionsExtensionString()) {
@@ -183,6 +189,17 @@
}
}
+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 GrGLSLCaps& glslCaps = *fProgramBuilder->glslCaps();
if (!glslCaps.sampleVariablesSupport()) {
@@ -314,11 +331,50 @@
: "gl_SecondaryFragColorEXT";
}
+GrSurfaceOrigin GrGLSLFragmentShaderBuilder::getSurfaceOrigin() const {
+ SkASSERT(fProgramBuilder->header().fSurfaceOriginKey);
+ return static_cast<GrSurfaceOrigin>(fProgramBuilder->header().fSurfaceOriginKey);
+
+ GR_STATIC_ASSERT(1 == kTopLeft_GrSurfaceOrigin);
+ GR_STATIC_ASSERT(2 == kBottomLeft_GrSurfaceOrigin);
+}
+
void GrGLSLFragmentShaderBuilder::onFinalize() {
fProgramBuilder->varyingHandler()->getFragDecls(&this->inputs(), &this->outputs());
GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision,
*fProgramBuilder->glslCaps(),
&this->precisionQualifier());
+ 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.getRenderTarget()->renderTargetPriv();
+ const GrGpu::MultisampleSpecs& specs = rtp.getMultisampleSpecs(pipeline.getStencil());
+ SkSTArray<16, SkPoint, true> offsets;
+ offsets.push_back_n(specs.fEffectiveSampleCnt);
+ m.mapPoints(offsets.begin(), specs.fSampleLocations.get(), specs.fEffectiveSampleCnt);
+ this->definitions().append("const ");
+ if (fProgramBuilder->glslCaps()->usesPrecisionModifiers()) {
+ this->definitions().append("highp ");
+ }
+ this->definitions().appendf("vec2 %s[] = vec2[](", name);
+ for (int i = 0; i < specs.fEffectiveSampleCnt; ++i) {
+ this->definitions().appendf("vec2(%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 57b8ee9..614b04f 100644
--- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
+++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
@@ -68,6 +68,23 @@
/** 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.
@@ -138,14 +155,11 @@
*/
class GrGLSLFragmentShaderBuilder : public GrGLSLPPFragmentBuilder, public GrGLSLXPFragmentBuilder {
public:
- typedef uint8_t FragPosKey;
+ /** 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);
- /** Returns a key for reading the fragment location. This should only be called if there is an
- effect that will requires the fragment position. If the fragment position is not required,
- the key is 0. */
- static FragPosKey KeyForFragmentPosition(const GrRenderTarget* dst);
-
- GrGLSLFragmentShaderBuilder(GrGLSLProgramBuilder* program, uint8_t fragPosKey);
+ GrGLSLFragmentShaderBuilder(GrGLSLProgramBuilder* program);
// Shared GrGLSLFragmentBuilder interface.
bool enableFeature(GLSLFeature) override;
@@ -154,6 +168,7 @@
const char* fragmentPosition() 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; }
@@ -167,8 +182,6 @@
void enableAdvancedBlendEquationIfNeeded(GrBlendEquation) override;
private:
- bool hasFragmentPosition() const;
-
// Private public interface, used by GrGLProgramBuilder to build a fragment shader
void enableCustomOutput();
void enableSecondaryOutput();
@@ -189,19 +202,10 @@
static const char* DeclaredColorOutputName() { return "fsColorOut"; }
static const char* DeclaredSecondaryColorOutputName() { return "fsSecondaryColorOut"; }
- /*
- * An internal call for GrGLProgramBuilder to use to add varyings to the vertex shader
- */
- void addVarying(GrGLSLVarying*, GrSLPrecision);
+ GrSurfaceOrigin getSurfaceOrigin() const;
void onFinalize() override;
-
- // Interpretation of FragPosKey when generating code
- enum {
- kNoFragPosRead_FragPosKey = 0, // The fragment positition will not be needed.
- kTopLeftFragPosRead_FragPosKey = 0x1,// Read frag pos relative to top-left.
- kBottomLeftFragPosRead_FragPosKey = 0x2,// Read frag pos relative to bottom-left.
- };
+ void defineSampleOffsetArray(const char* name, const SkMatrix&);
static const char* kDstTextureColorName;
@@ -225,12 +229,12 @@
*/
SkString fMangleString;
- bool fSetupFragPosition;
- bool fTopLeftFragPosRead;
- bool fHasCustomColorOutput;
- int fCustomColorOutputIndex;
- bool fHasSecondaryOutput;
- bool fHasInitializedSampleMask;
+ bool fSetupFragPosition;
+ bool fHasCustomColorOutput;
+ int fCustomColorOutputIndex;
+ bool fHasSecondaryOutput;
+ uint8_t fUsedSampleOffsetArrays;
+ bool fHasInitializedSampleMask;
#ifdef SK_DEBUG
// some state to verify shaders and effects are consistent, this is reset between effects by
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
index 417e924..b9eaca4 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
@@ -18,7 +18,7 @@
GrGLSLProgramBuilder::GrGLSLProgramBuilder(const DrawArgs& args)
: fVS(this)
, fGS(this)
- , fFS(this, args.fDesc->header().fFragPosKey)
+ , fFS(this)
, fStageIndex(-1)
, fArgs(args)
, fGeometryProcessor(nullptr)
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index a0e6aa5..1ce78fd 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -1211,6 +1211,13 @@
return false;
}
+void GrVkGpu::onGetMultisampleSpecs(GrRenderTarget* rt, const GrStencilSettings&,
+ int* effectiveSampleCnt, SkAutoTDeleteArray<SkPoint>*) {
+ // TODO: stub.
+ SkASSERT(!this->caps()->sampleLocationsSupport());
+ *effectiveSampleCnt = rt->desc().fSampleCnt;
+}
+
bool GrVkGpu::onGetReadPixelsInfo(GrSurface* srcSurface, int width, int height, size_t rowBytes,
GrPixelConfig readConfig, DrawPreference* drawPreference,
ReadPixelTempDrawInfo* tempDrawInfo) {
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index 344f81c..723d714 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -76,6 +76,11 @@
const SkIRect& srcRect,
const SkIPoint& dstPoint) override;
+ void onGetMultisampleSpecs(GrRenderTarget* rt,
+ const GrStencilSettings&,
+ int* effectiveSampleCnt,
+ SkAutoTDeleteArray<SkPoint>*);
+
bool initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc) const override {
SkDebugf("initCopySurfaceDstDesc not yet implemented for Vulkan\n");
return false;
diff --git a/src/gpu/vk/GrVkProgramDesc.cpp b/src/gpu/vk/GrVkProgramDesc.cpp
index 32357cd..74e6bbb 100644
--- a/src/gpu/vk/GrVkProgramDesc.cpp
+++ b/src/gpu/vk/GrVkProgramDesc.cpp
@@ -9,6 +9,7 @@
//#include "GrVkProcessor.h"
#include "GrProcessor.h"
#include "GrPipeline.h"
+#include "GrRenderTargetPriv.h"
#include "GrVkGpu.h"
#include "GrVkUtil.h"
#include "SkChecksum.h"
@@ -134,15 +135,24 @@
// make sure any padding in the header is zeroed.
memset(header, 0, kHeaderSize);
- if (requiredFeatures & GrProcessor::kFragmentPosition_RequiredFeature) {
- header->fFragPosKey =
- GrGLSLFragmentShaderBuilder::KeyForFragmentPosition(pipeline.getRenderTarget());
+ GrRenderTarget* rt = pipeline.getRenderTarget();
+
+ if (requiredFeatures & (GrProcessor::kFragmentPosition_RequiredFeature |
+ GrProcessor::kSampleLocations_RequiredFeature)) {
+ header->fSurfaceOriginKey = GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(rt->origin());
} else {
- header->fFragPosKey = 0;
+ header->fSurfaceOriginKey = 0;
}
- header->fOutputSwizzle =
- glslCaps.configOutputSwizzle(pipeline.getRenderTarget()->config()).asKey();
+ if (requiredFeatures & GrProcessor::kSampleLocations_RequiredFeature) {
+ SkASSERT(pipeline.isHWAntialiasState());
+ header->fSamplePatternKey =
+ rt->renderTargetPriv().getMultisampleSpecs(pipeline.getStencil()).fUniqueID;
+ } else {
+ header->fSamplePatternKey = 0;
+ }
+
+ header->fOutputSwizzle = glslCaps.configOutputSwizzle(rt->config()).asKey();
if (pipeline.ignoresCoverage()) {
header->fIgnoresCoverage = 1;