1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2020 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/gpu/ops/DrawAtlasPathOp.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "src/gpu/BufferWriter.h"
11cb93a386Sopenharmony_ci#include "src/gpu/GrGeometryProcessor.h"
12cb93a386Sopenharmony_ci#include "src/gpu/GrOpFlushState.h"
13cb93a386Sopenharmony_ci#include "src/gpu/GrOpsRenderPass.h"
14cb93a386Sopenharmony_ci#include "src/gpu/GrProgramInfo.h"
15cb93a386Sopenharmony_ci#include "src/gpu/GrResourceProvider.h"
16cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
17cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLVarying.h"
18cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
19cb93a386Sopenharmony_ci
20cb93a386Sopenharmony_cinamespace {
21cb93a386Sopenharmony_ci
22cb93a386Sopenharmony_ciclass DrawAtlasPathShader : public GrGeometryProcessor {
23cb93a386Sopenharmony_cipublic:
24cb93a386Sopenharmony_ci    DrawAtlasPathShader(bool usesLocalCoords,
25cb93a386Sopenharmony_ci                        const skgpu::v1::AtlasInstancedHelper* atlasHelper,
26cb93a386Sopenharmony_ci                        const GrShaderCaps& shaderCaps)
27cb93a386Sopenharmony_ci            : GrGeometryProcessor(kDrawAtlasPathShader_ClassID)
28cb93a386Sopenharmony_ci            , fUsesLocalCoords(usesLocalCoords)
29cb93a386Sopenharmony_ci            , fAtlasHelper(atlasHelper)
30cb93a386Sopenharmony_ci            , fAtlasAccess(GrSamplerState::Filter::kNearest,
31cb93a386Sopenharmony_ci                           fAtlasHelper->proxy()->backendFormat(),
32cb93a386Sopenharmony_ci                           fAtlasHelper->atlasSwizzle()) {
33cb93a386Sopenharmony_ci        if (!shaderCaps.vertexIDSupport()) {
34cb93a386Sopenharmony_ci            constexpr static Attribute kUnitCoordAttrib(
35cb93a386Sopenharmony_ci                    "unitCoord", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
36cb93a386Sopenharmony_ci            this->setVertexAttributes(&kUnitCoordAttrib, 1);
37cb93a386Sopenharmony_ci        }
38cb93a386Sopenharmony_ci        fAttribs.emplace_back("fillBounds", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
39cb93a386Sopenharmony_ci        if (fUsesLocalCoords) {
40cb93a386Sopenharmony_ci            fAttribs.emplace_back("affineMatrix", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
41cb93a386Sopenharmony_ci            fAttribs.emplace_back("translate", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
42cb93a386Sopenharmony_ci        }
43cb93a386Sopenharmony_ci        SkASSERT(fAttribs.count() == this->colorAttribIdx());
44cb93a386Sopenharmony_ci        fAttribs.emplace_back("color", kFloat4_GrVertexAttribType, kHalf4_GrSLType);
45cb93a386Sopenharmony_ci        fAtlasHelper->appendInstanceAttribs(&fAttribs);
46cb93a386Sopenharmony_ci        SkASSERT(fAttribs.count() <= kMaxInstanceAttribs);
47cb93a386Sopenharmony_ci        this->setInstanceAttributes(fAttribs.data(), fAttribs.count());
48cb93a386Sopenharmony_ci        this->setTextureSamplerCnt(1);
49cb93a386Sopenharmony_ci    }
50cb93a386Sopenharmony_ci
51cb93a386Sopenharmony_ciprivate:
52cb93a386Sopenharmony_ci    class Impl;
53cb93a386Sopenharmony_ci
54cb93a386Sopenharmony_ci    int colorAttribIdx() const { return fUsesLocalCoords ? 3 : 1; }
55cb93a386Sopenharmony_ci    const char* name() const override { return "DrawAtlasPathShader"; }
56cb93a386Sopenharmony_ci    SkString getShaderDfxInfo() const override {
57cb93a386Sopenharmony_ci        SkString format;
58cb93a386Sopenharmony_ci        format.printf("ShaderDfx_DrawAtlasPathShader_%d", fUsesLocalCoords);
59cb93a386Sopenharmony_ci        return format;
60cb93a386Sopenharmony_ci    }
61cb93a386Sopenharmony_ci    void addToKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
62cb93a386Sopenharmony_ci        b->addBits(1, fUsesLocalCoords, "localCoords");
63cb93a386Sopenharmony_ci        fAtlasHelper->getKeyBits(b);
64cb93a386Sopenharmony_ci    }
65cb93a386Sopenharmony_ci    const TextureSampler& onTextureSampler(int) const override { return fAtlasAccess; }
66cb93a386Sopenharmony_ci    std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const override;
67cb93a386Sopenharmony_ci
68cb93a386Sopenharmony_ci    const bool fUsesLocalCoords;
69cb93a386Sopenharmony_ci    const skgpu::v1::AtlasInstancedHelper* const fAtlasHelper;
70cb93a386Sopenharmony_ci    TextureSampler fAtlasAccess;
71cb93a386Sopenharmony_ci    constexpr static int kMaxInstanceAttribs = 6;
72cb93a386Sopenharmony_ci    SkSTArray<kMaxInstanceAttribs, GrGeometryProcessor::Attribute> fAttribs;
73cb93a386Sopenharmony_ci};
74cb93a386Sopenharmony_ci
75cb93a386Sopenharmony_ciclass DrawAtlasPathShader::Impl : public ProgramImpl {
76cb93a386Sopenharmony_cipublic:
77cb93a386Sopenharmony_ci    void setData(const GrGLSLProgramDataManager& pdman,
78cb93a386Sopenharmony_ci                 const GrShaderCaps&,
79cb93a386Sopenharmony_ci                 const GrGeometryProcessor& geomProc) override {
80cb93a386Sopenharmony_ci        auto* atlasHelper = geomProc.cast<DrawAtlasPathShader>().fAtlasHelper;
81cb93a386Sopenharmony_ci        atlasHelper->setUniformData(pdman, fAtlasAdjustUniform);
82cb93a386Sopenharmony_ci    }
83cb93a386Sopenharmony_ci
84cb93a386Sopenharmony_ciprivate:
85cb93a386Sopenharmony_ci    void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
86cb93a386Sopenharmony_ci        const auto& shader = args.fGeomProc.cast<DrawAtlasPathShader>();
87cb93a386Sopenharmony_ci        args.fVaryingHandler->emitAttributes(shader);
88cb93a386Sopenharmony_ci
89cb93a386Sopenharmony_ci        if (args.fShaderCaps->vertexIDSupport()) {
90cb93a386Sopenharmony_ci            // If we don't have sk_VertexID support then "unitCoord" already came in as a vertex
91cb93a386Sopenharmony_ci            // attrib.
92cb93a386Sopenharmony_ci            args.fVertBuilder->codeAppendf(R"(
93cb93a386Sopenharmony_ci            float2 unitCoord = float2(sk_VertexID & 1, sk_VertexID >> 1);)");
94cb93a386Sopenharmony_ci        }
95cb93a386Sopenharmony_ci
96cb93a386Sopenharmony_ci        args.fVertBuilder->codeAppendf(R"(
97cb93a386Sopenharmony_ci        float2 devCoord = mix(fillBounds.xy, fillBounds.zw, unitCoord);)");
98cb93a386Sopenharmony_ci        gpArgs->fPositionVar.set(kFloat2_GrSLType, "devCoord");
99cb93a386Sopenharmony_ci
100cb93a386Sopenharmony_ci        if (shader.fUsesLocalCoords) {
101cb93a386Sopenharmony_ci            args.fVertBuilder->codeAppendf(R"(
102cb93a386Sopenharmony_ci            float2x2 M = float2x2(affineMatrix);
103cb93a386Sopenharmony_ci            float2 localCoord = inverse(M) * (devCoord - translate);)");
104cb93a386Sopenharmony_ci            gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localCoord");
105cb93a386Sopenharmony_ci        }
106cb93a386Sopenharmony_ci
107cb93a386Sopenharmony_ci        args.fFragBuilder->codeAppendf("half4 %s = half4(1);", args.fOutputCoverage);
108cb93a386Sopenharmony_ci        shader.fAtlasHelper->injectShaderCode(args, gpArgs->fPositionVar, &fAtlasAdjustUniform);
109cb93a386Sopenharmony_ci
110cb93a386Sopenharmony_ci        args.fFragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
111cb93a386Sopenharmony_ci        args.fVaryingHandler->addPassThroughAttribute(
112cb93a386Sopenharmony_ci                shader.fAttribs[shader.colorAttribIdx()].asShaderVar(),
113cb93a386Sopenharmony_ci                args.fOutputColor,
114cb93a386Sopenharmony_ci                GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
115cb93a386Sopenharmony_ci    }
116cb93a386Sopenharmony_ci
117cb93a386Sopenharmony_ci    GrGLSLUniformHandler::UniformHandle fAtlasAdjustUniform;
118cb93a386Sopenharmony_ci};
119cb93a386Sopenharmony_ci
120cb93a386Sopenharmony_cistd::unique_ptr<GrGeometryProcessor::ProgramImpl> DrawAtlasPathShader::makeProgramImpl(
121cb93a386Sopenharmony_ci        const GrShaderCaps&) const {
122cb93a386Sopenharmony_ci    return std::make_unique<Impl>();
123cb93a386Sopenharmony_ci}
124cb93a386Sopenharmony_ci
125cb93a386Sopenharmony_ci}  // anonymous namespace
126cb93a386Sopenharmony_ci
127cb93a386Sopenharmony_cinamespace skgpu::v1 {
128cb93a386Sopenharmony_ci
129cb93a386Sopenharmony_ciGrProcessorSet::Analysis DrawAtlasPathOp::finalize(const GrCaps& caps, const GrAppliedClip* clip,
130cb93a386Sopenharmony_ci                                                   GrClampType clampType) {
131cb93a386Sopenharmony_ci    const GrProcessorSet::Analysis& analysis = fProcessors.finalize(
132cb93a386Sopenharmony_ci            fHeadInstance->fColor, GrProcessorAnalysisCoverage::kSingleChannel, clip,
133cb93a386Sopenharmony_ci            &GrUserStencilSettings::kUnused, caps, clampType, &fHeadInstance->fColor);
134cb93a386Sopenharmony_ci    fUsesLocalCoords = analysis.usesLocalCoords();
135cb93a386Sopenharmony_ci    return analysis;
136cb93a386Sopenharmony_ci}
137cb93a386Sopenharmony_ci
138cb93a386Sopenharmony_ciGrOp::CombineResult DrawAtlasPathOp::onCombineIfPossible(GrOp* op, SkArenaAlloc*, const GrCaps&) {
139cb93a386Sopenharmony_ci    auto that = op->cast<DrawAtlasPathOp>();
140cb93a386Sopenharmony_ci
141cb93a386Sopenharmony_ci    if (!fAtlasHelper.isCompatible(that->fAtlasHelper) ||
142cb93a386Sopenharmony_ci        fProcessors != that->fProcessors) {
143cb93a386Sopenharmony_ci        return CombineResult::kCannotCombine;
144cb93a386Sopenharmony_ci    }
145cb93a386Sopenharmony_ci
146cb93a386Sopenharmony_ci    SkASSERT(fUsesLocalCoords == that->fUsesLocalCoords);
147cb93a386Sopenharmony_ci    *fTailInstance = that->fHeadInstance;
148cb93a386Sopenharmony_ci    fTailInstance = that->fTailInstance;
149cb93a386Sopenharmony_ci    fInstanceCount += that->fInstanceCount;
150cb93a386Sopenharmony_ci    return CombineResult::kMerged;
151cb93a386Sopenharmony_ci}
152cb93a386Sopenharmony_ci
153cb93a386Sopenharmony_civoid DrawAtlasPathOp::prepareProgram(const GrCaps& caps, SkArenaAlloc* arena,
154cb93a386Sopenharmony_ci                                     const GrSurfaceProxyView& writeView, bool usesMSAASurface,
155cb93a386Sopenharmony_ci                                     GrAppliedClip&& appliedClip,
156cb93a386Sopenharmony_ci                                     const GrDstProxyView& dstProxyView,
157cb93a386Sopenharmony_ci                                     GrXferBarrierFlags renderPassXferBarriers,
158cb93a386Sopenharmony_ci                                     GrLoadOp colorLoadOp) {
159cb93a386Sopenharmony_ci    SkASSERT(!fProgram);
160cb93a386Sopenharmony_ci    GrPipeline::InitArgs initArgs;
161cb93a386Sopenharmony_ci    initArgs.fCaps = &caps;
162cb93a386Sopenharmony_ci    initArgs.fDstProxyView = dstProxyView;
163cb93a386Sopenharmony_ci    initArgs.fWriteSwizzle = writeView.swizzle();
164cb93a386Sopenharmony_ci    auto pipeline = arena->make<GrPipeline>(initArgs, std::move(fProcessors),
165cb93a386Sopenharmony_ci                                            std::move(appliedClip));
166cb93a386Sopenharmony_ci    auto shader = arena->make<DrawAtlasPathShader>(fUsesLocalCoords, &fAtlasHelper,
167cb93a386Sopenharmony_ci                                                   *caps.shaderCaps());
168cb93a386Sopenharmony_ci    fProgram = arena->make<GrProgramInfo>(caps, writeView, usesMSAASurface, pipeline,
169cb93a386Sopenharmony_ci                                          &GrUserStencilSettings::kUnused, shader,
170cb93a386Sopenharmony_ci                                          GrPrimitiveType::kTriangleStrip, 0,
171cb93a386Sopenharmony_ci                                          renderPassXferBarriers, colorLoadOp);
172cb93a386Sopenharmony_ci}
173cb93a386Sopenharmony_ci
174cb93a386Sopenharmony_civoid DrawAtlasPathOp::onPrePrepare(GrRecordingContext* rContext,
175cb93a386Sopenharmony_ci                                   const GrSurfaceProxyView& writeView,
176cb93a386Sopenharmony_ci                                   GrAppliedClip* appliedClip, const GrDstProxyView& dstProxyView,
177cb93a386Sopenharmony_ci                                   GrXferBarrierFlags renderPassXferBarriers,
178cb93a386Sopenharmony_ci                                   GrLoadOp colorLoadOp) {
179cb93a386Sopenharmony_ci    // DMSAA is not supported on DDL.
180cb93a386Sopenharmony_ci    bool usesMSAASurface = writeView.asRenderTargetProxy()->numSamples() > 1;
181cb93a386Sopenharmony_ci    this->prepareProgram(*rContext->priv().caps(), rContext->priv().recordTimeAllocator(),
182cb93a386Sopenharmony_ci                         writeView, usesMSAASurface, std::move(*appliedClip), dstProxyView,
183cb93a386Sopenharmony_ci                         renderPassXferBarriers, colorLoadOp);
184cb93a386Sopenharmony_ci    SkASSERT(fProgram);
185cb93a386Sopenharmony_ci    rContext->priv().recordProgramInfo(fProgram);
186cb93a386Sopenharmony_ci}
187cb93a386Sopenharmony_ci
188cb93a386Sopenharmony_ciGR_DECLARE_STATIC_UNIQUE_KEY(gUnitQuadBufferKey);
189cb93a386Sopenharmony_ci
190cb93a386Sopenharmony_civoid DrawAtlasPathOp::onPrepare(GrOpFlushState* flushState) {
191cb93a386Sopenharmony_ci    if (!fProgram) {
192cb93a386Sopenharmony_ci        this->prepareProgram(flushState->caps(), flushState->allocator(), flushState->writeView(),
193cb93a386Sopenharmony_ci                             flushState->usesMSAASurface(), flushState->detachAppliedClip(),
194cb93a386Sopenharmony_ci                             flushState->dstProxyView(), flushState->renderPassBarriers(),
195cb93a386Sopenharmony_ci                             flushState->colorLoadOp());
196cb93a386Sopenharmony_ci        SkASSERT(fProgram);
197cb93a386Sopenharmony_ci    }
198cb93a386Sopenharmony_ci
199cb93a386Sopenharmony_ci    if (VertexWriter instanceWriter = flushState->makeVertexSpace(
200cb93a386Sopenharmony_ci                fProgram->geomProc().instanceStride(), fInstanceCount, &fInstanceBuffer,
201cb93a386Sopenharmony_ci                &fBaseInstance)) {
202cb93a386Sopenharmony_ci        for (const Instance* i = fHeadInstance; i; i = i->fNext) {
203cb93a386Sopenharmony_ci            instanceWriter << SkRect::Make(i->fFillBounds)
204cb93a386Sopenharmony_ci                           << VertexWriter::If(fUsesLocalCoords,
205cb93a386Sopenharmony_ci                                               i->fLocalToDeviceIfUsingLocalCoords)
206cb93a386Sopenharmony_ci                           << i->fColor;
207cb93a386Sopenharmony_ci            fAtlasHelper.writeInstanceData(&instanceWriter, &i->fAtlasInstance);
208cb93a386Sopenharmony_ci        }
209cb93a386Sopenharmony_ci    }
210cb93a386Sopenharmony_ci
211cb93a386Sopenharmony_ci    if (!flushState->caps().shaderCaps()->vertexIDSupport()) {
212cb93a386Sopenharmony_ci        constexpr static SkPoint kUnitQuad[4] = {{0,0}, {0,1}, {1,0}, {1,1}};
213cb93a386Sopenharmony_ci
214cb93a386Sopenharmony_ci        GR_DEFINE_STATIC_UNIQUE_KEY(gUnitQuadBufferKey);
215cb93a386Sopenharmony_ci
216cb93a386Sopenharmony_ci        fVertexBufferIfNoIDSupport = flushState->resourceProvider()->findOrMakeStaticBuffer(
217cb93a386Sopenharmony_ci                GrGpuBufferType::kVertex, sizeof(kUnitQuad), kUnitQuad, gUnitQuadBufferKey);
218cb93a386Sopenharmony_ci    }
219cb93a386Sopenharmony_ci}
220cb93a386Sopenharmony_ci
221cb93a386Sopenharmony_civoid DrawAtlasPathOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
222cb93a386Sopenharmony_ci    if (fProgram->geomProc().hasVertexAttributes() && !fVertexBufferIfNoIDSupport) {
223cb93a386Sopenharmony_ci        return;
224cb93a386Sopenharmony_ci    }
225cb93a386Sopenharmony_ci    flushState->bindPipelineAndScissorClip(*fProgram, this->bounds());
226cb93a386Sopenharmony_ci    flushState->bindTextures(fProgram->geomProc(), *fAtlasHelper.proxy(), fProgram->pipeline());
227cb93a386Sopenharmony_ci    flushState->bindBuffers(nullptr, std::move(fInstanceBuffer), fVertexBufferIfNoIDSupport);
228cb93a386Sopenharmony_ci    flushState->drawInstanced(fInstanceCount, fBaseInstance, 4, 0);
229cb93a386Sopenharmony_ci}
230cb93a386Sopenharmony_ci
231cb93a386Sopenharmony_ci} // namespace skgpu::v1
232