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