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
18namespace {
19
20constexpr 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
27class DrawAtlasPathShader : public GrGeometryProcessor {
28public:
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
42private:
43 const char* name() const override { return "DrawAtlasPathShader"; }
44 void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
45 b->add32(fUsesLocalCoords);
46 }
47 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
57class DrawAtlasPathShader::Impl : public GrGLSLGeometryProcessor {
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 nullptr, 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
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
108GrGLSLPrimitiveProcessor* DrawAtlasPathShader::createGLSLInstance(const GrShaderCaps&) const {
109 return new Impl();
110}
111
112} // namespace
113
114GrProcessorSet::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
125GrOp::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
143void GrDrawAtlasPathOp::onPrePrepare(GrRecordingContext*,
144 const GrSurfaceProxyView* writeView,
145 GrAppliedClip*,
146 const GrXferProcessor::DstProxyView&) {
147}
148
149void 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
162void 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->writeView()->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