Implement inverse fill support in GrTessellationPathRenderer
Bug: skia:10419
Bug: skia:11396
Change-Id: I489236ec5dff59b0e7c4c4e22b83b2b5ec4e9a26
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/421796
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/src/gpu/tessellate/GrDrawAtlasPathOp.cpp b/src/gpu/tessellate/GrDrawAtlasPathOp.cpp
index d2cb90e..78c5253 100644
--- a/src/gpu/tessellate/GrDrawAtlasPathOp.cpp
+++ b/src/gpu/tessellate/GrDrawAtlasPathOp.cpp
@@ -10,6 +10,7 @@
#include "src/gpu/GrOpFlushState.h"
#include "src/gpu/GrOpsRenderPass.h"
#include "src/gpu/GrProgramInfo.h"
+#include "src/gpu/GrVertexWriter.h"
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
#include "src/gpu/glsl/GrGLSLVarying.h"
@@ -17,25 +18,27 @@
namespace {
-constexpr static GrGeometryProcessor::Attribute kInstanceAttribs[] = {
- {"dev_xywh", kInt4_GrVertexAttribType, kInt4_GrSLType},
- {"atlas_xy", kInt2_GrVertexAttribType, kInt2_GrSLType},
- {"color", kFloat4_GrVertexAttribType, kHalf4_GrSLType},
- {"viewmatrix_scaleskew", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
- {"viewmatrix_trans", kFloat2_GrVertexAttribType, kFloat2_GrSLType}};
-
class DrawAtlasPathShader : public GrGeometryProcessor {
public:
- DrawAtlasPathShader(const GrTextureProxy* atlasProxy, GrSwizzle swizzle, bool usesLocalCoords)
+ DrawAtlasPathShader(const GrTextureProxy* atlasProxy, GrSwizzle swizzle, bool isInverseFill,
+ bool usesLocalCoords)
: GrGeometryProcessor(kDrawAtlasPathShader_ClassID)
, fAtlasAccess(GrSamplerState::Filter::kNearest, atlasProxy->backendFormat(), swizzle)
, fAtlasDimensions(atlasProxy->backingStoreDimensions())
+ , fIsInverseFill(isInverseFill)
, fUsesLocalCoords(usesLocalCoords) {
- int numInstanceAttribs = SK_ARRAY_COUNT(kInstanceAttribs);
- if (!fUsesLocalCoords) {
- numInstanceAttribs -= 2;
+ fAttribs.emplace_back("dev_xywh", kInt4_GrVertexAttribType, kInt4_GrSLType);
+ fAttribs.emplace_back("atlas_xy", kInt2_GrVertexAttribType, kInt2_GrSLType);
+ fAttribs.emplace_back("color", kFloat4_GrVertexAttribType, kHalf4_GrSLType);
+ if (fIsInverseFill) {
+ fAttribs.emplace_back("drawbounds", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
}
- this->setInstanceAttributes(kInstanceAttribs, numInstanceAttribs);
+ if (fUsesLocalCoords) {
+ fAttribs.emplace_back("viewmatrix_scaleskew", kFloat4_GrVertexAttribType,
+ kFloat4_GrSLType);
+ fAttribs.emplace_back("viewmatrix_trans", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
+ }
+ this->setInstanceAttributes(fAttribs.data(), fAttribs.count());
this->setTextureSamplerCnt(1);
}
@@ -49,7 +52,9 @@
const TextureSampler fAtlasAccess;
const SkISize fAtlasDimensions;
+ const bool fIsInverseFill;
const bool fUsesLocalCoords;
+ SkSTArray<6, GrGeometryProcessor::Attribute> fAttribs;
class Impl;
};
@@ -65,7 +70,7 @@
GrGLSLVarying color(kHalf4_GrSLType);
args.fFragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
args.fVaryingHandler->addPassThroughAttribute(
- kInstanceAttribs[2], args.fOutputColor,
+ shader.fAttribs[2], args.fOutputColor,
GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
const char* atlasAdjust;
@@ -73,29 +78,61 @@
nullptr, kVertex_GrShaderFlag, kFloat2_GrSLType, "atlas_adjust", &atlasAdjust);
args.fVertBuilder->codeAppendf(R"(
- float2 T = float2(sk_VertexID & 1, sk_VertexID >> 1);
- float2 devtopleft = float2(dev_xywh.xy);
- float2 devcoord = abs(float2(dev_xywh.zw)) * T + devtopleft;
- float2 atlascoord = devcoord - devtopleft;
- if (dev_xywh.w < 0) { // Negative height indicates that the path is transposed.
- atlascoord = atlascoord.yx;
- }
- atlascoord += float2(atlas_xy);
- %s = atlascoord * %s;)",
- atlasCoord.vsOut(), atlasAdjust);
+ float2 T = float2(sk_VertexID & 1, sk_VertexID >> 1);
+ float2 devtopleft = float2(dev_xywh.xy);)");
+
+ if (shader.fIsInverseFill) {
+ args.fVertBuilder->codeAppendf(R"(
+ float2 devcoord = mix(drawbounds.xy, drawbounds.zw, T);)");
+ } else {
+ args.fVertBuilder->codeAppendf(R"(
+ float2 devcoord = abs(float2(dev_xywh.zw)) * T + devtopleft;)");
+ }
+
+ args.fVertBuilder->codeAppendf(R"(
+ float2 atlascoord = devcoord - devtopleft;
+ bool transposed = dev_xywh.w < 0; // Negative height means the path is transposed.
+ if (transposed) {
+ atlascoord = atlascoord.yx;
+ }
+ atlascoord += float2(atlas_xy);
+ %s = atlascoord * %s;)",
+ atlasCoord.vsOut(), atlasAdjust);
gpArgs->fPositionVar.set(kFloat2_GrSLType, "devcoord");
if (shader.fUsesLocalCoords) {
args.fVertBuilder->codeAppendf(R"(
- float2x2 M = float2x2(viewmatrix_scaleskew);
- float2 localcoord = inverse(M) * (devcoord - viewmatrix_trans);)");
+ float2x2 M = float2x2(viewmatrix_scaleskew);
+ float2 localcoord = inverse(M) * (devcoord - viewmatrix_trans);)");
gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord");
}
- args.fFragBuilder->codeAppendf("half4 %s = ", args.fOutputCoverage);
- args.fFragBuilder->appendTextureLookup(args.fTexSamplers[0], atlasCoord.fsIn());
- args.fFragBuilder->codeAppendf(".aaaa;");
+ if (shader.fIsInverseFill) {
+ GrGLSLVarying atlasBounds(kFloat4_GrSLType);
+ args.fVaryingHandler->addVarying("atlasbounds", &atlasBounds,
+ GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
+ args.fVertBuilder->codeAppendf(R"(
+ int2 atlas_wh = (transposed) ? abs(dev_xywh.wz) : dev_xywh.zw;
+ %s = float4(atlas_xy, atlas_xy + atlas_wh) * %s.xyxy;)", atlasBounds.vsOut(),
+ atlasAdjust);
+
+ args.fFragBuilder->codeAppendf(R"(
+ half coverage = 0;
+ float2 atlascoord = %s;
+ float4 atlasbounds = %s;
+ if (all(greaterThan(atlascoord, atlasbounds.xy)) &&
+ all(lessThan(atlascoord, atlasbounds.zw))) {
+ coverage = )", atlasCoord.fsIn(), atlasBounds.fsIn());
+ args.fFragBuilder->appendTextureLookup(args.fTexSamplers[0], "atlascoord");
+ args.fFragBuilder->codeAppendf(R"(.a;
+ }
+ half4 %s = half4(1 - coverage);)", args.fOutputCoverage);
+ } else {
+ args.fFragBuilder->codeAppendf("half4 %s = ", args.fOutputCoverage);
+ args.fFragBuilder->appendTextureLookup(args.fTexSamplers[0], atlasCoord.fsIn());
+ args.fFragBuilder->codeAppendf(".aaaa;");
+ }
}
void setData(const GrGLSLProgramDataManager& pdman,
@@ -117,8 +154,8 @@
GrProcessorSet::Analysis GrDrawAtlasPathOp::finalize(const GrCaps& caps, const GrAppliedClip* clip,
GrClampType clampType) {
const GrProcessorSet::Analysis& analysis = fProcessors.finalize(
- fInstanceList.fInstance.fColor, GrProcessorAnalysisCoverage::kSingleChannel, clip,
- &GrUserStencilSettings::kUnused, caps, clampType, &fInstanceList.fInstance.fColor);
+ fHeadInstance.fColor, GrProcessorAnalysisCoverage::kSingleChannel, clip,
+ &GrUserStencilSettings::kUnused, caps, clampType, &fHeadInstance.fColor);
fUsesLocalCoords = analysis.usesLocalCoords();
return analysis;
}
@@ -129,40 +166,27 @@
SkASSERT(fAtlasProxy == that->fAtlasProxy);
SkASSERT(fEnableHWAA == that->fEnableHWAA);
- if (fProcessors != that->fProcessors) {
+ if (fIsInverseFill != that->fIsInverseFill || fProcessors != that->fProcessors) {
return CombineResult::kCannotCombine;
}
SkASSERT(fUsesLocalCoords == that->fUsesLocalCoords);
- auto* copy = alloc->make<InstanceList>(that->fInstanceList);
- *fInstanceTail = copy;
- fInstanceTail = (!copy->fNext) ? ©->fNext : that->fInstanceTail;
+ auto* copy = alloc->make<Instance>(that->fHeadInstance);
+ *fTailInstance = copy;
+ fTailInstance = (!copy->fNext) ? ©->fNext : that->fTailInstance;
fInstanceCount += that->fInstanceCount;
return CombineResult::kMerged;
}
-void GrDrawAtlasPathOp::onPrePrepare(GrRecordingContext*,
- const GrSurfaceProxyView& writeView,
- GrAppliedClip*,
- const GrDstProxyView&,
+void GrDrawAtlasPathOp::onPrePrepare(GrRecordingContext*, const GrSurfaceProxyView& writeView,
+ GrAppliedClip*, const GrDstProxyView&,
GrXferBarrierFlags renderPassXferBarriers,
- GrLoadOp colorLoadOp) {}
-
-void GrDrawAtlasPathOp::onPrepare(GrOpFlushState* state) {
- size_t instanceStride = Instance::Stride(fUsesLocalCoords);
- if (char* instanceData = (char*)state->makeVertexSpace(
- instanceStride, fInstanceCount, &fInstanceBuffer, &fBaseInstance)) {
- SkDEBUGCODE(char* end = instanceData + fInstanceCount * instanceStride);
- for (const InstanceList* list = &fInstanceList; list; list = list->fNext) {
- memcpy(instanceData, &list->fInstance, instanceStride);
- instanceData += instanceStride;
- }
- SkASSERT(instanceData == end);
- }
+ GrLoadOp colorLoadOp) {
+ SK_ABORT("DDL support not implemented for GrDrawAtlasPathOp.");
}
-void GrDrawAtlasPathOp::onExecute(GrOpFlushState* state, const SkRect& chainBounds) {
- SkASSERT(fAtlasProxy->isInstantiated());
+void GrDrawAtlasPathOp::onPrepare(GrOpFlushState* state) {
+ SkArenaAlloc* arena = state->allocator();
GrPipeline::InitArgs initArgs;
if (fEnableHWAA) {
@@ -171,20 +195,34 @@
initArgs.fCaps = &state->caps();
initArgs.fDstProxyView = state->drawOpArgs().dstProxyView();
initArgs.fWriteSwizzle = state->drawOpArgs().writeView().swizzle();
- GrPipeline pipeline(initArgs, std::move(fProcessors), state->detachAppliedClip());
-
+ auto pipeline = arena->make<GrPipeline>(initArgs, std::move(fProcessors),
+ state->detachAppliedClip());
GrSwizzle swizzle = state->caps().getReadSwizzle(fAtlasProxy->backendFormat(),
GrColorType::kAlpha_8);
+ auto shader = arena->make<DrawAtlasPathShader>(fAtlasProxy.get(), swizzle, fIsInverseFill,
+ fUsesLocalCoords);
+ fProgram = arena->make<GrProgramInfo>(state->writeView(), pipeline,
+ &GrUserStencilSettings::kUnused, shader,
+ GrPrimitiveType::kTriangleStrip, 0,
+ state->renderPassBarriers(), state->colorLoadOp());
- DrawAtlasPathShader shader(fAtlasProxy.get(), swizzle, fUsesLocalCoords);
- SkASSERT(shader.instanceStride() == Instance::Stride(fUsesLocalCoords));
+ if (GrVertexWriter instanceWriter = state->makeVertexSpace(
+ shader->instanceStride(), fInstanceCount, &fInstanceBuffer, &fBaseInstance)) {
+ for (const Instance* instance = &fHeadInstance; instance; instance = instance->fNext) {
+ instanceWriter.write(
+ instance->fDevXYWH,
+ instance->fAtlasXY,
+ instance->fColor,
+ GrVertexWriter::If(fIsInverseFill, instance->fDrawBoundsIfInverseFilled),
+ GrVertexWriter::If(fUsesLocalCoords, instance->fViewMatrixIfUsingLocalCoords));
+ }
+ }
+}
- GrProgramInfo programInfo(state->writeView(), &pipeline, &GrUserStencilSettings::kUnused,
- &shader, GrPrimitiveType::kTriangleStrip, 0,
- state->renderPassBarriers(), state->colorLoadOp());
-
- state->bindPipelineAndScissorClip(programInfo, this->bounds());
- state->bindTextures(shader, *fAtlasProxy, pipeline);
+void GrDrawAtlasPathOp::onExecute(GrOpFlushState* state, const SkRect& chainBounds) {
+ SkASSERT(fAtlasProxy->isInstantiated());
+ state->bindPipelineAndScissorClip(*fProgram, this->bounds());
+ state->bindTextures(fProgram->geomProc(), *fAtlasProxy, fProgram->pipeline());
state->bindBuffers(nullptr, std::move(fInstanceBuffer), nullptr);
state->drawInstanced(fInstanceCount, fBaseInstance, 4, 0);
}