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 | |
12 | GrSPIRVUniformHandler::GrSPIRVUniformHandler(GrGLSLProgramBuilder* program) |
13 | : INHERITED(program) |
14 | , fUniforms(kUniformsPerBlock) |
15 | , fSamplers(kUniformsPerBlock) |
16 | , fTextures(kUniformsPerBlock) |
17 | { |
18 | } |
19 | |
20 | const GrShaderVar& GrSPIRVUniformHandler::getUniformVariable(UniformHandle u) const { |
21 | return fUniforms.item(u.toIndex()).fVariable; |
22 | } |
23 | |
24 | 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 | |
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 | break; |
97 | } |
98 | SK_ABORT("Unexpected type" ); |
99 | } |
100 | |
101 | static 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 | |
179 | uint32_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 | |
203 | GrGLSLUniformHandler::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 | |
237 | GrGLSLUniformHandler::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 | |
282 | const char* GrSPIRVUniformHandler::samplerVariable( |
283 | GrGLSLUniformHandler::SamplerHandle handle) const { |
284 | return fSamplerReferences[handle.toIndex()].c_str(); |
285 | } |
286 | |
287 | GrSwizzle GrSPIRVUniformHandler::samplerSwizzle(GrGLSLUniformHandler::SamplerHandle handle) const { |
288 | return fSamplerSwizzles[handle.toIndex()]; |
289 | } |
290 | |
291 | void 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 | |
316 | uint32_t GrSPIRVUniformHandler::getRTHeightOffset() const { |
317 | uint32_t dummy = fCurrentUBOOffset; |
318 | return get_ubo_offset(&dummy, kFloat_GrSLType, 0); |
319 | } |
320 | |