• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "src/gpu/BufferWriter.h"
11 #include "src/gpu/KeyBuilder.h"
12 #include "src/gpu/ganesh/GrBuffer.h"
13 #include "src/gpu/ganesh/GrCaps.h"
14 #include "src/gpu/ganesh/GrGeometryProcessor.h"
15 #include "src/gpu/ganesh/GrGpuBuffer.h"
16 #include "src/gpu/ganesh/GrOpFlushState.h"
17 #include "src/gpu/ganesh/GrOpsRenderPass.h"
18 #include "src/gpu/ganesh/GrProgramInfo.h"
19 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
20 #include "src/gpu/ganesh/GrResourceProvider.h"
21 #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
22 #include "src/gpu/ganesh/glsl/GrGLSLVarying.h"
23 #include "src/gpu/ganesh/glsl/GrGLSLVertexGeoBuilder.h"
24 
25 namespace {
26 
27 class DrawAtlasPathShader : public GrGeometryProcessor {
28 public:
DrawAtlasPathShader(bool usesLocalCoords,const skgpu::v1::AtlasInstancedHelper * atlasHelper,const GrShaderCaps & shaderCaps)29     DrawAtlasPathShader(bool usesLocalCoords,
30                         const skgpu::v1::AtlasInstancedHelper* atlasHelper,
31                         const GrShaderCaps& shaderCaps)
32             : GrGeometryProcessor(kDrawAtlasPathShader_ClassID)
33             , fUsesLocalCoords(usesLocalCoords)
34             , fAtlasHelper(atlasHelper)
35             , fAtlasAccess(GrSamplerState::Filter::kNearest,
36                            fAtlasHelper->proxy()->backendFormat(),
37                            fAtlasHelper->atlasSwizzle()) {
38         if (!shaderCaps.fVertexIDSupport) {
39             constexpr static Attribute kUnitCoordAttrib(
40                     "unitCoord", kFloat2_GrVertexAttribType, SkSLType::kFloat2);
41             this->setVertexAttributesWithImplicitOffsets(&kUnitCoordAttrib, 1);
42         }
43         fAttribs.emplace_back("fillBounds", kFloat4_GrVertexAttribType, SkSLType::kFloat4);
44         if (fUsesLocalCoords) {
45             fAttribs.emplace_back("affineMatrix", kFloat4_GrVertexAttribType, SkSLType::kFloat4);
46             fAttribs.emplace_back("translate", kFloat2_GrVertexAttribType, SkSLType::kFloat2);
47         }
48         SkASSERT(fAttribs.size() == this->colorAttribIdx());
49         fAttribs.emplace_back("color", kFloat4_GrVertexAttribType, SkSLType::kHalf4);
50         fAtlasHelper->appendInstanceAttribs(&fAttribs);
51         SkASSERT(fAttribs.size() <= kMaxInstanceAttribs);
52         this->setInstanceAttributesWithImplicitOffsets(fAttribs.data(), fAttribs.size());
53         this->setTextureSamplerCnt(1);
54     }
55 
56 private:
57     class Impl;
58 
colorAttribIdx() const59     int colorAttribIdx() const { return fUsesLocalCoords ? 3 : 1; }
name() const60     const char* name() const override { return "DrawAtlasPathShader"; }
addToKey(const GrShaderCaps &,skgpu::KeyBuilder * b) const61     void addToKey(const GrShaderCaps&, skgpu::KeyBuilder* b) const override {
62         b->addBits(1, fUsesLocalCoords, "localCoords");
63         fAtlasHelper->getKeyBits(b);
64     }
onTextureSampler(int) const65     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:
setData(const GrGLSLProgramDataManager & pdman,const GrShaderCaps &,const GrGeometryProcessor & geomProc)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:
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)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->fVertexIDSupport) {
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(SkSLType::kFloat2, "devCoord");
99 
100         if (shader.fUsesLocalCoords) {
101             args.fVertBuilder->codeAppendf(R"(
102             float2x2 M = float2x2(affineMatrix.xy, affineMatrix.zw);
103             float2 localCoord = inverse(M) * (devCoord - translate);)");
104             gpArgs->fLocalCoordVar.set(SkSLType::kFloat2, "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 = &caps;
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,
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 SKGPU_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->makeVertexWriter(
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()->fVertexIDSupport) {
212         constexpr static SkPoint kUnitQuad[4] = {{0,0}, {0,1}, {1,0}, {1,1}};
213 
214         SKGPU_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