Share GP implementation between GrFillRectOp and GrTextureOp
Bug: skia:
Change-Id: I6c71dac4cf88f274a39f121f0b5315e6c5b914c8
Reviewed-on: https://skia-review.googlesource.com/c/173700
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/ops/GrFillRectOp.cpp b/src/gpu/ops/GrFillRectOp.cpp
index 4dfc834..337d476 100644
--- a/src/gpu/ops/GrFillRectOp.cpp
+++ b/src/gpu/ops/GrFillRectOp.cpp
@@ -73,69 +73,6 @@
GrQuadAAFlags fAAFlags;
};
-// A GeometryProcessor for rendering TransformedQuads using the vertex attributes from
-// GrQuadPerEdgeAA. This is similar to the TextureGeometryProcessor of GrTextureOp except that it
-// handles full GrPaints.
-class QuadPerEdgeAAGeometryProcessor : public GrGeometryProcessor {
-public:
-
- static sk_sp<GrGeometryProcessor> Make(const VertexSpec& spec) {
- return sk_sp<QuadPerEdgeAAGeometryProcessor>(new QuadPerEdgeAAGeometryProcessor(spec));
- }
-
- const char* name() const override { return "QuadPerEdgeAAGeometryProcessor"; }
-
- void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
- // The attributes' key includes the device and local quad types implicitly since those
- // types decide the vertex attribute size
- b->add32(fAttrs.getKey());
- }
-
- GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps& caps) const override {
- class GLSLProcessor : public GrGLSLGeometryProcessor {
- public:
- void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& proc,
- FPCoordTransformIter&& transformIter) override {
- const auto& gp = proc.cast<QuadPerEdgeAAGeometryProcessor>();
- if (gp.fAttrs.hasLocalCoords()) {
- this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
- }
- }
-
- private:
- void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
- const auto& gp = args.fGP.cast<QuadPerEdgeAAGeometryProcessor>();
- args.fVaryingHandler->emitAttributes(gp);
- gpArgs->fPositionVar = gp.fAttrs.emitPosition(args, "pos");
-
- if (gp.fAttrs.hasLocalCoords()) {
- this->emitTransforms(args.fVertBuilder,
- args.fVaryingHandler,
- args.fUniformHandler,
- gp.fAttrs.localCoords().asShaderVar(),
- args.fFPCoordTransformHandler);
- }
-
- gp.fAttrs.emitColor(args, "paintColor");
- gp.fAttrs.emitCoverage(args, "aaDist");
- }
- };
- return new GLSLProcessor;
- }
-
-private:
- QuadPerEdgeAAGeometryProcessor(const VertexSpec& spec)
- : INHERITED(kQuadPerEdgeAAGeometryProcessor_ClassID)
- , fAttrs(spec) {
- SkASSERT(spec.hasVertexColors());
- this->setVertexAttributes(fAttrs.attributes(), fAttrs.attributeCount());
- }
-
- GrQuadPerEdgeAA::GPAttributes fAttrs;
-
- typedef GrGeometryProcessor INHERITED;
-};
-
class FillRectOp final : public GrMeshDrawOp {
private:
using Helper = GrSimpleMeshDrawOpHelperWithStencil;
@@ -273,7 +210,7 @@
this->localQuadType(), fHelper.usesLocalCoords(), Domain::kNo,
fHelper.aaType());
- sk_sp<GrGeometryProcessor> gp = QuadPerEdgeAAGeometryProcessor::Make(vertexSpec);
+ sk_sp<GrGeometryProcessor> gp = GrQuadPerEdgeAA::MakeProcessor(vertexSpec);
size_t vertexSize = gp->vertexStride();
const GrBuffer* vbuffer;
diff --git a/src/gpu/ops/GrQuadPerEdgeAA.cpp b/src/gpu/ops/GrQuadPerEdgeAA.cpp
index 3f69d4a..2849e29 100644
--- a/src/gpu/ops/GrQuadPerEdgeAA.cpp
+++ b/src/gpu/ops/GrQuadPerEdgeAA.cpp
@@ -9,6 +9,7 @@
#include "GrQuad.h"
#include "GrVertexWriter.h"
#include "glsl/GrGLSLColorSpaceXformHelper.h"
+#include "glsl/GrGLSLGeometryProcessor.h"
#include "glsl/GrGLSLPrimitiveProcessor.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "glsl/GrGLSLVarying.h"
@@ -460,135 +461,244 @@
return fHasLocalCoords ? (this->localQuadType() == GrQuadType::kPerspective ? 3 : 2) : 0;
}
-////////////////// GPAttributes Implementation
+////////////////// Geometry Processor Implementation
-GPAttributes::GPAttributes(const VertexSpec& spec) {
- fNeedsPerspective = spec.deviceDimensionality() == 3;
- fPositions = {"position", kFloat4_GrVertexAttribType, kFloat4_GrSLType};
+class QuadPerEdgeAAGeometryProcessor : public GrGeometryProcessor {
+public:
- int localDim = spec.localDimensionality();
- if (localDim == 3) {
- fLocalCoords = {"localCoord", kFloat3_GrVertexAttribType, kFloat3_GrSLType};
- } else if (localDim == 2) {
- fLocalCoords = {"localCoord", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
- } // else localDim == 0 and attribute remains uninitialized
-
- if (ColorType::kByte == spec.colorType()) {
- fColors = {"color", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType};
- } else if (ColorType::kHalf == spec.colorType()) {
- fColors = {"color", kHalf4_GrVertexAttribType, kHalf4_GrSLType};
+ static sk_sp<GrGeometryProcessor> Make(const VertexSpec& spec) {
+ return sk_sp<QuadPerEdgeAAGeometryProcessor>(new QuadPerEdgeAAGeometryProcessor(spec));
}
- if (spec.hasDomain()) {
- fDomain = {"domain", kFloat4_GrVertexAttribType, kFloat4_GrSLType};
+ static sk_sp<GrGeometryProcessor> Make(const VertexSpec& vertexSpec, const GrShaderCaps& caps,
+ GrTextureType textureType, GrPixelConfig textureConfig,
+ const GrSamplerState::Filter filter,
+ sk_sp<GrColorSpaceXform> textureColorSpaceXform) {
+ return sk_sp<QuadPerEdgeAAGeometryProcessor>(new QuadPerEdgeAAGeometryProcessor(
+ vertexSpec, caps, textureType, textureConfig, filter,
+ std::move(textureColorSpaceXform)));
}
- if (spec.usesCoverageAA()) {
- fAAEdgeDistances = {"aaEdgeDist", kFloat4_GrVertexAttribType, kFloat4_GrSLType};
- }
-}
+ const char* name() const override { return "QuadPerEdgeAAGeometryProcessor"; }
-bool GPAttributes::needsPerspectiveInterpolation() const {
- // This only needs to check the position; local position having perspective does not change
- // how the varyings are interpolated
- return fNeedsPerspective;
-}
-
-uint32_t GPAttributes::getKey() const {
- // aa, domain are single bit flags
- uint32_t x = this->usesCoverageAA() ? 0 : 1;
- x |= this->hasDomain() ? 0 : 2;
- // regular position has two options as well
- x |= fNeedsPerspective ? 0 : 4;
- // local coords require 2 bits (3 choices), 00 for none, 01 for 2d, 10 for 3d
- if (this->hasLocalCoords()) {
- x |= kFloat3_GrVertexAttribType == fLocalCoords.cpuType() ? 8 : 16;
- }
- // similar for colors, 00 for none, 01 for bytes, 10 for half-floats
- if (this->hasVertexColors()) {
- x |= kUByte4_norm_GrVertexAttribType == fColors.cpuType() ? 32 : 64;
- }
- return x;
-}
-
-GrShaderVar GPAttributes::emitPosition(GrGLSLPrimitiveProcessor::EmitArgs& args,
- const char* posVarName) const {
- if (fNeedsPerspective) {
- args.fVertBuilder->codeAppendf("float3 %s = %s.xyz;", posVarName, fPositions.name());
- return {posVarName, kFloat3_GrSLType, GrShaderVar::kNone_TypeModifier};
- } else {
- args.fVertBuilder->codeAppendf("float2 %s = %s.xy;", posVarName, fPositions.name());
- return {posVarName, kFloat2_GrSLType, GrShaderVar::kNone_TypeModifier};
- }
-}
-
-void GPAttributes::emitColor(GrGLSLPrimitiveProcessor::EmitArgs& args,
- const char* colorVarName) const {
- using Interpolation = GrGLSLVaryingHandler::Interpolation;
- if (fColors.isInitialized()) {
- args.fVaryingHandler->addPassThroughAttribute(fColors, args.fOutputColor,
- Interpolation::kCanBeFlat);
- }
-}
-
-void GPAttributes::emitExplicitLocalCoords(
- GrGLSLPrimitiveProcessor::EmitArgs& args, const char* localCoordName,
- const char* domainName) const {
- using Interpolation = GrGLSLVaryingHandler::Interpolation;
- if (!this->hasLocalCoords()) {
- return;
- }
-
- args.fFragBuilder->codeAppendf("float2 %s;", localCoordName);
- bool localHasPerspective = fLocalCoords.cpuType() == kFloat3_GrVertexAttribType;
- if (localHasPerspective) {
- // Can't do a pass through since we need to perform perspective division
- GrGLSLVarying v(fLocalCoords.gpuType());
- args.fVaryingHandler->addVarying(fLocalCoords.name(), &v);
- args.fVertBuilder->codeAppendf("%s = %s;", v.vsOut(), fLocalCoords.name());
- args.fFragBuilder->codeAppendf("%s = %s.xy / %s.z;", localCoordName, v.fsIn(), v.fsIn());
- } else {
- args.fVaryingHandler->addPassThroughAttribute(fLocalCoords, localCoordName);
- }
-
- // Clamp the now 2D localCoordName variable by the domain if it is provided
- if (this->hasDomain()) {
- args.fFragBuilder->codeAppendf("float4 %s;", domainName);
- args.fVaryingHandler->addPassThroughAttribute(fDomain, domainName,
- Interpolation::kCanBeFlat);
- args.fFragBuilder->codeAppendf("%s = clamp(%s, %s.xy, %s.zw);",
- localCoordName, localCoordName, domainName, domainName);
- }
-}
-
-void GPAttributes::emitCoverage(GrGLSLPrimitiveProcessor::EmitArgs& args,
- const char* edgeDistName) const {
- if (this->usesCoverageAA()) {
- GrGLSLVarying maxCoverage(kFloat_GrSLType);
- args.fVaryingHandler->addVarying("maxCoverage", &maxCoverage);
- args.fVertBuilder->codeAppendf("%s = %s.w;", maxCoverage.vsOut(), fPositions.name());
-
- args.fFragBuilder->codeAppendf("float4 %s;", edgeDistName);
- args.fVaryingHandler->addPassThroughAttribute(fAAEdgeDistances, edgeDistName);
-
- args.fFragBuilder->codeAppendf(
- "float min%s = min(min(%s.x, %s.y), min(%s.z, %s.w));",
- edgeDistName, edgeDistName, edgeDistName, edgeDistName, edgeDistName);
- if (fNeedsPerspective) {
- // The distance from edge equation e to homogeneous point p=sk_Position is e.x*p.x/p.w +
- // e.y*p.y/p.w + e.z. However, we want screen space interpolation of this distance. We
- // can do this by multiplying the vertex attribute by p.w and then multiplying by
- // sk_FragCoord.w in the FS. So we output e.x*p.x + e.y*p.y + e.z * p.w
- args.fFragBuilder->codeAppendf("min%s *= sk_FragCoord.w;", edgeDistName);
+ void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
+ // aa, domain, texturing are single bit flags
+ uint32_t x = fAAEdgeDistances.isInitialized() ? 0 : 1;
+ x |= fDomain.isInitialized() ? 0 : 2;
+ x |= fSampler.isInitialized() ? 0 : 4;
+ // regular position has two options as well
+ x |= fNeedsPerspective ? 0 : 8;
+ // local coords require 2 bits (3 choices), 00 for none, 01 for 2d, 10 for 3d
+ if (fLocalCoord.isInitialized()) {
+ x |= kFloat3_GrVertexAttribType == fLocalCoord.cpuType() ? 16 : 32;
}
- // Clamp to max coverage after the perspective divide since perspective quads calculated
- // the max coverage in projected space.
- args.fFragBuilder->codeAppendf("%s = float4(clamp(min%s, 0.0, %s));",
- args.fOutputCoverage, edgeDistName, maxCoverage.fsIn());
- } else {
- // Set coverage to 1
- args.fFragBuilder->codeAppendf("%s = float4(1);", args.fOutputCoverage);
+ // similar for colors, 00 for none, 01 for bytes, 10 for half-floats
+ if (this->fColor.isInitialized()) {
+ x |= kUByte4_norm_GrVertexAttribType == fColor.cpuType() ? 64 : 128;
+ }
+
+ b->add32(GrColorSpaceXform::XformKey(fTextureColorSpaceXform.get()));
+ b->add32(x);
}
+
+ GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps& caps) const override {
+ class GLSLProcessor : public GrGLSLGeometryProcessor {
+ public:
+ void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& proc,
+ FPCoordTransformIter&& transformIter) override {
+ const auto& gp = proc.cast<QuadPerEdgeAAGeometryProcessor>();
+ if (gp.fLocalCoord.isInitialized()) {
+ this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
+ }
+ fTextureColorSpaceXformHelper.setData(pdman, gp.fTextureColorSpaceXform.get());
+ }
+
+ private:
+ void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
+ using Interpolation = GrGLSLVaryingHandler::Interpolation;
+
+ const auto& gp = args.fGP.cast<QuadPerEdgeAAGeometryProcessor>();
+ fTextureColorSpaceXformHelper.emitCode(args.fUniformHandler,
+ gp.fTextureColorSpaceXform.get());
+
+ args.fVaryingHandler->emitAttributes(gp);
+
+ // Extract effective position out of vec4 as a local variable in the vertex shader
+ if (gp.fNeedsPerspective) {
+ args.fVertBuilder->codeAppendf("float3 position = %s.xyz;",
+ gp.fPositionWithCoverage.name());
+ } else {
+ args.fVertBuilder->codeAppendf("float2 position = %s.xy;",
+ gp.fPositionWithCoverage.name());
+ }
+ gpArgs->fPositionVar = {"position",
+ gp.fNeedsPerspective ? kFloat3_GrSLType : kFloat2_GrSLType,
+ GrShaderVar::kNone_TypeModifier};
+
+ // Handle local coordinates if they exist
+ if (gp.fLocalCoord.isInitialized()) {
+ // NOTE: If the only usage of local coordinates is for the inline texture fetch
+ // before FPs, then there are no registered FPCoordTransforms and this ends up
+ // emitting nothing, so there isn't a duplication of local coordinates
+ this->emitTransforms(args.fVertBuilder,
+ args.fVaryingHandler,
+ args.fUniformHandler,
+ gp.fLocalCoord.asShaderVar(),
+ args.fFPCoordTransformHandler);
+ }
+
+ // Solid color before any texturing gets modulated in
+ if (gp.fColor.isInitialized()) {
+ args.fVaryingHandler->addPassThroughAttribute(gp.fColor, args.fOutputColor,
+ Interpolation::kCanBeFlat);
+ }
+
+ // If there is a texture, must also handle texture coordinates and reading from
+ // the texture in the fragment shader before continuing to fragment processors.
+ if (gp.fSampler.isInitialized()) {
+ // Texture coordinates clamped by the domain on the fragment shader; if the GP
+ // has a texture, it's guaranteed to have local coordinates
+ args.fFragBuilder->codeAppend("float2 texCoord;");
+ if (gp.fLocalCoord.cpuType() == kFloat3_GrVertexAttribType) {
+ // Can't do a pass through since we need to perform perspective division
+ GrGLSLVarying v(gp.fLocalCoord.gpuType());
+ args.fVaryingHandler->addVarying(gp.fLocalCoord.name(), &v);
+ args.fVertBuilder->codeAppendf("%s = %s;",
+ v.vsOut(), gp.fLocalCoord.name());
+ args.fFragBuilder->codeAppendf("texCoord = %s.xy / %s.z;",
+ v.fsIn(), v.fsIn());
+ } else {
+ args.fVaryingHandler->addPassThroughAttribute(gp.fLocalCoord, "texCoord");
+ }
+
+ // Clamp the now 2D localCoordName variable by the domain if it is provided
+ if (gp.fDomain.isInitialized()) {
+ args.fFragBuilder->codeAppend("float4 domain;");
+ args.fVaryingHandler->addPassThroughAttribute(gp.fDomain, "domain",
+ Interpolation::kCanBeFlat);
+ args.fFragBuilder->codeAppend(
+ "texCoord = clamp(texCoord, domain.xy, domain.zw);");
+ }
+
+ // Now modulate the starting output color by the texture lookup
+ args.fFragBuilder->codeAppendf("%s = ", args.fOutputColor);
+ args.fFragBuilder->appendTextureLookupAndModulate(
+ args.fOutputColor, args.fTexSamplers[0], "texCoord", kFloat2_GrSLType,
+ &fTextureColorSpaceXformHelper);
+ args.fFragBuilder->codeAppend(";");
+ }
+
+ // And lastly, output the coverage calculation code
+ if (gp.fAAEdgeDistances.isInitialized()) {
+ GrGLSLVarying maxCoverage(kFloat_GrSLType);
+ args.fVaryingHandler->addVarying("maxCoverage", &maxCoverage);
+ args.fVertBuilder->codeAppendf("%s = %s.w;",
+ maxCoverage.vsOut(), gp.fPositionWithCoverage.name());
+
+ args.fFragBuilder->codeAppend("float4 edgeDists;");
+ args.fVaryingHandler->addPassThroughAttribute(gp.fAAEdgeDistances, "edgeDists");
+
+ args.fFragBuilder->codeAppend(
+ "float minDist = min(min(edgeDists.x, edgeDists.y),"
+ " min(edgeDists.z, edgeDists.w));");
+ if (gp.fNeedsPerspective) {
+ // The distance from edge equation e to homogeneous point p=sk_Position is
+ // e.x*p.x/p.w + e.y*p.y/p.w + e.z. However, we want screen space
+ // interpolation of this distance. We can do this by multiplying the vertex
+ // attribute by p.w and then multiplying by sk_FragCoord.w in the FS. So we
+ // output e.x*p.x + e.y*p.y + e.z * p.w
+ args.fFragBuilder->codeAppend("minDist *= sk_FragCoord.w;");
+ }
+ // Clamp to max coverage after the perspective divide since perspective quads
+ // calculated the max coverage in projected space.
+ args.fFragBuilder->codeAppendf("%s = float4(clamp(minDist, 0.0, %s));",
+ args.fOutputCoverage, maxCoverage.fsIn());
+ } else {
+ // Set coverage to 1
+ args.fFragBuilder->codeAppendf("%s = float4(1);", args.fOutputCoverage);
+ }
+ }
+ GrGLSLColorSpaceXformHelper fTextureColorSpaceXformHelper;
+ };
+ return new GLSLProcessor;
+ }
+
+private:
+ QuadPerEdgeAAGeometryProcessor(const VertexSpec& spec)
+ : INHERITED(kQuadPerEdgeAAGeometryProcessor_ClassID)
+ , fTextureColorSpaceXform(nullptr) {
+ SkASSERT(spec.hasVertexColors() && !spec.hasDomain());
+ this->initializeAttrs(spec);
+ this->setTextureSamplerCnt(0);
+ }
+
+ QuadPerEdgeAAGeometryProcessor(const VertexSpec& spec, const GrShaderCaps& caps,
+ GrTextureType textureType, GrPixelConfig textureConfig,
+ GrSamplerState::Filter filter,
+ sk_sp<GrColorSpaceXform> textureColorSpaceXform)
+ : INHERITED(kQuadPerEdgeAAGeometryProcessor_ClassID)
+ , fTextureColorSpaceXform(std::move(textureColorSpaceXform))
+ , fSampler(textureType, textureConfig, filter) {
+ SkASSERT(spec.hasVertexColors() && spec.hasLocalCoords());
+ this->initializeAttrs(spec);
+ this->setTextureSamplerCnt(1);
+ }
+
+ void initializeAttrs(const VertexSpec& spec) {
+ fNeedsPerspective = spec.deviceDimensionality() == 3;
+ fPositionWithCoverage = {"posAndCoverage", kFloat4_GrVertexAttribType, kFloat4_GrSLType};
+
+ int localDim = spec.localDimensionality();
+ if (localDim == 3) {
+ fLocalCoord = {"localCoord", kFloat3_GrVertexAttribType, kFloat3_GrSLType};
+ } else if (localDim == 2) {
+ fLocalCoord = {"localCoord", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
+ } // else localDim == 0 and attribute remains uninitialized
+
+ if (ColorType::kByte == spec.colorType()) {
+ fColor = {"color", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType};
+ } else if (ColorType::kHalf == spec.colorType()) {
+ fColor = {"color", kHalf4_GrVertexAttribType, kHalf4_GrSLType};
+ }
+
+ if (spec.hasDomain()) {
+ fDomain = {"domain", kFloat4_GrVertexAttribType, kFloat4_GrSLType};
+ }
+
+ if (spec.usesCoverageAA()) {
+ fAAEdgeDistances = {"aaEdgeDist", kFloat4_GrVertexAttribType, kFloat4_GrSLType};
+ }
+ this->setVertexAttributes(&fPositionWithCoverage, 5);
+ }
+
+ const TextureSampler& onTextureSampler(int) const override { return fSampler; }
+
+ Attribute fPositionWithCoverage;
+ Attribute fColor;
+ Attribute fLocalCoord;
+ Attribute fDomain;
+ Attribute fAAEdgeDistances;
+
+ // The positions attribute is always a vec4 and can't be used to encode perspectiveness
+ bool fNeedsPerspective;
+
+ // Color space will be null and fSampler.isInitialized() returns false when the GP is configured
+ // to skip texturing.
+ sk_sp<GrColorSpaceXform> fTextureColorSpaceXform;
+ TextureSampler fSampler;
+
+ typedef GrGeometryProcessor INHERITED;
+};
+
+sk_sp<GrGeometryProcessor> MakeProcessor(const VertexSpec& spec) {
+ return QuadPerEdgeAAGeometryProcessor::Make(spec);
+}
+
+sk_sp<GrGeometryProcessor> MakeTexturedProcessor(const VertexSpec& spec, const GrShaderCaps& caps,
+ GrTextureType textureType, GrPixelConfig textureConfig,
+ const GrSamplerState::Filter filter, sk_sp<GrColorSpaceXform> textureColorSpaceXform) {
+ return QuadPerEdgeAAGeometryProcessor::Make(spec, caps, textureType, textureConfig, filter,
+ std::move(textureColorSpaceXform));
}
} // namespace GrQuadPerEdgeAA
diff --git a/src/gpu/ops/GrQuadPerEdgeAA.h b/src/gpu/ops/GrQuadPerEdgeAA.h
index c02be56..9d1b650 100644
--- a/src/gpu/ops/GrQuadPerEdgeAA.h
+++ b/src/gpu/ops/GrQuadPerEdgeAA.h
@@ -9,15 +9,15 @@
#define GrQuadPerEdgeAA_DEFINED
#include "GrColor.h"
-#include "GrPrimitiveProcessor.h"
+#include "GrGeometryProcessor.h"
#include "GrQuad.h"
#include "GrSamplerState.h"
#include "GrTypesPriv.h"
-#include "glsl/GrGLSLPrimitiveProcessor.h"
#include "SkPoint.h"
#include "SkPoint3.h"
-class GrGLSLColorSpaceXformHelper;
+class GrColorSpaceXform;
+class GrShaderCaps;
namespace GrQuadPerEdgeAA {
@@ -65,81 +65,11 @@
unsigned fUsesCoverageAA: 1;
};
- // Utility class that manages the attribute state necessary to render a particular batch of
- // quads. It is similar to a geometry processor but is meant to be included in a has-a
- // relationship by specialized GP's that provide further functionality on top of the per-edge AA
- // coverage.
- //
- // For performance reasons, this uses fixed names for the attribute variables; since it defines
- // the majority of attributes a GP will likely need, this shouldn't be too limiting.
- //
- // In terms of responsibilities, the actual geometry processor must still call emitTransforms(),
- // using the localCoords() attribute as the 4th argument; it must set the transform data helper
- // to use the identity matrix; it must manage the color space transform for the quad's paint
- // color; it should include getKey() in the geometry processor's key builder; and it should
- // add these attributes at construction time.
- class GPAttributes {
- public:
- using Attribute = GrPrimitiveProcessor::Attribute;
+ sk_sp<GrGeometryProcessor> MakeProcessor(const VertexSpec& spec);
- GPAttributes(const VertexSpec& vertexSpec);
-
- const Attribute& positionsAndMaxCoverage() const { return fPositions; }
- const Attribute& colors() const { return fColors; }
- const Attribute& localCoords() const { return fLocalCoords; }
- const Attribute& domain() const { return fDomain; }
- const Attribute& edgeDistances() const { return fAAEdgeDistances; }
-
- bool hasVertexColors() const { return fColors.isInitialized(); }
-
- bool usesCoverageAA() const { return fAAEdgeDistances.isInitialized(); }
-
- bool hasLocalCoords() const { return fLocalCoords.isInitialized(); }
-
- bool hasDomain() const { return fDomain.isInitialized(); }
-
- bool needsPerspectiveInterpolation() const;
-
- const Attribute* attributes() const { return &fPositions; }
- int attributeCount() const { return 5; }
-
- uint32_t getKey() const;
-
- // Functions to be called at appropriate times in a processor's onEmitCode() block. These
- // are separated into discrete pieces so that they can be interleaved with the rest of the
- // processor's shader code as needed. The functions take char* arguments for the names of
- // variables the emitted code must declare, so that the calling GP can ensure there's no
- // naming conflicts with their own code.
-
- // Returns the GrShaderVar to store in GrGPArgs
- GrShaderVar emitPosition(GrGLSLPrimitiveProcessor::EmitArgs& args,
- const char* posVarName) const;
-
- void emitColor(GrGLSLPrimitiveProcessor::EmitArgs& args, const char* colorVarName) const;
-
- // localCoordName will be declared as a float2, with any domain applied after any
- // perspective division is performed.
- //
- // Note: this should only be used if the local coordinates need to be passed separately
- // from the standard coord transform process that is used by FPs.
- // FIXME: This can go in two directions from here, if GrTextureOp stops needing per-quad
- // domains it can be removed and GrTextureOp rewritten to use coord transforms. Or
- // emitTransform() in the primitive builder can be updated to have a notion of domain for
- // local coords, and all domain-needing code (blurs, filters, etc.) can switch to that magic
- void emitExplicitLocalCoords(GrGLSLPrimitiveProcessor::EmitArgs& args,
- const char* localCoordName, const char* domainVarName) const;
-
- void emitCoverage(GrGLSLPrimitiveProcessor::EmitArgs& args, const char* edgeDistName) const;
- private:
- Attribute fPositions; // named "position" in SkSL
- Attribute fColors; // named "color" in SkSL
- Attribute fLocalCoords; // named "localCoord" in SkSL
- Attribute fDomain; // named "domain" in SkSL
- Attribute fAAEdgeDistances; // named "aaEdgeDist" in SkSL
-
- // The positions attribute is always a vec4 and can't be used to encode perspectiveness
- bool fNeedsPerspective;
- };
+ sk_sp<GrGeometryProcessor> MakeTexturedProcessor(const VertexSpec& spec,
+ const GrShaderCaps& caps, GrTextureType textureType, GrPixelConfig textureConfig,
+ const GrSamplerState::Filter filter, sk_sp<GrColorSpaceXform> textureColorSpaceXform);
// Fill vertices with the vertex data needed to represent the given quad. The device position,
// local coords, vertex color, domain, and edge coefficients will be written and/or computed
@@ -147,7 +77,6 @@
// then its corresponding function argument is ignored.
//
// Returns the advanced pointer in vertices.
- // TODO4F: Switch GrColor to GrVertexColor
void* Tessellate(void* vertices, const VertexSpec& spec, const GrPerspQuad& deviceQuad,
const SkPMColor4f& color, const GrPerspQuad& localQuad, const SkRect& domain,
GrQuadAAFlags aa);
diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp
index 1a1cf1c..96174b2 100644
--- a/src/gpu/ops/GrTextureOp.cpp
+++ b/src/gpu/ops/GrTextureOp.cpp
@@ -30,8 +30,6 @@
#include "SkPoint3.h"
#include "SkRectPriv.h"
#include "SkTo.h"
-#include "glsl/GrGLSLColorSpaceXformHelper.h"
-#include "glsl/GrGLSLGeometryProcessor.h"
#include "glsl/GrGLSLVarying.h"
namespace {
@@ -40,96 +38,6 @@
using VertexSpec = GrQuadPerEdgeAA::VertexSpec;
using ColorType = GrQuadPerEdgeAA::ColorType;
-/**
- * Geometry Processor that draws a texture modulated by a vertex color (though, this is meant to be
- * the same value across all vertices of a quad and uses flat interpolation when available). This is
- * used by TextureOp below.
- */
-class TextureGeometryProcessor : public GrGeometryProcessor {
-public:
-
- static sk_sp<GrGeometryProcessor> Make(GrTextureType textureType, GrPixelConfig textureConfig,
- const GrSamplerState::Filter filter,
- sk_sp<GrColorSpaceXform> textureColorSpaceXform,
- const VertexSpec& vertexSpec, const GrShaderCaps& caps) {
- return sk_sp<TextureGeometryProcessor>(new TextureGeometryProcessor(
- textureType, textureConfig, filter, std::move(textureColorSpaceXform), vertexSpec,
- caps));
- }
-
- const char* name() const override { return "TextureGeometryProcessor"; }
-
- void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
- b->add32(GrColorSpaceXform::XformKey(fTextureColorSpaceXform.get()));
- b->add32(fAttrs.getKey());
- }
-
- GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps& caps) const override {
- class GLSLProcessor : public GrGLSLGeometryProcessor {
- public:
- void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& proc,
- FPCoordTransformIter&& transformIter) override {
- const auto& textureGP = proc.cast<TextureGeometryProcessor>();
- this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
- fTextureColorSpaceXformHelper.setData(
- pdman, textureGP.fTextureColorSpaceXform.get());
- }
-
- private:
- void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
- const auto& textureGP = args.fGP.cast<TextureGeometryProcessor>();
- fTextureColorSpaceXformHelper.emitCode(
- args.fUniformHandler, textureGP.fTextureColorSpaceXform.get());
- if (!textureGP.fAttrs.needsPerspectiveInterpolation()) {
- args.fVaryingHandler->setNoPerspective();
- }
- args.fVaryingHandler->emitAttributes(textureGP);
- gpArgs->fPositionVar = textureGP.fAttrs.emitPosition(args, "pos");
-
- this->emitTransforms(args.fVertBuilder,
- args.fVaryingHandler,
- args.fUniformHandler,
- textureGP.fAttrs.localCoords().asShaderVar(),
- args.fFPCoordTransformHandler);
- textureGP.fAttrs.emitColor(args, "paintColor");
- textureGP.fAttrs.emitExplicitLocalCoords(args, "texCoord", "domain");
-
- args.fFragBuilder->codeAppendf("%s = ", args.fOutputColor);
- args.fFragBuilder->appendTextureLookupAndModulate(
- args.fOutputColor, args.fTexSamplers[0], "texCoord", kFloat2_GrSLType,
- &fTextureColorSpaceXformHelper);
- args.fFragBuilder->codeAppend(";");
-
- textureGP.fAttrs.emitCoverage(args, "aaDist");
- }
- GrGLSLColorSpaceXformHelper fTextureColorSpaceXformHelper;
- };
- return new GLSLProcessor;
- }
-
-private:
- TextureGeometryProcessor(GrTextureType textureType, GrPixelConfig textureConfig,
- GrSamplerState::Filter filter,
- sk_sp<GrColorSpaceXform> textureColorSpaceXform,
- const VertexSpec& vertexSpec, const GrShaderCaps& caps)
- : INHERITED(kTextureGeometryProcessor_ClassID)
- , fAttrs(vertexSpec)
- , fTextureColorSpaceXform(std::move(textureColorSpaceXform))
- , fSampler(textureType, textureConfig, filter) {
- SkASSERT(vertexSpec.hasVertexColors() && vertexSpec.localDimensionality() == 2);
- this->setTextureSamplerCnt(1);
- this->setVertexAttributes(fAttrs.attributes(), fAttrs.attributeCount());
- }
-
- const TextureSampler& onTextureSampler(int) const override { return fSampler; }
-
- GrQuadPerEdgeAA::GPAttributes fAttrs;
- sk_sp<GrColorSpaceXform> fTextureColorSpaceXform;
- TextureSampler fSampler;
-
- typedef GrGeometryProcessor INHERITED;
-};
-
static bool filter_has_effect_for_rect_stays_rect(const GrPerspQuad& quad, const SkRect& srcRect) {
SkASSERT(quad.quadType() == GrQuadType::kRect);
float ql = quad.x(0);
@@ -444,9 +352,9 @@
VertexSpec vertexSpec(quadType, wideColor ? ColorType::kHalf : ColorType::kByte,
GrQuadType::kRect, /* hasLocal */ true, domain, aaType);
- sk_sp<GrGeometryProcessor> gp = TextureGeometryProcessor::Make(
- textureType, config, this->filter(), std::move(fTextureColorSpaceXform),
- vertexSpec, *target->caps().shaderCaps());
+ sk_sp<GrGeometryProcessor> gp = GrQuadPerEdgeAA::MakeTexturedProcessor(
+ vertexSpec, *target->caps().shaderCaps(),
+ textureType, config, this->filter(), std::move(fTextureColorSpaceXform));
GrPipeline::InitArgs args;
args.fProxy = target->proxy();
args.fCaps = &target->caps();