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