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