blob: 5089b21d0183ef18de9decf6bf7263916c751e85 [file] [log] [blame]
Chris Dalton4e998532020-02-10 11:06:42 -07001/*
2 * Copyright 2020 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "src/gpu/tessellate/GrDrawAtlasPathOp.h"
9
10#include "src/gpu/GrOpFlushState.h"
11#include "src/gpu/GrOpsRenderPass.h"
12#include "src/gpu/GrProgramInfo.h"
Robert Phillips1a82a4e2021-07-01 10:27:44 -040013#include "src/gpu/GrResourceProvider.h"
Chris Daltonbaae2dd2021-06-25 14:52:49 -060014#include "src/gpu/GrVertexWriter.h"
Chris Daltonee40d5a2021-07-07 16:34:36 -060015#include "src/gpu/GrVx.h"
Chris Dalton4e998532020-02-10 11:06:42 -070016#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
17#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
18#include "src/gpu/glsl/GrGLSLVarying.h"
19#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
20
21namespace {
22
Chris Dalton4e998532020-02-10 11:06:42 -070023class DrawAtlasPathShader : public GrGeometryProcessor {
24public:
Chris Daltonbaae2dd2021-06-25 14:52:49 -060025 DrawAtlasPathShader(const GrTextureProxy* atlasProxy, GrSwizzle swizzle, bool isInverseFill,
Chris Daltona05ccc32021-06-29 19:42:13 -060026 bool usesLocalCoords, const GrShaderCaps& shaderCaps)
Chris Dalton4e998532020-02-10 11:06:42 -070027 : GrGeometryProcessor(kDrawAtlasPathShader_ClassID)
28 , fAtlasAccess(GrSamplerState::Filter::kNearest, atlasProxy->backendFormat(), swizzle)
29 , fAtlasDimensions(atlasProxy->backingStoreDimensions())
Chris Daltonbaae2dd2021-06-25 14:52:49 -060030 , fIsInverseFill(isInverseFill)
Chris Dalton4e998532020-02-10 11:06:42 -070031 , fUsesLocalCoords(usesLocalCoords) {
Chris Daltona05ccc32021-06-29 19:42:13 -060032 if (!shaderCaps.vertexIDSupport()) {
Chris Daltonee40d5a2021-07-07 16:34:36 -060033 constexpr static Attribute kUnitCoordAttrib("unitCoord", kFloat2_GrVertexAttribType,
Chris Daltona05ccc32021-06-29 19:42:13 -060034 kFloat2_GrSLType);
35 this->setVertexAttributes(&kUnitCoordAttrib, 1);
36 }
Chris Daltonee40d5a2021-07-07 16:34:36 -060037 fAttribs.emplace_back("fillBounds", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
38 if (fUsesLocalCoords) {
39 fAttribs.emplace_back("affineMatrix", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
40 fAttribs.emplace_back("translate", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
41 }
42 SkASSERT(fAttribs.count() == this->colorAttribIdx());
43 fAttribs.emplace_back("color", kFloat4_GrVertexAttribType, kHalf4_GrSLType);
44 fAttribs.emplace_back("locations", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
45 if (fIsInverseFill) {
46 fAttribs.emplace_back("sizeInAtlas", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
47 }
48 this->setInstanceAttributes(fAttribs.data(), fAttribs.count());
Chris Dalton4e998532020-02-10 11:06:42 -070049 this->setTextureSamplerCnt(1);
50 }
51
52private:
Chris Daltonee40d5a2021-07-07 16:34:36 -060053 int colorAttribIdx() const { return fUsesLocalCoords ? 3 : 1; }
Chris Dalton4e998532020-02-10 11:06:42 -070054 const char* name() const override { return "DrawAtlasPathShader"; }
55 void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
Chris Daltonee40d5a2021-07-07 16:34:36 -060056 b->add32((fUsesLocalCoords << 1) | (int)fIsInverseFill);
Chris Dalton4e998532020-02-10 11:06:42 -070057 }
58 const TextureSampler& onTextureSampler(int) const override { return fAtlasAccess; }
Robert Phillipsf10535f2021-03-23 09:30:45 -040059 GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const override;
Chris Dalton4e998532020-02-10 11:06:42 -070060
61 const TextureSampler fAtlasAccess;
62 const SkISize fAtlasDimensions;
Chris Daltonbaae2dd2021-06-25 14:52:49 -060063 const bool fIsInverseFill;
Chris Dalton4e998532020-02-10 11:06:42 -070064 const bool fUsesLocalCoords;
Chris Daltonbaae2dd2021-06-25 14:52:49 -060065 SkSTArray<6, GrGeometryProcessor::Attribute> fAttribs;
Chris Dalton4e998532020-02-10 11:06:42 -070066
67 class Impl;
68};
69
70class DrawAtlasPathShader::Impl : public GrGLSLGeometryProcessor {
71 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
Robert Phillips787fd9d2021-03-22 14:48:09 -040072 const auto& shader = args.fGeomProc.cast<DrawAtlasPathShader>();
Chris Dalton4e998532020-02-10 11:06:42 -070073 args.fVaryingHandler->emitAttributes(shader);
74
75 GrGLSLVarying atlasCoord(kFloat2_GrSLType);
Chris Daltonee40d5a2021-07-07 16:34:36 -060076 args.fVaryingHandler->addVarying("atlasCoord", &atlasCoord);
Chris Dalton4e998532020-02-10 11:06:42 -070077
78 const char* atlasAdjust;
79 fAtlasAdjustUniform = args.fUniformHandler->addUniform(
Ethan Nicholas16464c32020-04-06 13:53:05 -040080 nullptr, kVertex_GrShaderFlag, kFloat2_GrSLType, "atlas_adjust", &atlasAdjust);
Chris Dalton4e998532020-02-10 11:06:42 -070081
Chris Daltona05ccc32021-06-29 19:42:13 -060082 if (args.fShaderCaps->vertexIDSupport()) {
Chris Daltonee40d5a2021-07-07 16:34:36 -060083 // If we don't have sk_VertexID support then "unitCoord" already came in as a vertex
Chris Daltona05ccc32021-06-29 19:42:13 -060084 // attrib.
85 args.fVertBuilder->codeAppendf(R"(
Chris Daltonee40d5a2021-07-07 16:34:36 -060086 float2 unitCoord = float2(sk_VertexID & 1, sk_VertexID >> 1);)");
Chris Daltona05ccc32021-06-29 19:42:13 -060087 }
88
Chris Dalton4e998532020-02-10 11:06:42 -070089 args.fVertBuilder->codeAppendf(R"(
Chris Daltonee40d5a2021-07-07 16:34:36 -060090 float2 devCoord = mix(fillBounds.xy, fillBounds.zw, unitCoord);)");
91 gpArgs->fPositionVar.set(kFloat2_GrSLType, "devCoord");
Chris Dalton4e998532020-02-10 11:06:42 -070092
Chris Dalton4e998532020-02-10 11:06:42 -070093 if (shader.fUsesLocalCoords) {
94 args.fVertBuilder->codeAppendf(R"(
Chris Daltonee40d5a2021-07-07 16:34:36 -060095 float2x2 M = float2x2(affineMatrix);
96 float2 localCoord = inverse(M) * (devCoord - translate);)");
97 gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localCoord");
Chris Dalton4e998532020-02-10 11:06:42 -070098 }
Chris Dalton4e998532020-02-10 11:06:42 -070099
Chris Daltonee40d5a2021-07-07 16:34:36 -0600100 args.fVertBuilder->codeAppendf(R"(
101 // A negative x coordinate in the atlas indicates that the path is transposed.
102 // We also added 1 since we can't negate zero.
103 float2 atlasTopLeft = float2(abs(locations.x) - 1, locations.y);
104 float2 devTopLeft = locations.zw;
105 bool transposed = locations.x < 0;
106 float2 atlasCoord = devCoord - devTopLeft;
107 if (transposed) {
108 atlasCoord = atlasCoord.yx;
109 }
110 atlasCoord += atlasTopLeft;
111 %s = atlasCoord * %s;)", atlasCoord.vsOut(), atlasAdjust);
112
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600113 if (shader.fIsInverseFill) {
114 GrGLSLVarying atlasBounds(kFloat4_GrSLType);
115 args.fVaryingHandler->addVarying("atlasbounds", &atlasBounds,
116 GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
117 args.fVertBuilder->codeAppendf(R"(
Chris Daltonee40d5a2021-07-07 16:34:36 -0600118 float4 atlasBounds = atlasTopLeft.xyxy + (transposed ? sizeInAtlas.00yx
119 : sizeInAtlas.00xy);
120 %s = atlasBounds * %s.xyxy;)", atlasBounds.vsOut(), atlasAdjust);
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600121
122 args.fFragBuilder->codeAppendf(R"(
123 half coverage = 0;
Chris Daltonee40d5a2021-07-07 16:34:36 -0600124 float2 atlasCoord = %s;
125 float4 atlasBounds = %s;
126 if (all(greaterThan(atlasCoord, atlasBounds.xy)) &&
127 all(lessThan(atlasCoord, atlasBounds.zw))) {
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600128 coverage = )", atlasCoord.fsIn(), atlasBounds.fsIn());
Chris Daltonee40d5a2021-07-07 16:34:36 -0600129 args.fFragBuilder->appendTextureLookup(args.fTexSamplers[0], "atlasCoord");
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600130 args.fFragBuilder->codeAppendf(R"(.a;
131 }
132 half4 %s = half4(1 - coverage);)", args.fOutputCoverage);
133 } else {
134 args.fFragBuilder->codeAppendf("half4 %s = ", args.fOutputCoverage);
135 args.fFragBuilder->appendTextureLookup(args.fTexSamplers[0], atlasCoord.fsIn());
136 args.fFragBuilder->codeAppendf(".aaaa;");
137 }
Chris Daltonee40d5a2021-07-07 16:34:36 -0600138
139 args.fFragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
140 args.fVaryingHandler->addPassThroughAttribute(
141 shader.fAttribs[shader.colorAttribIdx()], args.fOutputColor,
142 GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
Chris Dalton4e998532020-02-10 11:06:42 -0700143 }
144
Brian Osman609f1592020-07-01 15:14:39 -0400145 void setData(const GrGLSLProgramDataManager& pdman,
Brian Salomon5a328282021-04-14 10:32:25 -0400146 const GrShaderCaps&,
Robert Phillips787fd9d2021-03-22 14:48:09 -0400147 const GrGeometryProcessor& geomProc) override {
148 const SkISize& dimensions = geomProc.cast<DrawAtlasPathShader>().fAtlasDimensions;
Chris Dalton4e998532020-02-10 11:06:42 -0700149 pdman.set2f(fAtlasAdjustUniform, 1.f / dimensions.width(), 1.f / dimensions.height());
Chris Dalton4e998532020-02-10 11:06:42 -0700150 }
151
152 GrGLSLUniformHandler::UniformHandle fAtlasAdjustUniform;
153};
154
Robert Phillipsf10535f2021-03-23 09:30:45 -0400155GrGLSLGeometryProcessor* DrawAtlasPathShader::createGLSLInstance(const GrShaderCaps&) const {
Chris Dalton4e998532020-02-10 11:06:42 -0700156 return new Impl();
157}
158
159} // namespace
160
161GrProcessorSet::Analysis GrDrawAtlasPathOp::finalize(const GrCaps& caps, const GrAppliedClip* clip,
Chris Dalton4e998532020-02-10 11:06:42 -0700162 GrClampType clampType) {
163 const GrProcessorSet::Analysis& analysis = fProcessors.finalize(
Chris Daltonee40d5a2021-07-07 16:34:36 -0600164 fHeadInstance->fColor, GrProcessorAnalysisCoverage::kSingleChannel, clip,
165 &GrUserStencilSettings::kUnused, caps, clampType, &fHeadInstance->fColor);
Chris Dalton4e998532020-02-10 11:06:42 -0700166 fUsesLocalCoords = analysis.usesLocalCoords();
167 return analysis;
168}
169
170GrOp::CombineResult GrDrawAtlasPathOp::onCombineIfPossible(
Herb Derbye25c3002020-10-27 15:57:27 -0400171 GrOp* op, SkArenaAlloc* alloc, const GrCaps&) {
Chris Dalton4e998532020-02-10 11:06:42 -0700172 auto* that = op->cast<GrDrawAtlasPathOp>();
173 SkASSERT(fAtlasProxy == that->fAtlasProxy);
174 SkASSERT(fEnableHWAA == that->fEnableHWAA);
175
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600176 if (fIsInverseFill != that->fIsInverseFill || fProcessors != that->fProcessors) {
Chris Dalton4e998532020-02-10 11:06:42 -0700177 return CombineResult::kCannotCombine;
178 }
179
180 SkASSERT(fUsesLocalCoords == that->fUsesLocalCoords);
Chris Daltonee40d5a2021-07-07 16:34:36 -0600181 *fTailInstance = that->fHeadInstance;
182 fTailInstance = that->fTailInstance;
Chris Dalton4e998532020-02-10 11:06:42 -0700183 fInstanceCount += that->fInstanceCount;
184 return CombineResult::kMerged;
185}
186
Chris Daltonee40d5a2021-07-07 16:34:36 -0600187void GrDrawAtlasPathOp::prepareProgram(const GrCaps& caps, SkArenaAlloc* arena,
188 const GrSurfaceProxyView& writeView,
189 GrAppliedClip&& appliedClip,
190 const GrDstProxyView& dstProxyView,
191 GrXferBarrierFlags renderPassXferBarriers,
192 GrLoadOp colorLoadOp) {
193 SkASSERT(!fProgram);
Chris Dalton4e998532020-02-10 11:06:42 -0700194 GrPipeline::InitArgs initArgs;
195 if (fEnableHWAA) {
196 initArgs.fInputFlags |= GrPipeline::InputFlags::kHWAntialias;
197 }
Chris Daltonee40d5a2021-07-07 16:34:36 -0600198 initArgs.fCaps = &caps;
199 initArgs.fDstProxyView = dstProxyView;
200 initArgs.fWriteSwizzle = writeView.swizzle();
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600201 auto pipeline = arena->make<GrPipeline>(initArgs, std::move(fProcessors),
Chris Daltonee40d5a2021-07-07 16:34:36 -0600202 std::move(appliedClip));
203 GrSwizzle swizzle = caps.getReadSwizzle(fAtlasProxy->backendFormat(), GrColorType::kAlpha_8);
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600204 auto shader = arena->make<DrawAtlasPathShader>(fAtlasProxy.get(), swizzle, fIsInverseFill,
Chris Daltonee40d5a2021-07-07 16:34:36 -0600205 fUsesLocalCoords, *caps.shaderCaps());
206 fProgram = arena->make<GrProgramInfo>(writeView, pipeline, &GrUserStencilSettings::kUnused,
207 shader, GrPrimitiveType::kTriangleStrip, 0,
208 renderPassXferBarriers, colorLoadOp);
209}
Chris Dalton012f8492020-03-05 11:49:15 -0700210
Chris Daltonee40d5a2021-07-07 16:34:36 -0600211void GrDrawAtlasPathOp::onPrePrepare(GrRecordingContext* rContext,
212 const GrSurfaceProxyView& writeView,
213 GrAppliedClip* appliedClip, const GrDstProxyView& dstProxyView,
214 GrXferBarrierFlags renderPassXferBarriers,
215 GrLoadOp colorLoadOp) {
216 this->prepareProgram(*rContext->priv().caps(), rContext->priv().recordTimeAllocator(),
217 writeView, std::move(*appliedClip), dstProxyView, renderPassXferBarriers,
218 colorLoadOp);
219 SkASSERT(fProgram);
220 rContext->priv().recordProgramInfo(fProgram);
221}
222
223GR_DECLARE_STATIC_UNIQUE_KEY(gUnitQuadBufferKey);
224
225void GrDrawAtlasPathOp::onPrepare(GrOpFlushState* flushState) {
226 if (!fProgram) {
227 this->prepareProgram(flushState->caps(), flushState->allocator(), flushState->writeView(),
228 flushState->detachAppliedClip(), flushState->dstProxyView(),
229 flushState->renderPassBarriers(), flushState->colorLoadOp());
230 SkASSERT(fProgram);
231 }
232
233 if (GrVertexWriter instanceWriter = flushState->makeVertexSpace(
234 fProgram->geomProc().instanceStride(), fInstanceCount, &fInstanceBuffer,
235 &fBaseInstance)) {
236 for (const Instance* instance = fHeadInstance; instance; instance = instance->fNext) {
237 SkASSERT(instance->fLocationInAtlas.x() >= 0);
238 SkASSERT(instance->fLocationInAtlas.y() >= 0);
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600239 instanceWriter.write(
Chris Daltonee40d5a2021-07-07 16:34:36 -0600240 SkRect::Make(instance->fFillBounds),
241 GrVertexWriter::If(fUsesLocalCoords,
242 instance->fLocalToDeviceIfUsingLocalCoords),
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600243 instance->fColor,
Chris Daltonee40d5a2021-07-07 16:34:36 -0600244 // A negative x coordinate in the atlas indicates that the path is transposed.
245 // Also add 1 since we can't negate zero.
246 (float)(instance->fTransposedInAtlas ? -instance->fLocationInAtlas.x() - 1
247 : instance->fLocationInAtlas.x() + 1),
248 (float)instance->fLocationInAtlas.y(),
249 (float)instance->fPathDevIBounds.left(),
250 (float)instance->fPathDevIBounds.top(),
251 GrVertexWriter::If(fIsInverseFill,
252 SkSize::Make(instance->fPathDevIBounds.size())));
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600253 }
254 }
Chris Daltona05ccc32021-06-29 19:42:13 -0600255
Chris Daltonee40d5a2021-07-07 16:34:36 -0600256 if (!flushState->caps().shaderCaps()->vertexIDSupport()) {
Chris Daltona05ccc32021-06-29 19:42:13 -0600257 constexpr static SkPoint kUnitQuad[4] = {{0,0}, {0,1}, {1,0}, {1,1}};
258
259 GR_DEFINE_STATIC_UNIQUE_KEY(gUnitQuadBufferKey);
260
Chris Daltonee40d5a2021-07-07 16:34:36 -0600261 fVertexBufferIfNoIDSupport = flushState->resourceProvider()->findOrMakeStaticBuffer(
Chris Daltona05ccc32021-06-29 19:42:13 -0600262 GrGpuBufferType::kVertex, sizeof(kUnitQuad), kUnitQuad, gUnitQuadBufferKey);
263 }
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600264}
Chris Dalton4e998532020-02-10 11:06:42 -0700265
Chris Daltonee40d5a2021-07-07 16:34:36 -0600266void GrDrawAtlasPathOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600267 SkASSERT(fAtlasProxy->isInstantiated());
Chris Daltonee40d5a2021-07-07 16:34:36 -0600268 flushState->bindPipelineAndScissorClip(*fProgram, this->bounds());
269 flushState->bindTextures(fProgram->geomProc(), *fAtlasProxy, fProgram->pipeline());
270 flushState->bindBuffers(nullptr, std::move(fInstanceBuffer), fVertexBufferIfNoIDSupport);
271 flushState->drawInstanced(fInstanceCount, fBaseInstance, 4, 0);
Chris Dalton4e998532020-02-10 11:06:42 -0700272}