xref: /aosp_15_r20/external/skia/src/gpu/ganesh/GrSPIRVUniformHandler.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2019 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 #include "src/gpu/ganesh/GrSPIRVUniformHandler.h"
8 
9 #include "include/core/SkString.h"
10 #include "include/gpu/ganesh/GrBackendSurface.h"
11 #include "include/private/base/SkAssert.h"
12 #include "src/core/SkSLTypeShared.h"
13 #include "src/gpu/ganesh/GrShaderVar.h"
14 #include "src/gpu/ganesh/GrUtil.h"
15 #include "src/gpu/ganesh/glsl/GrGLSLProgramBuilder.h"
16 
17 #include <string.h>
18 #include <algorithm>
19 #include <cstddef>
20 #include <utility>
21 
22 class GrProcessor;
23 struct GrShaderCaps;
24 
25 static constexpr int kUniformBinding = 0;
26 static constexpr size_t kUniformsPerBlock = 8;
27 
GrSPIRVUniformHandler(GrGLSLProgramBuilder * program)28 GrSPIRVUniformHandler::GrSPIRVUniformHandler(GrGLSLProgramBuilder* program)
29     : INHERITED(program)
30     , fUniforms(kUniformsPerBlock)
31     , fSamplers(kUniformsPerBlock) {}
32 
getUniformVariable(UniformHandle u) const33 const GrShaderVar& GrSPIRVUniformHandler::getUniformVariable(UniformHandle u) const {
34     return fUniforms.item(u.toIndex()).fVariable;
35 }
36 
getUniformCStr(UniformHandle u) const37 const char* GrSPIRVUniformHandler::getUniformCStr(UniformHandle u) const {
38     return fUniforms.item(u.toIndex()).fVariable.getName().c_str();
39 }
40 
41 // FIXME: this code was ripped from GrVkUniformHandler; should be refactored.
42 namespace {
43 
sksltype_to_alignment_mask(SkSLType type)44 uint32_t sksltype_to_alignment_mask(SkSLType type) {
45     switch(type) {
46         case SkSLType::kShort: // fall through
47         case SkSLType::kUShort:
48             return 0x1;
49         case SkSLType::kShort2: // fall through
50         case SkSLType::kUShort2:
51             return 0x3;
52         case SkSLType::kShort3: // fall through
53         case SkSLType::kShort4:
54         case SkSLType::kUShort3:
55         case SkSLType::kUShort4:
56             return 0x7;
57         case SkSLType::kInt:
58         case SkSLType::kUInt:
59             return 0x3;
60         case SkSLType::kInt2:
61         case SkSLType::kUInt2:
62             return 0x7;
63         case SkSLType::kInt3:
64         case SkSLType::kUInt3:
65         case SkSLType::kInt4:
66         case SkSLType::kUInt4:
67             return 0xF;
68         case SkSLType::kHalf: // fall through
69         case SkSLType::kFloat:
70             return 0x3;
71         case SkSLType::kHalf2: // fall through
72         case SkSLType::kFloat2:
73             return 0x7;
74         case SkSLType::kHalf3: // fall through
75         case SkSLType::kFloat3:
76             return 0xF;
77         case SkSLType::kHalf4: // fall through
78         case SkSLType::kFloat4:
79             return 0xF;
80         case SkSLType::kHalf2x2: // fall through
81         case SkSLType::kFloat2x2:
82             return 0x7;
83         case SkSLType::kHalf3x3: // fall through
84         case SkSLType::kFloat3x3:
85             return 0xF;
86         case SkSLType::kHalf4x4: // fall through
87         case SkSLType::kFloat4x4:
88             return 0xF;
89 
90         // This query is only valid for certain types.
91         case SkSLType::kVoid:
92         case SkSLType::kBool:
93         case SkSLType::kBool2:
94         case SkSLType::kBool3:
95         case SkSLType::kBool4:
96         case SkSLType::kTexture2DSampler:
97         case SkSLType::kTextureExternalSampler:
98         case SkSLType::kTexture2DRectSampler:
99         case SkSLType::kTexture2D:
100         case SkSLType::kSampler:
101         case SkSLType::kInput:
102             break;
103     }
104     SK_ABORT("Unexpected type");
105 }
106 
sksltype_to_size(SkSLType type)107 static inline uint32_t sksltype_to_size(SkSLType type) {
108     switch(type) {
109         case SkSLType::kShort:
110             return sizeof(int16_t);
111         case SkSLType::kShort2:
112             return 2 * sizeof(int16_t);
113         case SkSLType::kShort3:
114             return 3 * sizeof(int16_t);
115         case SkSLType::kShort4:
116             return 4 * sizeof(int16_t);
117         case SkSLType::kUShort:
118             return sizeof(uint16_t);
119         case SkSLType::kUShort2:
120             return 2 * sizeof(uint16_t);
121         case SkSLType::kUShort3:
122             return 3 * sizeof(uint16_t);
123         case SkSLType::kUShort4:
124             return 4 * sizeof(uint16_t);
125         case SkSLType::kHalf: // fall through
126         case SkSLType::kFloat:
127             return sizeof(float);
128         case SkSLType::kHalf2: // fall through
129         case SkSLType::kFloat2:
130             return 2 * sizeof(float);
131         case SkSLType::kHalf3: // fall through
132         case SkSLType::kFloat3:
133             return 3 * sizeof(float);
134         case SkSLType::kHalf4: // fall through
135         case SkSLType::kFloat4:
136             return 4 * sizeof(float);
137         case SkSLType::kInt: // fall through
138         case SkSLType::kUInt:
139             return sizeof(int32_t);
140         case SkSLType::kInt2: // fall through
141         case SkSLType::kUInt2:
142             return 2 * sizeof(int32_t);
143         case SkSLType::kInt3: // fall through
144         case SkSLType::kUInt3:
145             return 3 * sizeof(int32_t);
146         case SkSLType::kInt4: // fall through
147         case SkSLType::kUInt4:
148             return 4 * sizeof(int32_t);
149         case SkSLType::kHalf2x2: // fall through
150         case SkSLType::kFloat2x2:
151             //TODO: this will be 4 * szof(float) on std430.
152             return 8 * sizeof(float);
153         case SkSLType::kHalf3x3: // fall through
154         case SkSLType::kFloat3x3:
155             return 12 * sizeof(float);
156         case SkSLType::kHalf4x4: // fall through
157         case SkSLType::kFloat4x4:
158             return 16 * sizeof(float);
159 
160         // This query is only valid for certain types.
161         case SkSLType::kVoid:
162         case SkSLType::kBool:
163         case SkSLType::kBool2:
164         case SkSLType::kBool3:
165         case SkSLType::kBool4:
166         case SkSLType::kTexture2DSampler:
167         case SkSLType::kTextureExternalSampler:
168         case SkSLType::kTexture2DRectSampler:
169         case SkSLType::kTexture2D:
170         case SkSLType::kSampler:
171         case SkSLType::kInput:
172             break;
173     }
174     SK_ABORT("Unexpected type");
175 }
176 
get_ubo_offset(uint32_t * currentOffset,SkSLType type,int arrayCount)177 uint32_t get_ubo_offset(uint32_t* currentOffset, SkSLType type, int arrayCount) {
178     uint32_t alignmentMask = sksltype_to_alignment_mask(type);
179     // We want to use the std140 layout here, so we must make arrays align to 16 bytes.
180     // TODO(skia:13380): make sure 2x3 and 3x2 matrices are handled properly once SkSLType adds
181     // support for non-square matrices
182     if (arrayCount || type == SkSLType::kFloat2x2 || type == SkSLType::kHalf2x2) {
183         alignmentMask = 0xF;
184     }
185     uint32_t offsetDiff = *currentOffset & alignmentMask;
186     if (offsetDiff != 0) {
187         offsetDiff = alignmentMask - offsetDiff + 1;
188     }
189     uint32_t uniformOffset = *currentOffset + offsetDiff;
190     SkASSERT(sizeof(float) == 4);
191     if (arrayCount) {
192         uint32_t elementSize = std::max<uint32_t>(16, sksltype_to_size(type));
193         SkASSERT(0 == (elementSize & 0xF));
194         *currentOffset = uniformOffset + elementSize * arrayCount;
195     } else {
196         *currentOffset = uniformOffset + sksltype_to_size(type);
197     }
198     return uniformOffset;
199 }
200 
201 }  // namespace
202 
internalAddUniformArray(const GrProcessor * owner,uint32_t visibility,SkSLType type,const char * name,bool mangleName,int arrayCount,const char ** outName)203 GrGLSLUniformHandler::UniformHandle GrSPIRVUniformHandler::internalAddUniformArray(
204         const GrProcessor* owner,
205         uint32_t visibility,
206         SkSLType type,
207         const char* name,
208         bool mangleName,
209         int arrayCount,
210         const char** outName) {
211     char prefix = 'u';
212     if ('u' == name[0] || !strncmp(name, GR_NO_MANGLE_PREFIX, strlen(GR_NO_MANGLE_PREFIX))) {
213         prefix = '\0';
214     }
215     SkString resolvedName = fProgramBuilder->nameVariable(prefix, name, mangleName);
216 
217     int offset = get_ubo_offset(&fCurrentUBOOffset, type, arrayCount);
218     SkString layoutQualifier;
219     layoutQualifier.appendf("offset = %d", offset);
220 
221     SPIRVUniformInfo tempInfo;
222     tempInfo.fVariable = GrShaderVar{std::move(resolvedName),
223                                      type,
224                                      GrShaderVar::TypeModifier::None,
225                                      arrayCount,
226                                      std::move(layoutQualifier),
227                                      SkString()};
228 
229     tempInfo.fVisibility = visibility;
230     tempInfo.fOwner      = owner;
231     tempInfo.fRawName    = SkString(name);
232     tempInfo.fUBOOffset  = offset;
233 
234     fUniforms.push_back(tempInfo);
235 
236     if (outName) {
237         *outName = fUniforms.back().fVariable.c_str();
238     }
239     return GrGLSLUniformHandler::UniformHandle(fUniforms.count() - 1);
240 }
241 
addSampler(const GrBackendFormat & backendFormat,GrSamplerState,const skgpu::Swizzle & swizzle,const char * name,const GrShaderCaps * caps)242 GrGLSLUniformHandler::SamplerHandle GrSPIRVUniformHandler::addSampler(
243         const GrBackendFormat& backendFormat,
244         GrSamplerState,
245         const skgpu::Swizzle& swizzle,
246         const char* name,
247         const GrShaderCaps* caps) {
248     SkASSERT(name && strlen(name));
249 
250     int binding = fSamplers.count() * 2;
251 
252     SkString mangleName = fProgramBuilder->nameVariable('u', name, /*mangle=*/true);
253     SkString layoutQualifier = SkStringPrintf("direct3d, set = %d, sampler = %d, texture = %d",
254                                               kSamplerTextureDescriptorSet,
255                                               binding,
256                                               binding + 1);
257 
258     SPIRVUniformInfo& uniformInfo = fSamplers.emplace_back();
259     uniformInfo.fVariable =
260             GrShaderVar{std::move(mangleName),
261                         SkSLCombinedSamplerTypeForTextureType(backendFormat.textureType()),
262                         GrShaderVar::TypeModifier::None,
263                         GrShaderVar::kNonArray,
264                         std::move(layoutQualifier),
265                         SkString()};
266 
267     uniformInfo.fVisibility = kFragment_GrShaderFlag;
268     uniformInfo.fOwner      = nullptr;
269     uniformInfo.fRawName    = SkString(name);
270     uniformInfo.fUBOOffset  = 0;
271 
272     fSamplerSwizzles.push_back(swizzle);
273     SkASSERT(fSamplerSwizzles.size() == fSamplers.count());
274 
275     return GrGLSLUniformHandler::SamplerHandle(fSamplers.count() - 1);
276 }
277 
samplerVariable(GrGLSLUniformHandler::SamplerHandle handle) const278 const char* GrSPIRVUniformHandler::samplerVariable(
279         GrGLSLUniformHandler::SamplerHandle handle) const {
280     return fSamplers.item(handle.toIndex()).fVariable.getName().c_str();
281 }
282 
samplerSwizzle(GrGLSLUniformHandler::SamplerHandle handle) const283 skgpu::Swizzle GrSPIRVUniformHandler::samplerSwizzle(
284         GrGLSLUniformHandler::SamplerHandle handle) const {
285     return fSamplerSwizzles[handle.toIndex()];
286 }
287 
appendUniformDecls(GrShaderFlags visibility,SkString * out) const288 void GrSPIRVUniformHandler::appendUniformDecls(GrShaderFlags visibility, SkString* out) const {
289     for (const SPIRVUniformInfo& sampler : fSamplers.items()) {
290         if (sampler.fVisibility & visibility) {
291             sampler.fVariable.appendDecl(fProgramBuilder->shaderCaps(), out);
292             out->append(";\n");
293         }
294     }
295     SkString uniformsString;
296     for (const UniformInfo& uniform : fUniforms.items()) {
297         if (uniform.fVisibility & visibility) {
298             uniform.fVariable.appendDecl(fProgramBuilder->shaderCaps(), &uniformsString);
299             uniformsString.append(";\n");
300         }
301     }
302     if (!uniformsString.isEmpty()) {
303         out->appendf("layout (set = %d, binding = %d) uniform UniformBuffer\n{\n",
304                      kUniformDescriptorSet, kUniformBinding);
305         out->appendf("%s\n};\n", uniformsString.c_str());
306     }
307 }
308 
getRTFlipOffset() const309 uint32_t GrSPIRVUniformHandler::getRTFlipOffset() const {
310     uint32_t currentOffset = fCurrentUBOOffset;
311     return get_ubo_offset(&currentOffset, SkSLType::kFloat2, 0);
312 }
313