• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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     if (arrayCount || type == SkSLType::kFloat2x2) {
168         alignmentMask = 0xF;
169     }
170     uint32_t offsetDiff = *currentOffset & alignmentMask;
171     if (offsetDiff != 0) {
172         offsetDiff = alignmentMask - offsetDiff + 1;
173     }
174     uint32_t uniformOffset = *currentOffset + offsetDiff;
175     SkASSERT(sizeof(float) == 4);
176     if (arrayCount) {
177         uint32_t elementSize = std::max<uint32_t>(16, sksltype_to_size(type));
178         SkASSERT(0 == (elementSize & 0xF));
179         *currentOffset = uniformOffset + elementSize * arrayCount;
180     } else {
181         *currentOffset = uniformOffset + sksltype_to_size(type);
182     }
183     return uniformOffset;
184 }
185 
186 }  // namespace
187 
internalAddUniformArray(const GrFragmentProcessor * owner,uint32_t visibility,SkSLType type,const char * name,bool mangleName,int arrayCount,const char ** outName)188 GrGLSLUniformHandler::UniformHandle GrSPIRVUniformHandler::internalAddUniformArray(
189         const GrFragmentProcessor* owner,
190         uint32_t visibility,
191         SkSLType type,
192         const char* name,
193         bool mangleName,
194         int arrayCount,
195         const char** outName) {
196     char prefix = 'u';
197     if ('u' == name[0] || !strncmp(name, GR_NO_MANGLE_PREFIX, strlen(GR_NO_MANGLE_PREFIX))) {
198         prefix = '\0';
199     }
200     SkString resolvedName = fProgramBuilder->nameVariable(prefix, name, mangleName);
201 
202     int offset = get_ubo_offset(&fCurrentUBOOffset, type, arrayCount);
203     SkString layoutQualifier;
204     layoutQualifier.appendf("offset = %d", offset);
205 
206     SPIRVUniformInfo tempInfo;
207     tempInfo.fVariable = GrShaderVar{std::move(resolvedName),
208                                      type,
209                                      GrShaderVar::TypeModifier::None,
210                                      arrayCount,
211                                      std::move(layoutQualifier),
212                                      SkString()};
213 
214     tempInfo.fVisibility = visibility;
215     tempInfo.fOwner      = owner;
216     tempInfo.fRawName    = SkString(name);
217     tempInfo.fUBOOffset  = offset;
218 
219     fUniforms.push_back(tempInfo);
220 
221     if (outName) {
222         *outName = fUniforms.back().fVariable.c_str();
223     }
224     return GrGLSLUniformHandler::UniformHandle(fUniforms.count() - 1);
225 }
226 
addSampler(const GrBackendFormat &,GrSamplerState,const skgpu::Swizzle & swizzle,const char * name,const GrShaderCaps * caps)227 GrGLSLUniformHandler::SamplerHandle GrSPIRVUniformHandler::addSampler(const GrBackendFormat&,
228                                                                      GrSamplerState,
229                                                                      const skgpu::Swizzle& swizzle,
230                                                                      const char* name,
231                                                                      const GrShaderCaps* caps) {
232     int binding = fSamplers.count() * 2;
233 
234     SkString mangleName = fProgramBuilder->nameVariable('s', name, /*mangle=*/true);
235     SkString layoutQualifier;
236     layoutQualifier.appendf("set = %d, binding = %d", kSamplerTextureDescriptorSet, binding);
237 
238     SPIRVUniformInfo tempInfo;
239     tempInfo.fVariable = GrShaderVar{std::move(mangleName),
240                                      SkSLType::kSampler,
241                                      GrShaderVar::TypeModifier::Uniform,
242                                      GrShaderVar::kNonArray,
243                                      std::move(layoutQualifier),
244                                      SkString()};
245 
246     tempInfo.fVisibility = kFragment_GrShaderFlag;
247     tempInfo.fOwner      = nullptr;
248     tempInfo.fRawName    = SkString(name);
249     tempInfo.fUBOOffset  = 0;
250 
251     fSamplers.push_back(tempInfo);
252     fSamplerSwizzles.push_back(swizzle);
253     SkASSERT(fSamplerSwizzles.count() == fSamplers.count());
254 
255     SkString mangleTexName = fProgramBuilder->nameVariable('t', name, /*mangle=*/true);
256     SkString texLayoutQualifier;
257     texLayoutQualifier.appendf("set = %d, binding = %d", kSamplerTextureDescriptorSet, binding + 1);
258     tempInfo.fVariable = GrShaderVar{std::move(mangleTexName),
259                                      SkSLType::kTexture2D,
260                                      GrShaderVar::TypeModifier::Uniform,
261                                      GrShaderVar::kNonArray,
262                                      std::move(texLayoutQualifier),
263                                      SkString()};
264     fTextures.push_back(tempInfo);
265 
266     SkString reference;
267     reference.printf("makeSampler2D(%s, %s)",
268                      fTextures.back().fVariable.getName().c_str(),
269                      fSamplers.back().fVariable.getName().c_str());
270     fSamplerReferences.emplace_back(std::move(reference));
271     return GrGLSLUniformHandler::SamplerHandle(fSamplers.count() - 1);
272 }
273 
samplerVariable(GrGLSLUniformHandler::SamplerHandle handle) const274 const char* GrSPIRVUniformHandler::samplerVariable(
275         GrGLSLUniformHandler::SamplerHandle handle) const {
276     return fSamplerReferences[handle.toIndex()].c_str();
277 }
278 
samplerSwizzle(GrGLSLUniformHandler::SamplerHandle handle) const279 skgpu::Swizzle GrSPIRVUniformHandler::samplerSwizzle(
280         GrGLSLUniformHandler::SamplerHandle handle) const {
281     return fSamplerSwizzles[handle.toIndex()];
282 }
283 
appendUniformDecls(GrShaderFlags visibility,SkString * out) const284 void GrSPIRVUniformHandler::appendUniformDecls(GrShaderFlags visibility, SkString* out) const {
285     auto textures = fTextures.items().begin();
286     for (const SPIRVUniformInfo& sampler : fSamplers.items()) {
287         if (sampler.fVisibility & visibility) {
288             sampler.fVariable.appendDecl(fProgramBuilder->shaderCaps(), out);
289             out->append(";\n");
290             (*textures).fVariable.appendDecl(fProgramBuilder->shaderCaps(), out);
291             out->append(";\n");
292         }
293         ++textures;
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