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/GrSPIRVUniformHandler.h"
9 
10 #include "src/gpu/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 
grsltype_to_alignment_mask(GrSLType type)31 uint32_t grsltype_to_alignment_mask(GrSLType type) {
32     switch(type) {
33         case kByte_GrSLType: // fall through
34         case kUByte_GrSLType:
35             return 0x0;
36         case kByte2_GrSLType: // fall through
37         case kUByte2_GrSLType:
38             return 0x1;
39         case kByte3_GrSLType: // fall through
40         case kByte4_GrSLType:
41         case kUByte3_GrSLType:
42         case kUByte4_GrSLType:
43             return 0x3;
44         case kShort_GrSLType: // fall through
45         case kUShort_GrSLType:
46             return 0x1;
47         case kShort2_GrSLType: // fall through
48         case kUShort2_GrSLType:
49             return 0x3;
50         case kShort3_GrSLType: // fall through
51         case kShort4_GrSLType:
52         case kUShort3_GrSLType:
53         case kUShort4_GrSLType:
54             return 0x7;
55         case kInt_GrSLType:
56         case kUint_GrSLType:
57             return 0x3;
58         case kHalf_GrSLType: // fall through
59         case kFloat_GrSLType:
60             return 0x3;
61         case kHalf2_GrSLType: // fall through
62         case kFloat2_GrSLType:
63             return 0x7;
64         case kHalf3_GrSLType: // fall through
65         case kFloat3_GrSLType:
66             return 0xF;
67         case kHalf4_GrSLType: // fall through
68         case kFloat4_GrSLType:
69             return 0xF;
70         case kUint2_GrSLType:
71             return 0x7;
72         case kInt2_GrSLType:
73             return 0x7;
74         case kInt3_GrSLType:
75             return 0xF;
76         case kInt4_GrSLType:
77             return 0xF;
78         case kHalf2x2_GrSLType: // fall through
79         case kFloat2x2_GrSLType:
80             return 0x7;
81         case kHalf3x3_GrSLType: // fall through
82         case kFloat3x3_GrSLType:
83             return 0xF;
84         case kHalf4x4_GrSLType: // fall through
85         case kFloat4x4_GrSLType:
86             return 0xF;
87 
88         // This query is only valid for certain types.
89         case kVoid_GrSLType:
90         case kBool_GrSLType:
91         case kTexture2DSampler_GrSLType:
92         case kTextureExternalSampler_GrSLType:
93         case kTexture2DRectSampler_GrSLType:
94         case kTexture2D_GrSLType:
95         case kSampler_GrSLType:
96         case kInput_GrSLType:
97             break;
98     }
99     SK_ABORT("Unexpected type");
100 }
101 
grsltype_to_size(GrSLType type)102 static inline uint32_t grsltype_to_size(GrSLType type) {
103     switch(type) {
104         case kByte_GrSLType:
105         case kUByte_GrSLType:
106             return 1;
107         case kByte2_GrSLType:
108         case kUByte2_GrSLType:
109             return 2;
110         case kByte3_GrSLType:
111         case kUByte3_GrSLType:
112             return 3;
113         case kByte4_GrSLType:
114         case kUByte4_GrSLType:
115             return 4;
116         case kShort_GrSLType:
117             return sizeof(int16_t);
118         case kShort2_GrSLType:
119             return 2 * sizeof(int16_t);
120         case kShort3_GrSLType:
121             return 3 * sizeof(int16_t);
122         case kShort4_GrSLType:
123             return 4 * sizeof(int16_t);
124         case kUShort_GrSLType:
125             return sizeof(uint16_t);
126         case kUShort2_GrSLType:
127             return 2 * sizeof(uint16_t);
128         case kUShort3_GrSLType:
129             return 3 * sizeof(uint16_t);
130         case kUShort4_GrSLType:
131             return 4 * sizeof(uint16_t);
132         case kInt_GrSLType:
133             return sizeof(int32_t);
134         case kUint_GrSLType:
135             return sizeof(int32_t);
136         case kHalf_GrSLType: // fall through
137         case kFloat_GrSLType:
138             return sizeof(float);
139         case kHalf2_GrSLType: // fall through
140         case kFloat2_GrSLType:
141             return 2 * sizeof(float);
142         case kHalf3_GrSLType: // fall through
143         case kFloat3_GrSLType:
144             return 3 * sizeof(float);
145         case kHalf4_GrSLType: // fall through
146         case kFloat4_GrSLType:
147             return 4 * sizeof(float);
148         case kUint2_GrSLType:
149             return 2 * sizeof(uint32_t);
150         case kInt2_GrSLType:
151             return 2 * sizeof(int32_t);
152         case kInt3_GrSLType:
153             return 3 * sizeof(int32_t);
154         case kInt4_GrSLType:
155             return 4 * sizeof(int32_t);
156         case kHalf2x2_GrSLType: // fall through
157         case kFloat2x2_GrSLType:
158             //TODO: this will be 4 * szof(float) on std430.
159             return 8 * sizeof(float);
160         case kHalf3x3_GrSLType: // fall through
161         case kFloat3x3_GrSLType:
162             return 12 * sizeof(float);
163         case kHalf4x4_GrSLType: // fall through
164         case kFloat4x4_GrSLType:
165             return 16 * sizeof(float);
166 
167         // This query is only valid for certain types.
168         case kVoid_GrSLType:
169         case kBool_GrSLType:
170         case kTexture2DSampler_GrSLType:
171         case kTextureExternalSampler_GrSLType:
172         case kTexture2DRectSampler_GrSLType:
173         case kTexture2D_GrSLType:
174         case kSampler_GrSLType:
175         case kInput_GrSLType:
176             break;
177     }
178     SK_ABORT("Unexpected type");
179 }
180 
get_ubo_offset(uint32_t * currentOffset,GrSLType type,int arrayCount)181 uint32_t get_ubo_offset(uint32_t* currentOffset, GrSLType type, int arrayCount) {
182     uint32_t alignmentMask = grsltype_to_alignment_mask(type);
183     // We want to use the std140 layout here, so we must make arrays align to 16 bytes.
184     if (arrayCount || type == kFloat2x2_GrSLType) {
185         alignmentMask = 0xF;
186     }
187     uint32_t offsetDiff = *currentOffset & alignmentMask;
188     if (offsetDiff != 0) {
189         offsetDiff = alignmentMask - offsetDiff + 1;
190     }
191     uint32_t uniformOffset = *currentOffset + offsetDiff;
192     SkASSERT(sizeof(float) == 4);
193     if (arrayCount) {
194         uint32_t elementSize = std::max<uint32_t>(16, grsltype_to_size(type));
195         SkASSERT(0 == (elementSize & 0xF));
196         *currentOffset = uniformOffset + elementSize * arrayCount;
197     } else {
198         *currentOffset = uniformOffset + grsltype_to_size(type);
199     }
200     return uniformOffset;
201 }
202 
203 }  // namespace
204 
internalAddUniformArray(const GrFragmentProcessor * owner,uint32_t visibility,GrSLType type,const char * name,bool mangleName,int arrayCount,const char ** outName)205 GrGLSLUniformHandler::UniformHandle GrSPIRVUniformHandler::internalAddUniformArray(
206         const GrFragmentProcessor* owner,
207         uint32_t visibility,
208         GrSLType type,
209         const char* name,
210         bool mangleName,
211         int arrayCount,
212         const char** outName) {
213     char prefix = 'u';
214     if ('u' == name[0] || !strncmp(name, GR_NO_MANGLE_PREFIX, strlen(GR_NO_MANGLE_PREFIX))) {
215         prefix = '\0';
216     }
217     SkString resolvedName = fProgramBuilder->nameVariable(prefix, name, mangleName);
218 
219     int offset = get_ubo_offset(&fCurrentUBOOffset, type, arrayCount);
220     SkString layoutQualifier;
221     layoutQualifier.appendf("offset = %d", offset);
222 
223     UniformInfo& info = fUniforms.push_back(SPIRVUniformInfo{
224         {
225             GrShaderVar{std::move(resolvedName), type, GrShaderVar::TypeModifier::None, arrayCount,
226                         std::move(layoutQualifier), SkString()},
227             visibility, owner, SkString(name)
228         },
229         offset
230     });
231 
232     if (outName) {
233         *outName = info.fVariable.c_str();
234     }
235     return GrGLSLUniformHandler::UniformHandle(fUniforms.count() - 1);
236 }
237 
addSampler(const GrBackendFormat &,GrSamplerState,const GrSwizzle & swizzle,const char * name,const GrShaderCaps * caps)238 GrGLSLUniformHandler::SamplerHandle GrSPIRVUniformHandler::addSampler(const GrBackendFormat&,
239                                                                      GrSamplerState,
240                                                                      const GrSwizzle& swizzle,
241                                                                      const char* name,
242                                                                      const GrShaderCaps* caps) {
243     int binding = fSamplers.count() * 2;
244 
245     SkString mangleName = fProgramBuilder->nameVariable('s', name, /*mangle=*/true);
246     SkString layoutQualifier;
247     layoutQualifier.appendf("set = %d, binding = %d", kSamplerTextureDescriptorSet, binding);
248     SPIRVUniformInfo& info = fSamplers.push_back(SPIRVUniformInfo{
249         {
250             GrShaderVar{std::move(mangleName), kSampler_GrSLType,
251                         GrShaderVar::TypeModifier::Uniform, GrShaderVar::kNonArray,
252                         std::move(layoutQualifier), SkString()},
253             kFragment_GrShaderFlag, nullptr, SkString(name)
254         },
255         0
256     });
257 
258     fSamplerSwizzles.push_back(swizzle);
259     SkASSERT(fSamplerSwizzles.count() == fSamplers.count());
260 
261     SkString mangleTexName = fProgramBuilder->nameVariable('t', name, /*mangle=*/true);
262     SkString texLayoutQualifier;
263     texLayoutQualifier.appendf("set = %d, binding = %d", kSamplerTextureDescriptorSet, binding + 1);
264     UniformInfo& texInfo = fTextures.push_back(SPIRVUniformInfo{
265         {
266             GrShaderVar{std::move(mangleTexName), kTexture2D_GrSLType,
267                         GrShaderVar::TypeModifier::Uniform, GrShaderVar::kNonArray,
268                         std::move(texLayoutQualifier), SkString()},
269             kFragment_GrShaderFlag, nullptr, SkString(name)
270         },
271         0
272     });
273 
274     SkString reference;
275     reference.printf("makeSampler2D(%s, %s)", texInfo.fVariable.getName().c_str(),
276                                               info.fVariable.getName().c_str());
277     fSamplerReferences.emplace_back(std::move(reference));
278     return GrGLSLUniformHandler::SamplerHandle(fSamplers.count() - 1);
279 }
280 
samplerVariable(GrGLSLUniformHandler::SamplerHandle handle) const281 const char* GrSPIRVUniformHandler::samplerVariable(
282         GrGLSLUniformHandler::SamplerHandle handle) const {
283     return fSamplerReferences[handle.toIndex()].c_str();
284 }
285 
samplerSwizzle(GrGLSLUniformHandler::SamplerHandle handle) const286 GrSwizzle GrSPIRVUniformHandler::samplerSwizzle(GrGLSLUniformHandler::SamplerHandle handle) const {
287     return fSamplerSwizzles[handle.toIndex()];
288 }
289 
appendUniformDecls(GrShaderFlags visibility,SkString * out) const290 void GrSPIRVUniformHandler::appendUniformDecls(GrShaderFlags visibility, SkString* out) const {
291     auto textures = fTextures.items().begin();
292     for (const SPIRVUniformInfo& sampler : fSamplers.items()) {
293         if (sampler.fVisibility & visibility) {
294             sampler.fVariable.appendDecl(fProgramBuilder->shaderCaps(), out);
295             out->append(";\n");
296             (*textures).fVariable.appendDecl(fProgramBuilder->shaderCaps(), out);
297             out->append(";\n");
298         }
299         ++textures;
300     }
301     SkString uniformsString;
302     for (const UniformInfo& uniform : fUniforms.items()) {
303         if (uniform.fVisibility & visibility) {
304             uniform.fVariable.appendDecl(fProgramBuilder->shaderCaps(), &uniformsString);
305             uniformsString.append(";\n");
306         }
307     }
308     if (!uniformsString.isEmpty()) {
309         out->appendf("layout (set = %d, binding = %d) uniform UniformBuffer\n{\n",
310                      kUniformDescriptorSet, kUniformBinding);
311         out->appendf("%s\n};\n", uniformsString.c_str());
312     }
313 }
314 
getRTHeightOffset() const315 uint32_t GrSPIRVUniformHandler::getRTHeightOffset() const {
316     uint32_t dummy = fCurrentUBOOffset;
317     return get_ubo_offset(&dummy, kFloat_GrSLType, 0);
318 }
319