xref: /aosp_15_r20/external/skia/src/gpu/ganesh/ops/DrawAtlasPathOp.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 = &caps;
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