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/tessellate/GrDrawAtlasPathOp.h"
9 
10 #include "src/gpu/GrOpFlushState.h"
11 #include "src/gpu/GrOpsRenderPass.h"
12 #include "src/gpu/GrProgramInfo.h"
13 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
14 #include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
15 #include "src/gpu/glsl/GrGLSLVarying.h"
16 #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
17 
18 namespace {
19 
20 constexpr static GrGeometryProcessor::Attribute kInstanceAttribs[] = {
21         {"devibounds", kInt4_GrVertexAttribType, kInt4_GrSLType},
22         {"dev_to_atlas_offset", kInt2_GrVertexAttribType, kInt2_GrSLType},
23         {"color", kFloat4_GrVertexAttribType, kHalf4_GrSLType},
24         {"viewmatrix_scaleskew", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
25         {"viewmatrix_trans", kFloat2_GrVertexAttribType, kFloat2_GrSLType}};
26 
27 class DrawAtlasPathShader : public GrGeometryProcessor {
28 public:
DrawAtlasPathShader(const GrTextureProxy * atlasProxy,GrSwizzle swizzle,bool usesLocalCoords)29     DrawAtlasPathShader(const GrTextureProxy* atlasProxy, GrSwizzle swizzle, bool usesLocalCoords)
30             : GrGeometryProcessor(kDrawAtlasPathShader_ClassID)
31             , fAtlasAccess(GrSamplerState::Filter::kNearest, atlasProxy->backendFormat(), swizzle)
32             , fAtlasDimensions(atlasProxy->backingStoreDimensions())
33             , fUsesLocalCoords(usesLocalCoords) {
34         int numInstanceAttribs = SK_ARRAY_COUNT(kInstanceAttribs);
35         if (!fUsesLocalCoords) {
36             numInstanceAttribs -= 2;
37         }
38         this->setInstanceAttributes(kInstanceAttribs, numInstanceAttribs);
39         this->setTextureSamplerCnt(1);
40     }
41 
42 private:
name() const43     const char* name() const override { return "DrawAtlasPathShader"; }
getGLSLProcessorKey(const GrShaderCaps &,GrProcessorKeyBuilder * b) const44     void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
45         b->add32(fUsesLocalCoords);
46     }
onTextureSampler(int) const47     const TextureSampler& onTextureSampler(int) const override { return fAtlasAccess; }
48     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
49 
50     const TextureSampler fAtlasAccess;
51     const SkISize fAtlasDimensions;
52     const bool fUsesLocalCoords;
53 
54     class Impl;
55 };
56 
57 class DrawAtlasPathShader::Impl : public GrGLSLGeometryProcessor {
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)58     void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
59         const auto& shader = args.fGP.cast<DrawAtlasPathShader>();
60         args.fVaryingHandler->emitAttributes(shader);
61 
62         GrGLSLVarying atlasCoord(kFloat2_GrSLType);
63         args.fVaryingHandler->addVarying("atlascoord", &atlasCoord);
64 
65         GrGLSLVarying color(kHalf4_GrSLType);
66         args.fVaryingHandler->addPassThroughAttribute(
67                 kInstanceAttribs[2], args.fOutputColor,
68                 GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
69 
70         const char* atlasAdjust;
71         fAtlasAdjustUniform = args.fUniformHandler->addUniform(
72                 kVertex_GrShaderFlag, kFloat2_GrSLType, "atlas_adjust", &atlasAdjust);
73 
74         args.fVertBuilder->codeAppendf(R"(
75                 float2 T = float2(sk_VertexID & 1, sk_VertexID >> 1);
76                 float2 devcoord = mix(float2(devibounds.xy), float2(devibounds.zw), T);
77                 float2 atlascoord = devcoord + float2(dev_to_atlas_offset);
78                 %s = atlascoord * %s;)",
79                 atlasCoord.vsOut(), atlasAdjust);
80 
81         gpArgs->fPositionVar.set(kFloat2_GrSLType, "devcoord");
82 
83         GrShaderVar localCoord = gpArgs->fPositionVar;
84         if (shader.fUsesLocalCoords) {
85             args.fVertBuilder->codeAppendf(R"(
86                     float2x2 M = float2x2(viewmatrix_scaleskew);
87                     float2 localcoord = inverse(M) * (devcoord - viewmatrix_trans);)");
88             localCoord.set(kFloat2_GrSLType, "localcoord");
89         }
90         this->emitTransforms(args.fVertBuilder, args.fVaryingHandler, args.fUniformHandler,
91                              localCoord, args.fFPCoordTransformHandler);
92 
93         args.fFragBuilder->codeAppendf("%s = ", args.fOutputCoverage);
94         args.fFragBuilder->appendTextureLookup(args.fTexSamplers[0], atlasCoord.fsIn());
95         args.fFragBuilder->codeAppendf(".aaaa;");
96     }
97 
setData(const GrGLSLProgramDataManager & pdman,const GrPrimitiveProcessor & primProc,const CoordTransformRange & transformRange)98     void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& primProc,
99                  const CoordTransformRange& transformRange) override {
100         const SkISize& dimensions = primProc.cast<DrawAtlasPathShader>().fAtlasDimensions;
101         pdman.set2f(fAtlasAdjustUniform, 1.f / dimensions.width(), 1.f / dimensions.height());
102         this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange);
103     }
104 
105     GrGLSLUniformHandler::UniformHandle fAtlasAdjustUniform;
106 };
107 
createGLSLInstance(const GrShaderCaps &) const108 GrGLSLPrimitiveProcessor* DrawAtlasPathShader::createGLSLInstance(const GrShaderCaps&) const {
109     return new Impl();
110 }
111 
112 }  // namespace
113 
finalize(const GrCaps & caps,const GrAppliedClip * clip,bool hasMixedSampledCoverage,GrClampType clampType)114 GrProcessorSet::Analysis GrDrawAtlasPathOp::finalize(const GrCaps& caps, const GrAppliedClip* clip,
115                                                      bool hasMixedSampledCoverage,
116                                                      GrClampType clampType) {
117     const GrProcessorSet::Analysis& analysis = fProcessors.finalize(
118             fInstanceList.fInstance.fColor, GrProcessorAnalysisCoverage::kSingleChannel, clip,
119             &GrUserStencilSettings::kUnused, hasMixedSampledCoverage, caps, clampType,
120             &fInstanceList.fInstance.fColor);
121     fUsesLocalCoords = analysis.usesLocalCoords();
122     return analysis;
123 }
124 
onCombineIfPossible(GrOp * op,GrRecordingContext::Arenas * arenas,const GrCaps &)125 GrOp::CombineResult GrDrawAtlasPathOp::onCombineIfPossible(
126         GrOp* op, GrRecordingContext::Arenas* arenas, const GrCaps&) {
127     auto* that = op->cast<GrDrawAtlasPathOp>();
128     SkASSERT(fAtlasProxy == that->fAtlasProxy);
129     SkASSERT(fEnableHWAA == that->fEnableHWAA);
130 
131     if (fProcessors != that->fProcessors) {
132         return CombineResult::kCannotCombine;
133     }
134 
135     SkASSERT(fUsesLocalCoords == that->fUsesLocalCoords);
136     auto* copy = arenas->recordTimeAllocator()->make<InstanceList>(that->fInstanceList);
137     *fInstanceTail = copy;
138     fInstanceTail = (!copy->fNext) ? &copy->fNext : that->fInstanceTail;
139     fInstanceCount += that->fInstanceCount;
140     return CombineResult::kMerged;
141 }
142 
onPrePrepare(GrRecordingContext *,const GrSurfaceProxyView * outputView,GrAppliedClip *,const GrXferProcessor::DstProxyView &)143 void GrDrawAtlasPathOp::onPrePrepare(GrRecordingContext*,
144                                      const GrSurfaceProxyView* outputView,
145                                      GrAppliedClip*,
146                                      const GrXferProcessor::DstProxyView&) {
147 }
148 
onPrepare(GrOpFlushState * state)149 void GrDrawAtlasPathOp::onPrepare(GrOpFlushState* state) {
150     size_t instanceStride = Instance::Stride(fUsesLocalCoords);
151     if (char* instanceData = (char*)state->makeVertexSpace(
152             instanceStride, fInstanceCount, &fInstanceBuffer, &fBaseInstance)) {
153         SkDEBUGCODE(char* end = instanceData + fInstanceCount * instanceStride);
154         for (const InstanceList* list = &fInstanceList; list; list = list->fNext) {
155             memcpy(instanceData, &list->fInstance, instanceStride);
156             instanceData += instanceStride;
157         }
158         SkASSERT(instanceData == end);
159     }
160 }
161 
onExecute(GrOpFlushState * state,const SkRect & chainBounds)162 void GrDrawAtlasPathOp::onExecute(GrOpFlushState* state, const SkRect& chainBounds) {
163     SkASSERT(fAtlasProxy->isInstantiated());
164 
165     GrPipeline::InitArgs initArgs;
166     if (fEnableHWAA) {
167         initArgs.fInputFlags |= GrPipeline::InputFlags::kHWAntialias;
168     }
169     initArgs.fCaps = &state->caps();
170     initArgs.fDstProxyView = state->drawOpArgs().dstProxyView();
171     initArgs.fWriteSwizzle = state->drawOpArgs().writeSwizzle();
172     GrPipeline pipeline(initArgs, std::move(fProcessors), state->detachAppliedClip());
173 
174     GrSwizzle swizzle = state->caps().getReadSwizzle(fAtlasProxy->backendFormat(),
175                                                      GrColorType::kAlpha_8);
176 
177     DrawAtlasPathShader shader(fAtlasProxy.get(), swizzle, fUsesLocalCoords);
178     SkASSERT(shader.instanceStride() == Instance::Stride(fUsesLocalCoords));
179 
180     GrProgramInfo programInfo(state->proxy()->numSamples(), state->proxy()->numStencilSamples(),
181                               state->proxy()->backendFormat(), state->outputView()->origin(),
182                               &pipeline, &shader, GrPrimitiveType::kTriangleStrip);
183 
184     state->bindPipelineAndScissorClip(programInfo, this->bounds());
185     state->bindTextures(shader, *fAtlasProxy, pipeline);
186     state->bindBuffers(nullptr, fInstanceBuffer.get(), nullptr);
187     state->drawInstanced(fInstanceCount, fBaseInstance, 4, 0);
188 }
189