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