1 /*
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/ops/DrawAtlasPathOp.h"
9
10 #include "src/gpu/BufferWriter.h"
11 #include "src/gpu/GrGeometryProcessor.h"
12 #include "src/gpu/GrOpFlushState.h"
13 #include "src/gpu/GrOpsRenderPass.h"
14 #include "src/gpu/GrProgramInfo.h"
15 #include "src/gpu/GrResourceProvider.h"
16 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
17 #include "src/gpu/glsl/GrGLSLVarying.h"
18 #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
19
20 namespace {
21
22 class DrawAtlasPathShader : public GrGeometryProcessor {
23 public:
DrawAtlasPathShader(bool usesLocalCoords, const skgpu::v1::AtlasInstancedHelper* atlasHelper, const GrShaderCaps& shaderCaps)24 DrawAtlasPathShader(bool usesLocalCoords,
25 const skgpu::v1::AtlasInstancedHelper* atlasHelper,
26 const GrShaderCaps& shaderCaps)
27 : GrGeometryProcessor(kDrawAtlasPathShader_ClassID)
28 , fUsesLocalCoords(usesLocalCoords)
29 , fAtlasHelper(atlasHelper)
30 , fAtlasAccess(GrSamplerState::Filter::kNearest,
31 fAtlasHelper->proxy()->backendFormat(),
32 fAtlasHelper->atlasSwizzle()) {
33 if (!shaderCaps.vertexIDSupport()) {
34 constexpr static Attribute kUnitCoordAttrib(
35 "unitCoord", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
36 this->setVertexAttributes(&kUnitCoordAttrib, 1);
37 }
38 fAttribs.emplace_back("fillBounds", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
39 if (fUsesLocalCoords) {
40 fAttribs.emplace_back("affineMatrix", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
41 fAttribs.emplace_back("translate", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
42 }
43 SkASSERT(fAttribs.count() == this->colorAttribIdx());
44 fAttribs.emplace_back("color", kFloat4_GrVertexAttribType, kHalf4_GrSLType);
45 fAtlasHelper->appendInstanceAttribs(&fAttribs);
46 SkASSERT(fAttribs.count() <= kMaxInstanceAttribs);
47 this->setInstanceAttributes(fAttribs.data(), fAttribs.count());
48 this->setTextureSamplerCnt(1);
49 }
50
51 private:
52 class Impl;
53
colorAttribIdx() const54 int colorAttribIdx() const { return fUsesLocalCoords ? 3 : 1; }
55 const char* name() const override { return "DrawAtlasPathShader"; }
56 SkString getShaderDfxInfo() const override {
57 SkString format;
58 format.printf("ShaderDfx_DrawAtlasPathShader_%d", fUsesLocalCoords);
59 return format;
60 }
61 void addToKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
62 b->addBits(1, fUsesLocalCoords, "localCoords");
63 fAtlasHelper->getKeyBits(b);
64 }
65 const TextureSampler& onTextureSampler(int) const override { return fAtlasAccess; }
66 std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const override;
67
68 const bool fUsesLocalCoords;
69 const skgpu::v1::AtlasInstancedHelper* const fAtlasHelper;
70 TextureSampler fAtlasAccess;
71 constexpr static int kMaxInstanceAttribs = 6;
72 SkSTArray<kMaxInstanceAttribs, GrGeometryProcessor::Attribute> fAttribs;
73 };
74
75 class DrawAtlasPathShader::Impl : public ProgramImpl {
76 public:
77 void setData(const GrGLSLProgramDataManager& pdman,
78 const GrShaderCaps&,
79 const GrGeometryProcessor& geomProc) override {
80 auto* atlasHelper = geomProc.cast<DrawAtlasPathShader>().fAtlasHelper;
81 atlasHelper->setUniformData(pdman, fAtlasAdjustUniform);
82 }
83
84 private:
85 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
86 const auto& shader = args.fGeomProc.cast<DrawAtlasPathShader>();
87 args.fVaryingHandler->emitAttributes(shader);
88
89 if (args.fShaderCaps->vertexIDSupport()) {
90 // If we don't have sk_VertexID support then "unitCoord" already came in as a vertex
91 // attrib.
92 args.fVertBuilder->codeAppendf(R"(
93 float2 unitCoord = float2(sk_VertexID & 1, sk_VertexID >> 1);)");
94 }
95
96 args.fVertBuilder->codeAppendf(R"(
97 float2 devCoord = mix(fillBounds.xy, fillBounds.zw, unitCoord);)");
98 gpArgs->fPositionVar.set(kFloat2_GrSLType, "devCoord");
99
100 if (shader.fUsesLocalCoords) {
101 args.fVertBuilder->codeAppendf(R"(
102 float2x2 M = float2x2(affineMatrix);
103 float2 localCoord = inverse(M) * (devCoord - translate);)");
104 gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localCoord");
105 }
106
107 args.fFragBuilder->codeAppendf("half4 %s = half4(1);", args.fOutputCoverage);
108 shader.fAtlasHelper->injectShaderCode(args, gpArgs->fPositionVar, &fAtlasAdjustUniform);
109
110 args.fFragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
111 args.fVaryingHandler->addPassThroughAttribute(
112 shader.fAttribs[shader.colorAttribIdx()].asShaderVar(),
113 args.fOutputColor,
114 GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
115 }
116
117 GrGLSLUniformHandler::UniformHandle fAtlasAdjustUniform;
118 };
119
makeProgramImpl( const GrShaderCaps&) const120 std::unique_ptr<GrGeometryProcessor::ProgramImpl> DrawAtlasPathShader::makeProgramImpl(
121 const GrShaderCaps&) const {
122 return std::make_unique<Impl>();
123 }
124
125 } // anonymous namespace
126
127 namespace skgpu::v1 {
128
finalize(const GrCaps& caps, const GrAppliedClip* clip, GrClampType clampType)129 GrProcessorSet::Analysis DrawAtlasPathOp::finalize(const GrCaps& caps, const GrAppliedClip* clip,
130 GrClampType clampType) {
131 const GrProcessorSet::Analysis& analysis = fProcessors.finalize(
132 fHeadInstance->fColor, GrProcessorAnalysisCoverage::kSingleChannel, clip,
133 &GrUserStencilSettings::kUnused, caps, clampType, &fHeadInstance->fColor);
134 fUsesLocalCoords = analysis.usesLocalCoords();
135 return analysis;
136 }
137
onCombineIfPossible(GrOp* op, SkArenaAlloc*, const GrCaps&)138 GrOp::CombineResult DrawAtlasPathOp::onCombineIfPossible(GrOp* op, SkArenaAlloc*, const GrCaps&) {
139 auto that = op->cast<DrawAtlasPathOp>();
140
141 if (!fAtlasHelper.isCompatible(that->fAtlasHelper) ||
142 fProcessors != that->fProcessors) {
143 return CombineResult::kCannotCombine;
144 }
145
146 SkASSERT(fUsesLocalCoords == that->fUsesLocalCoords);
147 *fTailInstance = that->fHeadInstance;
148 fTailInstance = that->fTailInstance;
149 fInstanceCount += that->fInstanceCount;
150 return CombineResult::kMerged;
151 }
152
prepareProgram(const GrCaps& caps, SkArenaAlloc* arena, const GrSurfaceProxyView& writeView, bool usesMSAASurface, GrAppliedClip&& appliedClip, const GrDstProxyView& dstProxyView, GrXferBarrierFlags renderPassXferBarriers, GrLoadOp colorLoadOp)153 void DrawAtlasPathOp::prepareProgram(const GrCaps& caps, SkArenaAlloc* arena,
154 const GrSurfaceProxyView& writeView, bool usesMSAASurface,
155 GrAppliedClip&& appliedClip,
156 const GrDstProxyView& dstProxyView,
157 GrXferBarrierFlags renderPassXferBarriers,
158 GrLoadOp colorLoadOp) {
159 SkASSERT(!fProgram);
160 GrPipeline::InitArgs initArgs;
161 initArgs.fCaps = ∩︀
162 initArgs.fDstProxyView = dstProxyView;
163 initArgs.fWriteSwizzle = writeView.swizzle();
164 auto pipeline = arena->make<GrPipeline>(initArgs, std::move(fProcessors),
165 std::move(appliedClip));
166 auto shader = arena->make<DrawAtlasPathShader>(fUsesLocalCoords, &fAtlasHelper,
167 *caps.shaderCaps());
168 fProgram = arena->make<GrProgramInfo>(caps, writeView, usesMSAASurface, pipeline,
169 &GrUserStencilSettings::kUnused, shader,
170 GrPrimitiveType::kTriangleStrip, 0,
171 renderPassXferBarriers, colorLoadOp);
172 }
173
onPrePrepare(GrRecordingContext* rContext, const GrSurfaceProxyView& writeView, GrAppliedClip* appliedClip, const GrDstProxyView& dstProxyView, GrXferBarrierFlags renderPassXferBarriers, GrLoadOp colorLoadOp)174 void DrawAtlasPathOp::onPrePrepare(GrRecordingContext* rContext,
175 const GrSurfaceProxyView& writeView,
176 GrAppliedClip* appliedClip, const GrDstProxyView& dstProxyView,
177 GrXferBarrierFlags renderPassXferBarriers,
178 GrLoadOp colorLoadOp) {
179 // DMSAA is not supported on DDL.
180 bool usesMSAASurface = writeView.asRenderTargetProxy()->numSamples() > 1;
181 this->prepareProgram(*rContext->priv().caps(), rContext->priv().recordTimeAllocator(),
182 writeView, usesMSAASurface, std::move(*appliedClip), dstProxyView,
183 renderPassXferBarriers, colorLoadOp);
184 SkASSERT(fProgram);
185 rContext->priv().recordProgramInfo(fProgram);
186 }
187
188 GR_DECLARE_STATIC_UNIQUE_KEY(gUnitQuadBufferKey);
189
onPrepare(GrOpFlushState* flushState)190 void DrawAtlasPathOp::onPrepare(GrOpFlushState* flushState) {
191 if (!fProgram) {
192 this->prepareProgram(flushState->caps(), flushState->allocator(), flushState->writeView(),
193 flushState->usesMSAASurface(), flushState->detachAppliedClip(),
194 flushState->dstProxyView(), flushState->renderPassBarriers(),
195 flushState->colorLoadOp());
196 SkASSERT(fProgram);
197 }
198
199 if (VertexWriter instanceWriter = flushState->makeVertexSpace(
200 fProgram->geomProc().instanceStride(), fInstanceCount, &fInstanceBuffer,
201 &fBaseInstance)) {
202 for (const Instance* i = fHeadInstance; i; i = i->fNext) {
203 instanceWriter << SkRect::Make(i->fFillBounds)
204 << VertexWriter::If(fUsesLocalCoords,
205 i->fLocalToDeviceIfUsingLocalCoords)
206 << i->fColor;
207 fAtlasHelper.writeInstanceData(&instanceWriter, &i->fAtlasInstance);
208 }
209 }
210
211 if (!flushState->caps().shaderCaps()->vertexIDSupport()) {
212 constexpr static SkPoint kUnitQuad[4] = {{0,0}, {0,1}, {1,0}, {1,1}};
213
214 GR_DEFINE_STATIC_UNIQUE_KEY(gUnitQuadBufferKey);
215
216 fVertexBufferIfNoIDSupport = flushState->resourceProvider()->findOrMakeStaticBuffer(
217 GrGpuBufferType::kVertex, sizeof(kUnitQuad), kUnitQuad, gUnitQuadBufferKey);
218 }
219 }
220
onExecute(GrOpFlushState* flushState, const SkRect& chainBounds)221 void DrawAtlasPathOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
222 if (fProgram->geomProc().hasVertexAttributes() && !fVertexBufferIfNoIDSupport) {
223 return;
224 }
225 flushState->bindPipelineAndScissorClip(*fProgram, this->bounds());
226 flushState->bindTextures(fProgram->geomProc(), *fAtlasHelper.proxy(), fProgram->pipeline());
227 flushState->bindBuffers(nullptr, std::move(fInstanceBuffer), fVertexBufferIfNoIDSupport);
228 flushState->drawInstanced(fInstanceCount, fBaseInstance, 4, 0);
229 }
230
231 } // namespace skgpu::v1
232