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: |
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: |
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 | |
57 | class 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 | |
108 | GrGLSLPrimitiveProcessor* DrawAtlasPathShader::createGLSLInstance(const GrShaderCaps&) const { |
109 | return new Impl(); |
110 | } |
111 | |
112 | } // namespace |
113 | |
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 | |
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) ? ©->fNext : that->fInstanceTail; |
139 | fInstanceCount += that->fInstanceCount; |
140 | return CombineResult::kMerged; |
141 | } |
142 | |
143 | void GrDrawAtlasPathOp::onPrePrepare(GrRecordingContext*, |
144 | const GrSurfaceProxyView* writeView, |
145 | GrAppliedClip*, |
146 | const GrXferProcessor::DstProxyView&) { |
147 | } |
148 | |
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 | |
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->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 | |