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
12GrSPIRVUniformHandler::GrSPIRVUniformHandler(GrGLSLProgramBuilder* program)
13 : INHERITED(program)
14 , fUniforms(kUniformsPerBlock)
15 , fSamplers(kUniformsPerBlock)
16 , fTextures(kUniformsPerBlock)
17{
18}
19
20const GrShaderVar& GrSPIRVUniformHandler::getUniformVariable(UniformHandle u) const {
21 return fUniforms.item(u.toIndex()).fVariable;
22}
23
24const 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.
29namespace {
30
31uint32_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 break;
97 }
98 SK_ABORT("Unexpected type");
99}
100
101static inline uint32_t grsltype_to_size(GrSLType type) {
102 switch(type) {
103 case kByte_GrSLType:
104 case kUByte_GrSLType:
105 return 1;
106 case kByte2_GrSLType:
107 case kUByte2_GrSLType:
108 return 2;
109 case kByte3_GrSLType:
110 case kUByte3_GrSLType:
111 return 3;
112 case kByte4_GrSLType:
113 case kUByte4_GrSLType:
114 return 4;
115 case kShort_GrSLType:
116 return sizeof(int16_t);
117 case kShort2_GrSLType:
118 return 2 * sizeof(int16_t);
119 case kShort3_GrSLType:
120 return 3 * sizeof(int16_t);
121 case kShort4_GrSLType:
122 return 4 * sizeof(int16_t);
123 case kUShort_GrSLType:
124 return sizeof(uint16_t);
125 case kUShort2_GrSLType:
126 return 2 * sizeof(uint16_t);
127 case kUShort3_GrSLType:
128 return 3 * sizeof(uint16_t);
129 case kUShort4_GrSLType:
130 return 4 * sizeof(uint16_t);
131 case kInt_GrSLType:
132 return sizeof(int32_t);
133 case kUint_GrSLType:
134 return sizeof(int32_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 kUint2_GrSLType:
148 return 2 * sizeof(uint32_t);
149 case kInt2_GrSLType:
150 return 2 * sizeof(int32_t);
151 case kInt3_GrSLType:
152 return 3 * sizeof(int32_t);
153 case kInt4_GrSLType:
154 return 4 * sizeof(int32_t);
155 case kHalf2x2_GrSLType: // fall through
156 case kFloat2x2_GrSLType:
157 //TODO: this will be 4 * szof(float) on std430.
158 return 8 * sizeof(float);
159 case kHalf3x3_GrSLType: // fall through
160 case kFloat3x3_GrSLType:
161 return 12 * sizeof(float);
162 case kHalf4x4_GrSLType: // fall through
163 case kFloat4x4_GrSLType:
164 return 16 * sizeof(float);
165
166 // This query is only valid for certain types.
167 case kVoid_GrSLType:
168 case kBool_GrSLType:
169 case kTexture2DSampler_GrSLType:
170 case kTextureExternalSampler_GrSLType:
171 case kTexture2DRectSampler_GrSLType:
172 case kTexture2D_GrSLType:
173 case kSampler_GrSLType:
174 break;
175 }
176 SK_ABORT("Unexpected type");
177}
178
179uint32_t get_ubo_offset(uint32_t* currentOffset, GrSLType type, int arrayCount) {
180 uint32_t alignmentMask = grsltype_to_alignment_mask(type);
181 // We want to use the std140 layout here, so we must make arrays align to 16 bytes.
182 if (arrayCount || type == kFloat2x2_GrSLType) {
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, grsltype_to_size(type));
193 SkASSERT(0 == (elementSize & 0xF));
194 *currentOffset = uniformOffset + elementSize * arrayCount;
195 } else {
196 *currentOffset = uniformOffset + grsltype_to_size(type);
197 }
198 return uniformOffset;
199}
200
201} // namespace
202
203GrGLSLUniformHandler::UniformHandle GrSPIRVUniformHandler::internalAddUniformArray(
204 const GrFragmentProcessor* owner,
205 uint32_t visibility,
206 GrSLType type,
207 const char* name,
208 bool mangleName,
209 int arrayCount,
210 const char** outName) {
211 SkString resolvedName;
212 char prefix = 'u';
213 if ('u' == name[0] || !strncmp(name, GR_NO_MANGLE_PREFIX, strlen(GR_NO_MANGLE_PREFIX))) {
214 prefix = '\0';
215 }
216 fProgramBuilder->nameVariable(&resolvedName, prefix, name, mangleName);
217
218 int offset = get_ubo_offset(&fCurrentUBOOffset, type, arrayCount);
219 SkString layoutQualifier;
220 layoutQualifier.appendf("offset = %d", offset);
221
222 UniformInfo& info = fUniforms.push_back(SPIRVUniformInfo{
223 {
224 GrShaderVar{std::move(resolvedName), type, GrShaderVar::TypeModifier::None, arrayCount,
225 std::move(layoutQualifier), SkString()},
226 visibility, owner, SkString(name)
227 },
228 offset
229 });
230
231 if (outName) {
232 *outName = info.fVariable.c_str();
233 }
234 return GrGLSLUniformHandler::UniformHandle(fUniforms.count() - 1);
235}
236
237GrGLSLUniformHandler::SamplerHandle GrSPIRVUniformHandler::addSampler(const GrBackendFormat&,
238 GrSamplerState,
239 const GrSwizzle& swizzle,
240 const char* name,
241 const GrShaderCaps* caps) {
242 int binding = fSamplers.count() * 2;
243
244 SkString mangleName;
245 fProgramBuilder->nameVariable(&mangleName, 's', name, 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;
262 fProgramBuilder->nameVariable(&mangleTexName, 't', name, true);
263 SkString texLayoutQualifier;
264 texLayoutQualifier.appendf("set = %d, binding = %d", kSamplerTextureDescriptorSet, binding + 1);
265 UniformInfo& texInfo = fTextures.push_back(SPIRVUniformInfo{
266 {
267 GrShaderVar{std::move(mangleTexName), kTexture2D_GrSLType,
268 GrShaderVar::TypeModifier::Uniform, GrShaderVar::kNonArray,
269 std::move(texLayoutQualifier), SkString()},
270 kFragment_GrShaderFlag, nullptr, SkString(name)
271 },
272 0
273 });
274
275 SkString reference;
276 reference.printf("makeSampler2D(%s, %s)", texInfo.fVariable.getName().c_str(),
277 info.fVariable.getName().c_str());
278 fSamplerReferences.emplace_back(std::move(reference));
279 return GrGLSLUniformHandler::SamplerHandle(fSamplers.count() - 1);
280}
281
282const char* GrSPIRVUniformHandler::samplerVariable(
283 GrGLSLUniformHandler::SamplerHandle handle) const {
284 return fSamplerReferences[handle.toIndex()].c_str();
285}
286
287GrSwizzle GrSPIRVUniformHandler::samplerSwizzle(GrGLSLUniformHandler::SamplerHandle handle) const {
288 return fSamplerSwizzles[handle.toIndex()];
289}
290
291void GrSPIRVUniformHandler::appendUniformDecls(GrShaderFlags visibility, SkString* out) const {
292 auto textures = fTextures.items().begin();
293 for (const SPIRVUniformInfo& sampler : fSamplers.items()) {
294 if (sampler.fVisibility & visibility) {
295 sampler.fVariable.appendDecl(fProgramBuilder->shaderCaps(), out);
296 out->append(";\n");
297 (*textures).fVariable.appendDecl(fProgramBuilder->shaderCaps(), out);
298 out->append(";\n");
299 }
300 ++textures;
301 }
302 SkString uniformsString;
303 for (const UniformInfo& uniform : fUniforms.items()) {
304 if (uniform.fVisibility & visibility) {
305 uniform.fVariable.appendDecl(fProgramBuilder->shaderCaps(), &uniformsString);
306 uniformsString.append(";\n");
307 }
308 }
309 if (!uniformsString.isEmpty()) {
310 out->appendf("layout (set = %d, binding = %d) uniform UniformBuffer\n{\n",
311 kUniformDescriptorSet, kUniformBinding);
312 out->appendf("%s\n};\n", uniformsString.c_str());
313 }
314}
315
316uint32_t GrSPIRVUniformHandler::getRTHeightOffset() const {
317 uint32_t dummy = fCurrentUBOOffset;
318 return get_ubo_offset(&dummy, kFloat_GrSLType, 0);
319}
320