aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar dvonbeck <dvonbeck@google.com>2016-07-29 09:53:56 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-07-29 09:53:56 -0700
commit4ef6dfa7089c092c67b0d5ec34e89c1e319af196 (patch)
treedea8644d31df5b148fc95469c74fe761bc018260
parent5db44aa2aa4a3a1b9ce1fe7e22c54c8d9b61f51d (diff)
GrFP can express distance vector field req., program builder declares variable for it
This update allows fragment processors to require a field of vectors to the nearest edge. This requirement propagates: - from child FPs to their parent - from parent FPs to the GrPaint - from GrPaint through the PipelineBuilder into GrPipeline - acessed from GrPipeline by GrGLSLProgramBuilder GrGLSL generates a variable for the distance vector and passes it down to the GeometryProcessor->emitCode() method. This CL's base is the CL for adding the BevelNormalSource API: https://codereview.chromium.org/2080993002 BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2114993002 Review-Url: https://codereview.chromium.org/2114993002
-rw-r--r--gyp/core.gypi1
-rw-r--r--gyp/ports.gyp2
-rw-r--r--include/gpu/GrFragmentProcessor.h9
-rw-r--r--include/gpu/GrPaint.h9
-rw-r--r--src/core/SkNormalBevelSource.cpp14
-rw-r--r--src/core/SkNormalFlatSource.cpp10
-rw-r--r--src/core/SkNormalMapSource.cpp10
-rw-r--r--src/core/SkNormalSource.h2
-rw-r--r--src/core/SkNormalSourcePriv.h57
-rw-r--r--src/gpu/GrFragmentProcessor.cpp3
-rw-r--r--src/gpu/GrPipeline.cpp3
-rw-r--r--src/gpu/GrPipeline.h6
-rw-r--r--src/gpu/GrPipelineBuilder.cpp2
-rw-r--r--src/gpu/GrPipelineBuilder.h10
-rw-r--r--src/gpu/GrPrimitiveProcessor.h4
-rw-r--r--src/gpu/glsl/GrGLSLFragmentProcessor.cpp3
-rw-r--r--src/gpu/glsl/GrGLSLFragmentProcessor.h7
-rw-r--r--src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp4
-rw-r--r--src/gpu/glsl/GrGLSLFragmentShaderBuilder.h6
-rw-r--r--src/gpu/glsl/GrGLSLPrimitiveProcessor.h4
-rw-r--r--src/gpu/glsl/GrGLSLProgramBuilder.cpp12
21 files changed, 157 insertions, 21 deletions
diff --git a/gyp/core.gypi b/gyp/core.gypi
index 6306a75df9..2c32c798eb 100644
--- a/gyp/core.gypi
+++ b/gyp/core.gypi
@@ -197,6 +197,7 @@
'<(skia_src_path)/core/SkNormalFlatSource.h',
'<(skia_src_path)/core/SkNormalSource.cpp',
'<(skia_src_path)/core/SkNormalSource.h',
+ '<(skia_src_path)/core/SkNormalSourcePriv.h',
'<(skia_src_path)/core/SkNx.h',
'<(skia_src_path)/core/SkOpts.cpp',
'<(skia_src_path)/core/SkOpts.h',
diff --git a/gyp/ports.gyp b/gyp/ports.gyp
index 8080fe0056..1950680d8b 100644
--- a/gyp/ports.gyp
+++ b/gyp/ports.gyp
@@ -16,12 +16,14 @@
'include_dirs': [
'../include/effects',
'../include/client/android',
+ '../include/gpu',
'../include/images',
'../include/ports',
'../include/private',
'../include/utils',
'../include/utils/win',
'../src/core',
+ '../src/gpu',
'../src/image',
'../src/lazy',
'../src/ports',
diff --git a/include/gpu/GrFragmentProcessor.h b/include/gpu/GrFragmentProcessor.h
index 4b56fbf728..ffbf576dbe 100644
--- a/include/gpu/GrFragmentProcessor.h
+++ b/include/gpu/GrFragmentProcessor.h
@@ -65,6 +65,7 @@ public:
GrFragmentProcessor()
: INHERITED()
+ , fUsesDistanceVectorField(false)
, fUsesLocalCoords(false)
, fNumTexturesExclChildren(0)
, fNumBuffersExclChildren(0)
@@ -110,6 +111,9 @@ public:
/** Do any of the coordtransforms for this processor require local coords? */
bool usesLocalCoords() const { return fUsesLocalCoords; }
+ /** Does this FP need a vector to the nearest edge? */
+ bool usesDistanceVectorField() const { return fUsesDistanceVectorField; }
+
/** Returns true if this and other processor conservatively draw identically. It can only return
true when the two processor are of the same subclass (i.e. they return the same object from
from getFactory()).
@@ -173,6 +177,11 @@ protected:
*/
virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const = 0;
+ /* Sub-classes should set this to true in their constructors if they need access to a distance
+ * vector field to the nearest edge
+ */
+ bool fUsesDistanceVectorField;
+
private:
void notifyRefCntIsZero() const final;
diff --git a/include/gpu/GrPaint.h b/include/gpu/GrPaint.h
index 8be1d50744..ca9ba59818 100644
--- a/include/gpu/GrPaint.h
+++ b/include/gpu/GrPaint.h
@@ -78,6 +78,11 @@ public:
bool getAllowSRGBInputs() const { return fAllowSRGBInputs; }
/**
+ * Does one of the fragment processors need a field of distance vectors to the nearest edge?
+ */
+ bool usesDistanceVectorField() const { return fUsesDistanceVectorField; }
+
+ /**
* Should rendering be gamma-correct, end-to-end. Causes sRGB render targets to behave
* as such (with linear blending), and sRGB inputs to be filtered and decoded correctly.
*/
@@ -101,6 +106,7 @@ public:
*/
void addColorFragmentProcessor(sk_sp<GrFragmentProcessor> fp) {
SkASSERT(fp);
+ fUsesDistanceVectorField |= fp->usesDistanceVectorField();
fColorFragmentProcessors.push_back(std::move(fp));
}
@@ -109,6 +115,7 @@ public:
*/
void addCoverageFragmentProcessor(sk_sp<GrFragmentProcessor> fp) {
SkASSERT(fp);
+ fUsesDistanceVectorField |= fp->usesDistanceVectorField();
fCoverageFragmentProcessors.push_back(std::move(fp));
}
@@ -142,6 +149,7 @@ public:
fAntiAlias = paint.fAntiAlias;
fDisableOutputConversionToSRGB = paint.fDisableOutputConversionToSRGB;
fAllowSRGBInputs = paint.fAllowSRGBInputs;
+ fUsesDistanceVectorField = paint.fUsesDistanceVectorField;
fColor = paint.fColor;
fColorFragmentProcessors = paint.fColorFragmentProcessors;
@@ -168,6 +176,7 @@ private:
bool fAntiAlias;
bool fDisableOutputConversionToSRGB;
bool fAllowSRGBInputs;
+ bool fUsesDistanceVectorField;
GrColor4f fColor;
};
diff --git a/src/core/SkNormalBevelSource.cpp b/src/core/SkNormalBevelSource.cpp
index feccb0cce8..a63e434c3f 100644
--- a/src/core/SkNormalBevelSource.cpp
+++ b/src/core/SkNormalBevelSource.cpp
@@ -8,6 +8,7 @@
#include "SkNormalBevelSource.h"
#include "SkNormalSource.h"
+#include "SkNormalSourcePriv.h"
#include "SkPoint3.h"
#include "SkReadBuffer.h"
#include "SkWriteBuffer.h"
@@ -25,17 +26,19 @@ public:
, fWidth(width)
, fHeight(height) {
this->initClassID<NormalBevelFP>();
+
+ fUsesDistanceVectorField = true;
}
- class GLSLNormalBevelFP : public GrGLSLFragmentProcessor {
+ class GLSLNormalBevelFP : public GLSLNormalFP {
public:
GLSLNormalBevelFP() {
fPrevWidth = SkFloatToScalar(0.0f);
fPrevHeight = SkFloatToScalar(0.0f);
}
- void emitCode(EmitArgs& args) override {
- GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
+ void onEmitCode(EmitArgs& args) override {
+ GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
const char* widthUniName = nullptr;
@@ -46,7 +49,7 @@ public:
fHeightUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
kDefault_GrSLPrecision, "Height", &heightUniName);
- fragBuilder->codeAppendf("%s = vec4(0, 0, 1, 0);", args.fOutputColor);
+ fragBuilder->codeAppendf("%s = vec4(0.0, 0.0, 1.0, 0.0);", args.fOutputColor);
}
static void GenKey(const GrProcessor& proc, const GrGLSLCaps&,
@@ -56,7 +59,8 @@ public:
}
protected:
- void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {
+ void setNormalData(const GrGLSLProgramDataManager& pdman,
+ const GrProcessor& proc) override {
const NormalBevelFP& normalBevelFP = proc.cast<NormalBevelFP>();
if (fPrevWidth != normalBevelFP.fWidth) {
diff --git a/src/core/SkNormalFlatSource.cpp b/src/core/SkNormalFlatSource.cpp
index fcb1a4f3ad..bdd65b03e9 100644
--- a/src/core/SkNormalFlatSource.cpp
+++ b/src/core/SkNormalFlatSource.cpp
@@ -8,6 +8,7 @@
#include "SkNormalFlatSource.h"
#include "SkNormalSource.h"
+#include "SkNormalSourcePriv.h"
#include "SkPoint3.h"
#include "SkReadBuffer.h"
#include "SkWriteBuffer.h"
@@ -23,12 +24,12 @@ public:
this->initClassID<NormalFlatFP>();
}
- class GLSLNormalFlatFP : public GrGLSLFragmentProcessor {
+ class GLSLNormalFlatFP : public GLSLNormalFP {
public:
GLSLNormalFlatFP() {}
- void emitCode(EmitArgs& args) override {
- GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
+ void onEmitCode(EmitArgs& args) override {
+ GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
fragBuilder->codeAppendf("%s = vec4(0, 0, 1, 0);", args.fOutputColor);
}
@@ -39,7 +40,8 @@ public:
}
protected:
- void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {}
+ void setNormalData(const GrGLSLProgramDataManager& pdman,
+ const GrProcessor& proc) override {}
};
void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
diff --git a/src/core/SkNormalMapSource.cpp b/src/core/SkNormalMapSource.cpp
index 2ecf1d310d..c2cda099ab 100644
--- a/src/core/SkNormalMapSource.cpp
+++ b/src/core/SkNormalMapSource.cpp
@@ -10,6 +10,7 @@
#include "SkLightingShader.h"
#include "SkMatrix.h"
#include "SkNormalSource.h"
+#include "SkNormalSourcePriv.h"
#include "SkPM4f.h"
#include "SkReadBuffer.h"
#include "SkWriteBuffer.h"
@@ -31,13 +32,13 @@ public:
this->initClassID<NormalMapFP>();
}
- class GLSLNormalMapFP : public GrGLSLFragmentProcessor {
+ class GLSLNormalMapFP : public GLSLNormalFP {
public:
GLSLNormalMapFP()
: fColumnMajorInvCTM22{0.0f} {}
- void emitCode(EmitArgs& args) override {
- GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
+ void onEmitCode(EmitArgs& args) override {
+ GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
// add uniform
@@ -78,7 +79,8 @@ public:
}
protected:
- void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {
+ void setNormalData(const GrGLSLProgramDataManager& pdman,
+ const GrProcessor& proc) override {
const NormalMapFP& normalMapFP = proc.cast<NormalMapFP>();
const SkMatrix& invCTM = normalMapFP.invCTM();
diff --git a/src/core/SkNormalSource.h b/src/core/SkNormalSource.h
index 8cbb3e4fae..4b09d0b411 100644
--- a/src/core/SkNormalSource.h
+++ b/src/core/SkNormalSource.h
@@ -111,7 +111,7 @@ public:
/** Returns a normal source that generates a bevel for the given shape. UNIMPLEMENTED: Will
return straight-up normals only.
- @param type the type of bevel to add
+ @param type the type of bevel to add.
@param width the width of the bevel, in source space. Must be positive.
@param height the height of the plateau, in source space. Can be positive, negative,
or zero. A negative height means the simulated bevels slope downwards.
diff --git a/src/core/SkNormalSourcePriv.h b/src/core/SkNormalSourcePriv.h
new file mode 100644
index 0000000000..ce8baf61e4
--- /dev/null
+++ b/src/core/SkNormalSourcePriv.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkNormalSourcePriv_DEFINED
+#define SkNormalSourcePriv_DEFINED
+
+#if SK_SUPPORT_GPU
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+
+/* GLSLFragmentProcessors for NormalSourceImpls must sub-class this class and override onEmitCode,
+ * and setNormalData calls, as well as all other calls FPs normally override, except for the 2
+ * defined in this superclass.
+ * This class exists to intercept emitCode calls and emit <0, 0, 1> if the FP requires a distance
+ * vector but the GP doesn't provide it. onSetData calls need to be intercepted too because
+ * uniform handlers will be invalid in subclasses where onEmitCode isn't called.
+ * We don't need to adjust the key here since the use of a given GP (through its class ID already in
+ * the key), will determine what code gets emitted here.
+ */
+class GLSLNormalFP : public GrGLSLFragmentProcessor {
+public:
+ GLSLNormalFP()
+ : fDidIntercept(false) {}
+
+ void emitCode(EmitArgs& args) final override {
+ if (args.fFp.usesDistanceVectorField() && !args.fGpImplementsDistanceVector) {
+ GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+ fragBuilder->codeAppendf("// GLSLNormalFP intercepted emitCode call, GP does not "
+ "implement required distance vector feature\n");
+ fragBuilder->codeAppendf("%s = vec4(0, 0, 1, 0);", args.fOutputColor);
+
+ fDidIntercept = true;
+ } else {
+ this->onEmitCode(args);
+ }
+ }
+
+ void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) final override {
+ if (!fDidIntercept) {
+ this->setNormalData(pdman, proc);
+ }
+ }
+
+protected:
+ virtual void onEmitCode(EmitArgs& args) = 0;
+ virtual void setNormalData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) = 0;
+
+private:
+ bool fDidIntercept;
+};
+#endif
+
+#endif
diff --git a/src/gpu/GrFragmentProcessor.cpp b/src/gpu/GrFragmentProcessor.cpp
index fdba610356..a8a4898e78 100644
--- a/src/gpu/GrFragmentProcessor.cpp
+++ b/src/gpu/GrFragmentProcessor.cpp
@@ -106,6 +106,9 @@ int GrFragmentProcessor::registerChildProcessor(sk_sp<GrFragmentProcessor> child
if (child->usesLocalCoords()) {
fUsesLocalCoords = true;
}
+ if (child->usesDistanceVectorField()) {
+ fUsesDistanceVectorField = true;
+ }
int index = fChildProcessors.count();
fChildProcessors.push_back(child.release());
diff --git a/src/gpu/GrPipeline.cpp b/src/gpu/GrPipeline.cpp
index 7767bf220d..c60a94be7e 100644
--- a/src/gpu/GrPipeline.cpp
+++ b/src/gpu/GrPipeline.cpp
@@ -48,6 +48,9 @@ GrPipeline* GrPipeline::CreateAt(void* memory, const CreateArgs& args,
if (builder.getAllowSRGBInputs()) {
pipeline->fFlags |= kAllowSRGBInputs_Flag;
}
+ if (builder.getUsesDistanceVectorField()) {
+ pipeline->fFlags |= kUsesDistanceVectorField_Flag;
+ }
if (args.fHasStencilClip) {
pipeline->fFlags |= kHasStencilClip_Flag;
}
diff --git a/src/gpu/GrPipeline.h b/src/gpu/GrPipeline.h
index 5ec572d0ae..1457dbc3f5 100644
--- a/src/gpu/GrPipeline.h
+++ b/src/gpu/GrPipeline.h
@@ -160,6 +160,9 @@ public:
bool getAllowSRGBInputs() const {
return SkToBool(fFlags & kAllowSRGBInputs_Flag);
}
+ bool usesDistanceVectorField() const {
+ return SkToBool(fFlags & kUsesDistanceVectorField_Flag);
+ }
bool hasStencilClip() const {
return SkToBool(fFlags & kHasStencilClip_Flag);
}
@@ -206,7 +209,8 @@ private:
kSnapVertices_Flag = 0x2,
kDisableOutputConversionToSRGB_Flag = 0x4,
kAllowSRGBInputs_Flag = 0x8,
- kHasStencilClip_Flag = 0x10
+ kUsesDistanceVectorField_Flag = 0x10,
+ kHasStencilClip_Flag = 0x20,
};
typedef GrPendingIOResource<GrRenderTarget, kWrite_GrIOType> RenderTarget;
diff --git a/src/gpu/GrPipelineBuilder.cpp b/src/gpu/GrPipelineBuilder.cpp
index 60cbc62cf2..864d6f1bc6 100644
--- a/src/gpu/GrPipelineBuilder.cpp
+++ b/src/gpu/GrPipelineBuilder.cpp
@@ -41,6 +41,8 @@ GrPipelineBuilder::GrPipelineBuilder(const GrPaint& paint, bool useHWAA)
paint.getDisableOutputConversionToSRGB());
this->setState(GrPipelineBuilder::kAllowSRGBInputs_Flag,
paint.getAllowSRGBInputs());
+ this->setState(GrPipelineBuilder::kUsesDistanceVectorField_Flag,
+ paint.usesDistanceVectorField());
}
//////////////////////////////////////////////////////////////////////////////s
diff --git a/src/gpu/GrPipelineBuilder.h b/src/gpu/GrPipelineBuilder.h
index dca7f36034..0c33eb344f 100644
--- a/src/gpu/GrPipelineBuilder.h
+++ b/src/gpu/GrPipelineBuilder.h
@@ -221,7 +221,13 @@ public:
*/
kAllowSRGBInputs_Flag = 0x08,
- kLast_Flag = kAllowSRGBInputs_Flag,
+ /**
+ * Signals that one or more FPs need access to the distance vector field to the nearest
+ * edge
+ */
+ kUsesDistanceVectorField_Flag = 0x10,
+
+ kLast_Flag = kUsesDistanceVectorField_Flag,
};
bool isHWAntialias() const { return SkToBool(fFlags & kHWAntialias_Flag); }
@@ -231,6 +237,8 @@ public:
return SkToBool(fFlags & kDisableOutputConversionToSRGB_Flag); }
bool getAllowSRGBInputs() const {
return SkToBool(fFlags & kAllowSRGBInputs_Flag); }
+ bool getUsesDistanceVectorField() const {
+ return SkToBool(fFlags & kUsesDistanceVectorField_Flag); }
/**
* Enable render state settings.
diff --git a/src/gpu/GrPrimitiveProcessor.h b/src/gpu/GrPrimitiveProcessor.h
index 0d5280fbd3..d27a6f31c7 100644
--- a/src/gpu/GrPrimitiveProcessor.h
+++ b/src/gpu/GrPrimitiveProcessor.h
@@ -221,6 +221,10 @@ public:
return 0.0;
}
+ /* Sub-class should override and return true if this primitive processor implements the distance
+ * vector field, a field of vectors to the nearest point in the edge of the shape. */
+ virtual bool implementsDistanceVector() const { return false; }
+
protected:
GrPrimitiveProcessor() : fVertexStride(0) {}
diff --git a/src/gpu/glsl/GrGLSLFragmentProcessor.cpp b/src/gpu/glsl/GrGLSLFragmentProcessor.cpp
index 9533d5a8cb..46945bdc6b 100644
--- a/src/gpu/glsl/GrGLSLFragmentProcessor.cpp
+++ b/src/gpu/glsl/GrGLSLFragmentProcessor.cpp
@@ -107,7 +107,8 @@ void GrGLSLFragmentProcessor::internalEmitChild(int childIndex, const char* inpu
inputColor,
childCoords,
childTexSamplers,
- childBufferSamplers);
+ childBufferSamplers,
+ args.fGpImplementsDistanceVector);
this->childProcessor(childIndex)->emitCode(childArgs);
fragBuilder->codeAppend("}\n");
diff --git a/src/gpu/glsl/GrGLSLFragmentProcessor.h b/src/gpu/glsl/GrGLSLFragmentProcessor.h
index 43614f2279..c6eb016a32 100644
--- a/src/gpu/glsl/GrGLSLFragmentProcessor.h
+++ b/src/gpu/glsl/GrGLSLFragmentProcessor.h
@@ -61,7 +61,8 @@ public:
const char* inputColor,
const GrGLSLTransformedCoordsArray& coords,
const SamplerHandle* texSamplers,
- const SamplerHandle* bufferSamplers)
+ const SamplerHandle* bufferSamplers,
+ bool gpImplementsDistanceVector)
: fFragBuilder(fragBuilder)
, fUniformHandler(uniformHandler)
, fGLSLCaps(caps)
@@ -70,7 +71,8 @@ public:
, fInputColor(inputColor)
, fCoords(coords)
, fTexSamplers(texSamplers)
- , fBufferSamplers(bufferSamplers) {}
+ , fBufferSamplers(bufferSamplers)
+ , fGpImplementsDistanceVector(gpImplementsDistanceVector){}
GrGLSLFPFragmentBuilder* fFragBuilder;
GrGLSLUniformHandler* fUniformHandler;
const GrGLSLCaps* fGLSLCaps;
@@ -80,6 +82,7 @@ public:
const GrGLSLTransformedCoordsArray& fCoords;
const SamplerHandle* fTexSamplers;
const SamplerHandle* fBufferSamplers;
+ bool fGpImplementsDistanceVector;
};
virtual void emitCode(EmitArgs&) = 0;
diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
index 5d1ba511b7..e6ecf8c171 100644
--- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
@@ -189,6 +189,10 @@ const char* GrGLSLFragmentShaderBuilder::fragmentPosition() {
}
}
+const char* GrGLSLFragmentShaderBuilder::distanceVectorName() const {
+ return "fsDistanceVector";
+}
+
void GrGLSLFragmentShaderBuilder::appendOffsetToSample(const char* sampleIdx, Coordinates coords) {
SkASSERT(fProgramBuilder->header().fSamplePatternKey);
SkDEBUGCODE(fUsedProcessorFeatures |= GrProcessor::kSampleLocations_RequiredFeature);
diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
index 614b04f54b..6845376261 100644
--- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
+++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
@@ -96,6 +96,10 @@ public:
*/
virtual void maskSampleCoverage(const char* mask, bool invert = false) = 0;
+ /** Returns a variable name that represents a vector to the nearest edge of the shape, in source
+ space coordinates. */
+ virtual const char* distanceVectorName() const = 0;
+
/**
* Fragment procs with child procs should call these functions before/after calling emitCode
* on a child proc.
@@ -166,6 +170,7 @@ public:
virtual SkString ensureFSCoords2D(const GrGLSLTransformedCoordsArray& coords,
int index) override;
const char* fragmentPosition() override;
+ const char* distanceVectorName() const override;
// GrGLSLFPFragmentBuilder interface.
void appendOffsetToSample(const char* sampleIdx, Coordinates) override;
@@ -235,6 +240,7 @@ private:
bool fHasSecondaryOutput;
uint8_t fUsedSampleOffsetArrays;
bool fHasInitializedSampleMask;
+ SkString fDistanceVectorOutput;
#ifdef SK_DEBUG
// some state to verify shaders and effects are consistent, this is reset between effects by
diff --git a/src/gpu/glsl/GrGLSLPrimitiveProcessor.h b/src/gpu/glsl/GrGLSLPrimitiveProcessor.h
index d726027686..a94099656b 100644
--- a/src/gpu/glsl/GrGLSLPrimitiveProcessor.h
+++ b/src/gpu/glsl/GrGLSLPrimitiveProcessor.h
@@ -42,6 +42,7 @@ public:
const GrPrimitiveProcessor& gp,
const char* outputColor,
const char* outputCoverage,
+ const char* distanceVectorName,
const SamplerHandle* texSamplers,
const SamplerHandle* bufferSamplers,
const TransformsIn& transformsIn,
@@ -54,6 +55,7 @@ public:
, fGP(gp)
, fOutputColor(outputColor)
, fOutputCoverage(outputCoverage)
+ , fDistanceVectorName(distanceVectorName)
, fTexSamplers(texSamplers)
, fBufferSamplers(bufferSamplers)
, fTransformsIn(transformsIn)
@@ -66,6 +68,7 @@ public:
const GrPrimitiveProcessor& fGP;
const char* fOutputColor;
const char* fOutputCoverage;
+ const char* fDistanceVectorName;
const SamplerHandle* fTexSamplers;
const SamplerHandle* fBufferSamplers;
const TransformsIn& fTransformsIn;
@@ -78,7 +81,6 @@ public:
*/
virtual void emitCode(EmitArgs&) = 0;
-
/** A GrGLSLPrimitiveProcessor instance can be reused with any GrGLSLPrimitiveProcessor that
produces the same stage key; this function reads data from a GrGLSLPrimitiveProcessor and
uploads any uniform variables required by the shaders created in emitCode(). The
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
index 64bc0640b9..1f28f19bb9 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
@@ -87,6 +87,13 @@ void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& pr
this->nameExpression(outputColor, "outputColor");
this->nameExpression(outputCoverage, "outputCoverage");
+ const char* distanceVectorName = nullptr;
+ if (this->fPipeline.usesDistanceVectorField() && proc.implementsDistanceVector()) {
+ distanceVectorName = fFS.distanceVectorName();
+ fFS.codeAppend( "// Un-normalized vector to the closed geometric edge (in source space)\n");
+ fFS.codeAppendf("vec2 %s;", distanceVectorName);
+ }
+
// Enclose custom code in a block to avoid namespace conflicts
SkString openBrace;
openBrace.printf("{ // Stage %d, %s\n", fStageIndex, proc.name());
@@ -108,6 +115,7 @@ void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& pr
proc,
outputColor->c_str(),
outputCoverage->c_str(),
+ distanceVectorName,
texSamplers.begin(),
bufferSamplers.begin(),
fCoordTransforms,
@@ -161,7 +169,9 @@ void GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp,
input.isOnes() ? nullptr : input.c_str(),
fOutCoords[index],
texSamplers.begin(),
- bufferSamplers.begin());
+ bufferSamplers.begin(),
+ this->primitiveProcessor().implementsDistanceVector());
+
fragProc->emitCode(args);
// We have to check that effects and the code they emit are consistent, ie if an effect