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