• 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/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 = &caps;
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