• 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 <string>
11 #include "include/private/SkSLString.h"
12 #include "src/core/SkBlenderBase.h"
13 #include "src/gpu/graphite/Caps.h"
14 #include "src/gpu/graphite/GraphicsPipelineDesc.h"
15 #include "src/gpu/graphite/KeyContext.h"
16 #include "src/gpu/graphite/PaintParams.h"
17 #include "src/gpu/graphite/PipelineData.h"
18 #include "src/gpu/graphite/RecorderPriv.h"
19 #include "src/gpu/graphite/Renderer.h"
20 #include "src/gpu/graphite/ResourceProvider.h"
21 #include "src/gpu/graphite/ShaderCodeDictionary.h"
22 #include "src/gpu/graphite/UniformManager.h"
23 #include "src/gpu/graphite/UniquePaintParamsID.h"
24 
25 namespace skgpu::graphite {
26 
27 std::tuple<UniquePaintParamsID, const UniformDataBlock*, const TextureDataBlock*>
ExtractPaintData(Recorder * recorder,PipelineDataGatherer * gatherer,PaintParamsKeyBuilder * builder,const Layout layout,const SkM44 & local2Dev,const PaintParams & p,const SkColorInfo & targetColorInfo)28 ExtractPaintData(Recorder* recorder,
29                  PipelineDataGatherer* gatherer,
30                  PaintParamsKeyBuilder* builder,
31                  const Layout layout,
32                  const SkM44& local2Dev,
33                  const PaintParams& p,
34                  const SkColorInfo& targetColorInfo) {
35     SkDEBUGCODE(builder->checkReset());
36 
37     gatherer->resetWithNewLayout(layout);
38 
39     KeyContext keyContext(recorder, local2Dev, targetColorInfo);
40     p.toKey(keyContext, builder, gatherer);
41 
42     auto dict = recorder->priv().shaderCodeDictionary();
43     UniformDataCache* uniformDataCache = recorder->priv().uniformDataCache();
44     TextureDataCache* textureDataCache = recorder->priv().textureDataCache();
45 
46     auto entry = dict->findOrCreate(builder);
47 
48     const UniformDataBlock* uniforms =
49             gatherer->hasUniforms() ? uniformDataCache->insert(gatherer->finishUniformDataBlock())
50                                     : nullptr;
51     const TextureDataBlock* textures =
52             gatherer->hasTextures() ? textureDataCache->insert(gatherer->textureDataBlock())
53                                     : nullptr;
54 
55     return { entry->uniqueID(), uniforms, textures };
56 }
57 
ExtractRenderStepData(UniformDataCache * uniformDataCache,TextureDataCache * textureDataCache,PipelineDataGatherer * gatherer,const Layout layout,const RenderStep * step,const DrawParams & params)58 std::tuple<const UniformDataBlock*, const TextureDataBlock*> ExtractRenderStepData(
59         UniformDataCache* uniformDataCache,
60         TextureDataCache* textureDataCache,
61         PipelineDataGatherer* gatherer,
62         const Layout layout,
63         const RenderStep* step,
64         const DrawParams& params) {
65     gatherer->resetWithNewLayout(layout);
66     step->writeUniformsAndTextures(params, gatherer);
67 
68     const UniformDataBlock* uniforms =
69             gatherer->hasUniforms() ? uniformDataCache->insert(gatherer->finishUniformDataBlock())
70                                     : nullptr;
71     const TextureDataBlock* textures =
72             gatherer->hasTextures() ? textureDataCache->insert(gatherer->textureDataBlock())
73                                     : nullptr;
74 
75     return { uniforms, textures };
76 }
77 
78 namespace {
get_uniform_header(int bufferID,const char * name)79 std::string get_uniform_header(int bufferID, const char* name) {
80     std::string result;
81 
82     SkSL::String::appendf(&result, "layout (binding=%d) uniform %sUniforms {\n", bufferID, name);
83 
84     return result;
85 }
86 
get_uniforms(Layout layout,SkSpan<const Uniform> uniforms,int * offset,int manglingSuffix)87 std::string get_uniforms(Layout layout,
88                          SkSpan<const Uniform> uniforms,
89                          int* offset,
90                          int manglingSuffix) {
91     std::string result;
92     UniformOffsetCalculator offsetter(layout, *offset);
93 
94     for (const Uniform& u : uniforms) {
95         SkSL::String::appendf(&result,
96                               "    layout(offset=%zu) %s %s",
97                               offsetter.advanceOffset(u.type(), u.count()),
98                               SkSLTypeString(u.type()),
99                               u.name());
100         if (manglingSuffix >= 0) {
101             result.append("_");
102             result.append(std::to_string(manglingSuffix));
103         }
104         if (u.count()) {
105             result.append("[");
106             result.append(std::to_string(u.count()));
107             result.append("]");
108         }
109         result.append(";\n");
110     }
111 
112     *offset = offsetter.size();
113     return result;
114 }
115 }  // anonymous namespace
116 
EmitPaintParamsUniforms(int bufferID,const char * name,const Layout layout,const std::vector<PaintParamsKey::BlockReader> & readers)117 std::string EmitPaintParamsUniforms(int bufferID,
118                                     const char* name,
119                                     const Layout layout,
120                                     const std::vector<PaintParamsKey::BlockReader>& readers) {
121     int offset = 0;
122 
123     std::string result = get_uniform_header(bufferID, name);
124     for (int i = 0; i < (int) readers.size(); ++i) {
125         SkSpan<const Uniform> uniforms = readers[i].entry()->fUniforms;
126 
127         if (!uniforms.empty()) {
128             SkSL::String::appendf(&result, "// %s uniforms\n", readers[i].entry()->fName);
129             result += get_uniforms(layout, uniforms, &offset, i);
130         }
131     }
132     result.append("};\n\n");
133 
134     return result;
135 }
136 
EmitRenderStepUniforms(int bufferID,const char * name,const Layout layout,SkSpan<const Uniform> uniforms)137 std::string EmitRenderStepUniforms(int bufferID,
138                                    const char* name,
139                                    const Layout layout,
140                                    SkSpan<const Uniform> uniforms) {
141     int offset = 0;
142 
143     std::string result = get_uniform_header(bufferID, name);
144     result += get_uniforms(layout, uniforms, &offset, -1);
145     result.append("};\n\n");
146 
147     return result;
148 }
149 
EmitPaintParamsStorageBuffer(int bufferID,const char * bufferTypePrefix,const char * bufferNamePrefix,const std::vector<PaintParamsKey::BlockReader> & readers)150 std::string EmitPaintParamsStorageBuffer(
151         int bufferID,
152         const char* bufferTypePrefix,
153         const char* bufferNamePrefix,
154         const std::vector<PaintParamsKey::BlockReader>& readers) {
155 
156     std::string result;
157     SkSL::String::appendf(&result, "struct %sUniformData {\n", bufferTypePrefix);
158     for (int i = 0; i < (int)readers.size(); ++i) {
159         SkSpan<const Uniform> uniforms = readers[i].entry()->fUniforms;
160         if (uniforms.empty()) {
161             continue;
162         }
163         SkSL::String::appendf(&result, "// %s uniforms\n", readers[i].entry()->fName);
164         int manglingSuffix = i;
165         for (const Uniform& u : uniforms) {
166             SkSL::String::appendf(
167                     &result, "    %s %s_%d", SkSLTypeString(u.type()), u.name(), manglingSuffix);
168             if (u.count()) {
169                 SkSL::String::appendf(&result, "[%u]", u.count());
170             }
171             result.append(";\n");
172         }
173     }
174     result.append("};\n\n");
175 
176     SkSL::String::appendf(&result,
177                           "layout (binding=%d) buffer %sUniforms {\n"
178                           "    %sUniformData %sUniformData[];\n"
179                           "};\n",
180                           bufferID,
181                           bufferTypePrefix,
182                           bufferTypePrefix,
183                           bufferNamePrefix);
184     return result;
185 }
186 
EmitStorageBufferAccess(const char * bufferNamePrefix,const char * ssboIndex,const char * uniformName)187 std::string EmitStorageBufferAccess(const char* bufferNamePrefix,
188                                     const char* ssboIndex,
189                                     const char* uniformName) {
190     return SkSL::String::printf("%sUniformData[%s].%s", bufferNamePrefix, ssboIndex, uniformName);
191 }
192 
EmitTexturesAndSamplers(const ResourceBindingRequirements & bindingReqs,const std::vector<PaintParamsKey::BlockReader> & readers,int * binding)193 std::string EmitTexturesAndSamplers(const ResourceBindingRequirements& bindingReqs,
194                                     const std::vector<PaintParamsKey::BlockReader>& readers,
195                                     int* binding) {
196     std::string result;
197     for (int i = 0; i < (int) readers.size(); ++i) {
198         SkSpan<const TextureAndSampler> samplers = readers[i].entry()->fTexturesAndSamplers;
199 
200         if (!samplers.empty()) {
201             SkSL::String::appendf(&result, "// %s samplers\n", readers[i].entry()->fName);
202 
203             for (const TextureAndSampler& t : samplers) {
204                 result += EmitSamplerLayout(bindingReqs, binding);
205                 SkSL::String::appendf(&result, " uniform sampler2D %s_%d;\n", t.name(), i);
206             }
207         }
208     }
209 
210     return result;
211 }
212 
EmitSamplerLayout(const ResourceBindingRequirements & bindingReqs,int * binding)213 std::string EmitSamplerLayout(const ResourceBindingRequirements& bindingReqs, int* binding) {
214     std::string result;
215 
216     // If fDistinctIndexRanges is false, then texture and sampler indices may clash with other
217     // resource indices. Graphite assumes that they will be placed in descriptor set (Vulkan) and
218     // bind group (Dawn) index 1.
219     if (bindingReqs.fSeparateTextureAndSamplerBinding) {
220         int samplerIndex = (*binding)++;
221         int textureIndex = (*binding)++;
222         SkSL::String::appendf(&result,
223                               "layout(wgsl, %ssampler=%d, texture=%d)",
224                               bindingReqs.fDistinctIndexRanges ? "" : "set=1, ",
225                               samplerIndex,
226                               textureIndex);
227     } else {
228         SkSL::String::appendf(&result,
229                               "layout(%sbinding=%d)",
230                               bindingReqs.fDistinctIndexRanges ? "" : "set=1, ",
231                               *binding);
232         (*binding)++;
233     }
234     return result;
235 }
236 
237 namespace {
emit_attributes(SkSpan<const Attribute> vertexAttrs,SkSpan<const Attribute> instanceAttrs)238 std::string emit_attributes(SkSpan<const Attribute> vertexAttrs,
239                             SkSpan<const Attribute> instanceAttrs) {
240     std::string result;
241 
242     int attr = 0;
243     auto add_attrs = [&](SkSpan<const Attribute> attrs) {
244         for (auto a : attrs) {
245             SkSL::String::appendf(&result, "    layout(location=%d) in ", attr++);
246             result.append(SkSLTypeString(a.gpuType()));
247             SkSL::String::appendf(&result, " %s;\n", a.name());
248         }
249     };
250 
251     if (!vertexAttrs.empty()) {
252         result.append("// vertex attrs\n");
253         add_attrs(vertexAttrs);
254     }
255     if (!instanceAttrs.empty()) {
256         result.append("// instance attrs\n");
257         add_attrs(instanceAttrs);
258     }
259 
260     return result;
261 }
262 }  // anonymous namespace
263 
EmitVaryings(const RenderStep * step,const char * direction,bool emitShadingSsboIndexVarying,bool emitLocalCoordsVarying)264 std::string EmitVaryings(const RenderStep* step,
265                          const char* direction,
266                          bool emitShadingSsboIndexVarying,
267                          bool emitLocalCoordsVarying) {
268     std::string result;
269     int location = 0;
270 
271     if (emitShadingSsboIndexVarying) {
272         SkSL::String::appendf(&result,
273                               "    layout(location=%d) %s int shadingSsboIndexVar;\n",
274                               location++,
275                               direction);
276     }
277 
278     if (emitLocalCoordsVarying) {
279         SkSL::String::appendf(&result, "    layout(location=%d) %s ", location++, direction);
280         result.append(SkSLTypeString(SkSLType::kFloat2));
281         SkSL::String::appendf(&result, " localCoordsVar;\n");
282     }
283 
284     for (auto v : step->varyings()) {
285         SkSL::String::appendf(&result, "    layout(location=%d) %s ", location++, direction);
286         result.append(SkSLTypeString(v.fType));
287         SkSL::String::appendf(&result, " %s;\n", v.fName);
288     }
289 
290     return result;
291 }
292 
GetSkSLVS(const ResourceBindingRequirements & bindingReqs,const RenderStep * step,bool defineShadingSsboIndexVarying,bool defineLocalCoordsVarying)293 std::string GetSkSLVS(const ResourceBindingRequirements& bindingReqs,
294                       const RenderStep* step,
295                       bool defineShadingSsboIndexVarying,
296                       bool defineLocalCoordsVarying) {
297     // TODO: To more completely support end-to-end rendering, this will need to be updated so that
298     // the RenderStep shader snippet can produce a device coord, a local coord, and depth.
299     // If the paint combination doesn't need the local coord it can be ignored, otherwise we need
300     // a varying for it. The fragment function's output will need to be updated to have a color and
301     // the depth, or when there's no combination, just the depth. Lastly, we also should add the
302     // static/intrinsic uniform binding point so that we can handle normalizing the device position
303     // produced by the RenderStep automatically.
304 
305     // Fixed program header
306     std::string sksl =
307         "layout (binding=0) uniform intrinsicUniforms {\n"
308         "    layout(offset=0) float4 rtAdjust;\n"
309         "};\n"
310         "\n";
311 
312     if (step->numVertexAttributes() > 0 || step->numInstanceAttributes() > 0) {
313         sksl += emit_attributes(step->vertexAttributes(), step->instanceAttributes());
314     }
315 
316     // Uniforms needed by RenderStep
317     // The uniforms are mangled by having their index in 'fEntries' as a suffix (i.e., "_%d")
318     // TODO: replace hard-coded bufferID with the backend's renderstep uniform-buffer index.
319     if (step->numUniforms() > 0) {
320         sksl += EmitRenderStepUniforms(
321                 1, "Step", bindingReqs.fUniformBufferLayout, step->uniforms());
322     }
323 
324     // Varyings needed by RenderStep
325     sksl += EmitVaryings(step, "out", defineShadingSsboIndexVarying, defineLocalCoordsVarying);
326 
327     // Vertex shader function declaration
328     sksl += "void main() {";
329     // Create stepLocalCoords which render steps can write to.
330     sksl += "float2 stepLocalCoords = float2(0);";
331     // Vertex shader body
332     sksl += step->vertexSkSL();
333     sksl += "sk_Position = float4(devPosition.xy * rtAdjust.xy + devPosition.ww * rtAdjust.zw,"
334             "devPosition.zw);";
335 
336     if (defineShadingSsboIndexVarying) {
337         // Assign SSBO index value to the SSBO index varying
338         SkSL::String::appendf(&sksl, "shadingSsboIndexVar = %s;", step->ssboIndex());
339     }
340 
341     if (defineLocalCoordsVarying) {
342         // Assign Render Step's stepLocalCoords to the localCoordsVar varying.
343         sksl += "localCoordsVar = stepLocalCoords;";
344     }
345     sksl += "}";
346 
347     return sksl;
348 }
349 
GetSkSLFS(const ResourceBindingRequirements & bindingReqs,const ShaderCodeDictionary * dict,const RuntimeEffectDictionary * rteDict,const RenderStep * step,UniquePaintParamsID paintID,bool useStorageBuffers)350 FragSkSLInfo GetSkSLFS(const ResourceBindingRequirements& bindingReqs,
351                       const ShaderCodeDictionary* dict,
352                       const RuntimeEffectDictionary* rteDict,
353                       const RenderStep* step,
354                       UniquePaintParamsID paintID,
355                       bool useStorageBuffers) {
356     if (!paintID.isValid()) {
357         // TODO: we should return the error shader code here
358         return {};
359     }
360 
361     FragSkSLInfo result;
362 
363     const char* shadingSsboIndexVar = useStorageBuffers ? "shadingSsboIndexVar" : nullptr;
364     ShaderInfo shaderInfo(rteDict, shadingSsboIndexVar);
365 
366     dict->getShaderInfo(paintID, &shaderInfo);
367     result.fBlendInfo = shaderInfo.blendInfo();
368     result.fRequiresLocalCoords = shaderInfo.needsLocalCoords();
369 
370     // Extra RenderStep uniforms are always backed by a UBO. Uniforms for the PaintParams are either
371     // UBO or SSBO backed based on `useStorageBuffers`.
372     result.fSkSL =
373             shaderInfo.toSkSL(bindingReqs,
374                               step,
375                               useStorageBuffers,
376                               /*defineLocalCoordsVarying=*/result.fRequiresLocalCoords,
377                               /*numTexturesAndSamplersUsed=*/&result.fNumTexturesAndSamplers);
378 
379     return result;
380 }
381 
382 } // namespace skgpu::graphite
383