xref: /aosp_15_r20/external/skia/src/gpu/graphite/ContextUtils.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2021 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ContextUtils.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/BlendFormula.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Caps.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/KeyContext.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/PaintParams.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/RecorderPriv.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/RenderPassDesc.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Renderer.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ShaderCodeDictionary.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/UniformManager.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/UniquePaintParamsID.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/compute/ComputeStep.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/geom/Geometry.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/SkSLString.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/SkSLUtil.h"
24*c8dee2aaSAndroid Build Coastguard Worker 
25*c8dee2aaSAndroid Build Coastguard Worker #include <string>
26*c8dee2aaSAndroid Build Coastguard Worker 
27*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite {
28*c8dee2aaSAndroid Build Coastguard Worker 
ExtractPaintData(Recorder * recorder,PipelineDataGatherer * gatherer,PaintParamsKeyBuilder * builder,const Layout layout,const SkM44 & local2Dev,const PaintParams & p,const Geometry & geometry,const SkColorInfo & targetColorInfo)29*c8dee2aaSAndroid Build Coastguard Worker UniquePaintParamsID ExtractPaintData(Recorder* recorder,
30*c8dee2aaSAndroid Build Coastguard Worker                                      PipelineDataGatherer* gatherer,
31*c8dee2aaSAndroid Build Coastguard Worker                                      PaintParamsKeyBuilder* builder,
32*c8dee2aaSAndroid Build Coastguard Worker                                      const Layout layout,
33*c8dee2aaSAndroid Build Coastguard Worker                                      const SkM44& local2Dev,
34*c8dee2aaSAndroid Build Coastguard Worker                                      const PaintParams& p,
35*c8dee2aaSAndroid Build Coastguard Worker                                      const Geometry& geometry,
36*c8dee2aaSAndroid Build Coastguard Worker                                      const SkColorInfo& targetColorInfo) {
37*c8dee2aaSAndroid Build Coastguard Worker     SkDEBUGCODE(builder->checkReset());
38*c8dee2aaSAndroid Build Coastguard Worker 
39*c8dee2aaSAndroid Build Coastguard Worker     gatherer->resetWithNewLayout(layout);
40*c8dee2aaSAndroid Build Coastguard Worker 
41*c8dee2aaSAndroid Build Coastguard Worker     KeyContext keyContext(recorder,
42*c8dee2aaSAndroid Build Coastguard Worker                           local2Dev,
43*c8dee2aaSAndroid Build Coastguard Worker                           targetColorInfo,
44*c8dee2aaSAndroid Build Coastguard Worker                           geometry.isShape() || geometry.isEdgeAAQuad()
45*c8dee2aaSAndroid Build Coastguard Worker                                   ? KeyContext::OptimizeSampling::kYes
46*c8dee2aaSAndroid Build Coastguard Worker                                   : KeyContext::OptimizeSampling::kNo,
47*c8dee2aaSAndroid Build Coastguard Worker                           p.color());
48*c8dee2aaSAndroid Build Coastguard Worker     p.toKey(keyContext, builder, gatherer);
49*c8dee2aaSAndroid Build Coastguard Worker 
50*c8dee2aaSAndroid Build Coastguard Worker     return recorder->priv().shaderCodeDictionary()->findOrCreate(builder);
51*c8dee2aaSAndroid Build Coastguard Worker }
52*c8dee2aaSAndroid Build Coastguard Worker 
GetDstReadRequirement(const Caps * caps,std::optional<SkBlendMode> blendMode,Coverage coverage)53*c8dee2aaSAndroid Build Coastguard Worker DstReadRequirement GetDstReadRequirement(const Caps* caps,
54*c8dee2aaSAndroid Build Coastguard Worker                                          std::optional<SkBlendMode> blendMode,
55*c8dee2aaSAndroid Build Coastguard Worker                                          Coverage coverage) {
56*c8dee2aaSAndroid Build Coastguard Worker     // If the blend mode is absent, this is assumed to be for a runtime blender, for which we always
57*c8dee2aaSAndroid Build Coastguard Worker     // do a dst read.
58*c8dee2aaSAndroid Build Coastguard Worker     // If the blend mode is plus, always do in-shader blending since we may be drawing to an
59*c8dee2aaSAndroid Build Coastguard Worker     // unsaturated surface (e.g. F16) and we don't want to let the hardware clamp the color output
60*c8dee2aaSAndroid Build Coastguard Worker     // in that case. We could check the draw dst properties to only do in-shader blending with plus
61*c8dee2aaSAndroid Build Coastguard Worker     // when necessary, but we can't detect that during shader precompilation.
62*c8dee2aaSAndroid Build Coastguard Worker     if (!blendMode || *blendMode > SkBlendMode::kLastCoeffMode ||
63*c8dee2aaSAndroid Build Coastguard Worker         *blendMode == SkBlendMode::kPlus) {
64*c8dee2aaSAndroid Build Coastguard Worker         return caps->getDstReadRequirement();
65*c8dee2aaSAndroid Build Coastguard Worker     }
66*c8dee2aaSAndroid Build Coastguard Worker 
67*c8dee2aaSAndroid Build Coastguard Worker     const bool isLCD = coverage == Coverage::kLCD;
68*c8dee2aaSAndroid Build Coastguard Worker     const bool hasCoverage = coverage != Coverage::kNone;
69*c8dee2aaSAndroid Build Coastguard Worker     BlendFormula blendFormula = isLCD ? skgpu::GetLCDBlendFormula(*blendMode)
70*c8dee2aaSAndroid Build Coastguard Worker                                       : skgpu::GetBlendFormula(false, hasCoverage, *blendMode);
71*c8dee2aaSAndroid Build Coastguard Worker     if ((blendFormula.hasSecondaryOutput() && !caps->shaderCaps()->fDualSourceBlendingSupport) ||
72*c8dee2aaSAndroid Build Coastguard Worker         (coverage == Coverage::kLCD && blendMode != SkBlendMode::kSrcOver)) {
73*c8dee2aaSAndroid Build Coastguard Worker         return caps->getDstReadRequirement();
74*c8dee2aaSAndroid Build Coastguard Worker     }
75*c8dee2aaSAndroid Build Coastguard Worker 
76*c8dee2aaSAndroid Build Coastguard Worker     return DstReadRequirement::kNone;
77*c8dee2aaSAndroid Build Coastguard Worker }
78*c8dee2aaSAndroid Build Coastguard Worker 
CollectIntrinsicUniforms(const Caps * caps,SkIRect viewport,SkIRect dstCopyBounds,UniformManager * uniforms)79*c8dee2aaSAndroid Build Coastguard Worker void CollectIntrinsicUniforms(const Caps* caps,
80*c8dee2aaSAndroid Build Coastguard Worker                               SkIRect viewport,
81*c8dee2aaSAndroid Build Coastguard Worker                               SkIRect dstCopyBounds,
82*c8dee2aaSAndroid Build Coastguard Worker                               UniformManager* uniforms) {
83*c8dee2aaSAndroid Build Coastguard Worker     SkDEBUGCODE(uniforms->setExpectedUniforms(kIntrinsicUniforms, /*isSubstruct=*/false);)
84*c8dee2aaSAndroid Build Coastguard Worker 
85*c8dee2aaSAndroid Build Coastguard Worker     // viewport
86*c8dee2aaSAndroid Build Coastguard Worker     {
87*c8dee2aaSAndroid Build Coastguard Worker         // The vertex shader needs to divide by the dimension and then multiply by 2, so do this
88*c8dee2aaSAndroid Build Coastguard Worker         // once on the CPU. This is because viewport normalization wants to range from -1 to 1, and
89*c8dee2aaSAndroid Build Coastguard Worker         // not 0 to 1. If any other user of the viewport uniform requires the true reciprocal or
90*c8dee2aaSAndroid Build Coastguard Worker         // original dimensions, this can be adjusted.
91*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(!viewport.isEmpty());
92*c8dee2aaSAndroid Build Coastguard Worker         float invTwoW = 2.f / viewport.width();
93*c8dee2aaSAndroid Build Coastguard Worker         float invTwoH = 2.f / viewport.height();
94*c8dee2aaSAndroid Build Coastguard Worker 
95*c8dee2aaSAndroid Build Coastguard Worker         // If the NDC Y axis points up (opposite normal skia convention and the underlying view
96*c8dee2aaSAndroid Build Coastguard Worker         // convention), upload the inverse height as a negative value. See ShaderInfo::Make
97*c8dee2aaSAndroid Build Coastguard Worker         // for how this is used.
98*c8dee2aaSAndroid Build Coastguard Worker         if (!caps->ndcYAxisPointsDown()) {
99*c8dee2aaSAndroid Build Coastguard Worker             invTwoH *= -1.f;
100*c8dee2aaSAndroid Build Coastguard Worker         }
101*c8dee2aaSAndroid Build Coastguard Worker         uniforms->write(SkV4{(float) viewport.left(), (float) viewport.top(), invTwoW, invTwoH});
102*c8dee2aaSAndroid Build Coastguard Worker     }
103*c8dee2aaSAndroid Build Coastguard Worker 
104*c8dee2aaSAndroid Build Coastguard Worker     // dstCopyBounds
105*c8dee2aaSAndroid Build Coastguard Worker     {
106*c8dee2aaSAndroid Build Coastguard Worker         // Unlike viewport, dstCopyBounds can be empty so check for 0 dimensions and set the
107*c8dee2aaSAndroid Build Coastguard Worker         // reciprocal to 0. It is also not doubled since its purpose is to normalize texture coords
108*c8dee2aaSAndroid Build Coastguard Worker         // to 0 to 1, and not -1 to 1.
109*c8dee2aaSAndroid Build Coastguard Worker         int width = dstCopyBounds.width();
110*c8dee2aaSAndroid Build Coastguard Worker         int height = dstCopyBounds.height();
111*c8dee2aaSAndroid Build Coastguard Worker         uniforms->write(SkV4{(float) dstCopyBounds.left(), (float) dstCopyBounds.top(),
112*c8dee2aaSAndroid Build Coastguard Worker                              width ? 1.f / width : 0.f, height ? 1.f / height : 0.f});
113*c8dee2aaSAndroid Build Coastguard Worker     }
114*c8dee2aaSAndroid Build Coastguard Worker 
115*c8dee2aaSAndroid Build Coastguard Worker     SkDEBUGCODE(uniforms->doneWithExpectedUniforms());
116*c8dee2aaSAndroid Build Coastguard Worker }
117*c8dee2aaSAndroid Build Coastguard Worker 
EmitSamplerLayout(const ResourceBindingRequirements & bindingReqs,int * binding)118*c8dee2aaSAndroid Build Coastguard Worker std::string EmitSamplerLayout(const ResourceBindingRequirements& bindingReqs, int* binding) {
119*c8dee2aaSAndroid Build Coastguard Worker     std::string result;
120*c8dee2aaSAndroid Build Coastguard Worker 
121*c8dee2aaSAndroid Build Coastguard Worker     // If fDistinctIndexRanges is false, then texture and sampler indices may clash with other
122*c8dee2aaSAndroid Build Coastguard Worker     // resource indices. Graphite assumes that they will be placed in descriptor set (Vulkan) and
123*c8dee2aaSAndroid Build Coastguard Worker     // bind group (Dawn) index 1.
124*c8dee2aaSAndroid Build Coastguard Worker     const char* distinctIndexRange = bindingReqs.fDistinctIndexRanges ? "" : "set=1, ";
125*c8dee2aaSAndroid Build Coastguard Worker 
126*c8dee2aaSAndroid Build Coastguard Worker     if (bindingReqs.fSeparateTextureAndSamplerBinding) {
127*c8dee2aaSAndroid Build Coastguard Worker         int samplerIndex = (*binding)++;
128*c8dee2aaSAndroid Build Coastguard Worker         int textureIndex = (*binding)++;
129*c8dee2aaSAndroid Build Coastguard Worker         result = SkSL::String::printf("layout(webgpu, %ssampler=%d, texture=%d)",
130*c8dee2aaSAndroid Build Coastguard Worker                                       distinctIndexRange,
131*c8dee2aaSAndroid Build Coastguard Worker                                       samplerIndex,
132*c8dee2aaSAndroid Build Coastguard Worker                                       textureIndex);
133*c8dee2aaSAndroid Build Coastguard Worker     } else {
134*c8dee2aaSAndroid Build Coastguard Worker         int samplerIndex = (*binding)++;
135*c8dee2aaSAndroid Build Coastguard Worker         result = SkSL::String::printf("layout(%sbinding=%d)",
136*c8dee2aaSAndroid Build Coastguard Worker                                       distinctIndexRange,
137*c8dee2aaSAndroid Build Coastguard Worker                                       samplerIndex);
138*c8dee2aaSAndroid Build Coastguard Worker     }
139*c8dee2aaSAndroid Build Coastguard Worker     return result;
140*c8dee2aaSAndroid Build Coastguard Worker }
141*c8dee2aaSAndroid Build Coastguard Worker 
GetPipelineLabel(const ShaderCodeDictionary * dict,const RenderPassDesc & renderPassDesc,const RenderStep * renderStep,UniquePaintParamsID paintID)142*c8dee2aaSAndroid Build Coastguard Worker std::string GetPipelineLabel(const ShaderCodeDictionary* dict,
143*c8dee2aaSAndroid Build Coastguard Worker                              const RenderPassDesc& renderPassDesc,
144*c8dee2aaSAndroid Build Coastguard Worker                              const RenderStep* renderStep,
145*c8dee2aaSAndroid Build Coastguard Worker                              UniquePaintParamsID paintID) {
146*c8dee2aaSAndroid Build Coastguard Worker     std::string label = renderPassDesc.toPipelineLabel().c_str(); // includes the write swizzle
147*c8dee2aaSAndroid Build Coastguard Worker     label += " + ";
148*c8dee2aaSAndroid Build Coastguard Worker     label += renderStep->name();
149*c8dee2aaSAndroid Build Coastguard Worker     label += " + ";
150*c8dee2aaSAndroid Build Coastguard Worker     label += dict->idToString(paintID).c_str(); // will be "(empty)" for depth-only draws
151*c8dee2aaSAndroid Build Coastguard Worker     return label;
152*c8dee2aaSAndroid Build Coastguard Worker }
153*c8dee2aaSAndroid Build Coastguard Worker 
BuildComputeSkSL(const Caps * caps,const ComputeStep * step)154*c8dee2aaSAndroid Build Coastguard Worker std::string BuildComputeSkSL(const Caps* caps, const ComputeStep* step) {
155*c8dee2aaSAndroid Build Coastguard Worker     std::string sksl =
156*c8dee2aaSAndroid Build Coastguard Worker             SkSL::String::printf("layout(local_size_x=%u, local_size_y=%u, local_size_z=%u) in;\n",
157*c8dee2aaSAndroid Build Coastguard Worker                                  step->localDispatchSize().fWidth,
158*c8dee2aaSAndroid Build Coastguard Worker                                  step->localDispatchSize().fHeight,
159*c8dee2aaSAndroid Build Coastguard Worker                                  step->localDispatchSize().fDepth);
160*c8dee2aaSAndroid Build Coastguard Worker 
161*c8dee2aaSAndroid Build Coastguard Worker     const auto& bindingReqs = caps->resourceBindingRequirements();
162*c8dee2aaSAndroid Build Coastguard Worker     bool distinctRanges = bindingReqs.fDistinctIndexRanges;
163*c8dee2aaSAndroid Build Coastguard Worker     bool separateSampler = bindingReqs.fSeparateTextureAndSamplerBinding;
164*c8dee2aaSAndroid Build Coastguard Worker 
165*c8dee2aaSAndroid Build Coastguard Worker     int index = 0;
166*c8dee2aaSAndroid Build Coastguard Worker     int texIdx = 0;
167*c8dee2aaSAndroid Build Coastguard Worker     // NOTE: SkSL Metal codegen always assigns the same binding index to a texture and its sampler.
168*c8dee2aaSAndroid Build Coastguard Worker     // TODO: This could cause sampler indices to not be tightly packed if the sampler2D declaration
169*c8dee2aaSAndroid Build Coastguard Worker     // comes after 1 or more storage texture declarations (which don't have samplers). An optional
170*c8dee2aaSAndroid Build Coastguard Worker     // "layout(msl, sampler=T, texture=T)" syntax to count them separately (like we do for WGSL)
171*c8dee2aaSAndroid Build Coastguard Worker     // could come in handy here but it's not supported in MSL codegen yet.
172*c8dee2aaSAndroid Build Coastguard Worker 
173*c8dee2aaSAndroid Build Coastguard Worker     for (const ComputeStep::ResourceDesc& r : step->resources()) {
174*c8dee2aaSAndroid Build Coastguard Worker         using Type = ComputeStep::ResourceType;
175*c8dee2aaSAndroid Build Coastguard Worker         switch (r.fType) {
176*c8dee2aaSAndroid Build Coastguard Worker             case Type::kUniformBuffer:
177*c8dee2aaSAndroid Build Coastguard Worker                 SkSL::String::appendf(&sksl, "layout(binding=%d) uniform ", index++);
178*c8dee2aaSAndroid Build Coastguard Worker                 sksl += r.fSkSL;
179*c8dee2aaSAndroid Build Coastguard Worker                 break;
180*c8dee2aaSAndroid Build Coastguard Worker             case Type::kStorageBuffer:
181*c8dee2aaSAndroid Build Coastguard Worker             case Type::kIndirectBuffer:
182*c8dee2aaSAndroid Build Coastguard Worker                 SkSL::String::appendf(&sksl, "layout(binding=%d) buffer ", index++);
183*c8dee2aaSAndroid Build Coastguard Worker                 sksl += r.fSkSL;
184*c8dee2aaSAndroid Build Coastguard Worker                 break;
185*c8dee2aaSAndroid Build Coastguard Worker             case Type::kReadOnlyStorageBuffer:
186*c8dee2aaSAndroid Build Coastguard Worker                 SkSL::String::appendf(&sksl, "layout(binding=%d) readonly buffer ", index++);
187*c8dee2aaSAndroid Build Coastguard Worker                 sksl += r.fSkSL;
188*c8dee2aaSAndroid Build Coastguard Worker                 break;
189*c8dee2aaSAndroid Build Coastguard Worker             case Type::kWriteOnlyStorageTexture:
190*c8dee2aaSAndroid Build Coastguard Worker                 SkSL::String::appendf(&sksl, "layout(binding=%d, rgba8) writeonly texture2D ",
191*c8dee2aaSAndroid Build Coastguard Worker                                       distinctRanges ? texIdx++ : index++);
192*c8dee2aaSAndroid Build Coastguard Worker                 sksl += r.fSkSL;
193*c8dee2aaSAndroid Build Coastguard Worker                 break;
194*c8dee2aaSAndroid Build Coastguard Worker             case Type::kReadOnlyTexture:
195*c8dee2aaSAndroid Build Coastguard Worker                 SkSL::String::appendf(&sksl, "layout(binding=%d, rgba8) readonly texture2D ",
196*c8dee2aaSAndroid Build Coastguard Worker                                       distinctRanges ? texIdx++ : index++);
197*c8dee2aaSAndroid Build Coastguard Worker                 sksl += r.fSkSL;
198*c8dee2aaSAndroid Build Coastguard Worker                 break;
199*c8dee2aaSAndroid Build Coastguard Worker             case Type::kSampledTexture:
200*c8dee2aaSAndroid Build Coastguard Worker                 if (distinctRanges) {
201*c8dee2aaSAndroid Build Coastguard Worker                     SkSL::String::appendf(&sksl, "layout(metal, binding=%d) ", texIdx++);
202*c8dee2aaSAndroid Build Coastguard Worker                 } else if (separateSampler) {
203*c8dee2aaSAndroid Build Coastguard Worker                     SkSL::String::appendf(
204*c8dee2aaSAndroid Build Coastguard Worker                             &sksl, "layout(webgpu, sampler=%d, texture=%d) ", index, index + 1);
205*c8dee2aaSAndroid Build Coastguard Worker                     index += 2;
206*c8dee2aaSAndroid Build Coastguard Worker                 } else {
207*c8dee2aaSAndroid Build Coastguard Worker                     SkSL::String::appendf(&sksl, "layout(binding=%d) ", index++);
208*c8dee2aaSAndroid Build Coastguard Worker                 }
209*c8dee2aaSAndroid Build Coastguard Worker                 sksl += "sampler2D ";
210*c8dee2aaSAndroid Build Coastguard Worker                 sksl += r.fSkSL;
211*c8dee2aaSAndroid Build Coastguard Worker                 break;
212*c8dee2aaSAndroid Build Coastguard Worker         }
213*c8dee2aaSAndroid Build Coastguard Worker         sksl += ";\n";
214*c8dee2aaSAndroid Build Coastguard Worker     }
215*c8dee2aaSAndroid Build Coastguard Worker 
216*c8dee2aaSAndroid Build Coastguard Worker     sksl += step->computeSkSL();
217*c8dee2aaSAndroid Build Coastguard Worker     return sksl;
218*c8dee2aaSAndroid Build Coastguard Worker }
219*c8dee2aaSAndroid Build Coastguard Worker 
220*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::graphite
221