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 #include "src/gpu/ganesh/GrSPIRVUniformHandler.h"
8
9 #include "include/core/SkString.h"
10 #include "include/gpu/ganesh/GrBackendSurface.h"
11 #include "include/private/base/SkAssert.h"
12 #include "src/core/SkSLTypeShared.h"
13 #include "src/gpu/ganesh/GrShaderVar.h"
14 #include "src/gpu/ganesh/GrUtil.h"
15 #include "src/gpu/ganesh/glsl/GrGLSLProgramBuilder.h"
16
17 #include <string.h>
18 #include <algorithm>
19 #include <cstddef>
20 #include <utility>
21
22 class GrProcessor;
23 struct GrShaderCaps;
24
25 static constexpr int kUniformBinding = 0;
26 static constexpr size_t kUniformsPerBlock = 8;
27
GrSPIRVUniformHandler(GrGLSLProgramBuilder * program)28 GrSPIRVUniformHandler::GrSPIRVUniformHandler(GrGLSLProgramBuilder* program)
29 : INHERITED(program)
30 , fUniforms(kUniformsPerBlock)
31 , fSamplers(kUniformsPerBlock) {}
32
getUniformVariable(UniformHandle u) const33 const GrShaderVar& GrSPIRVUniformHandler::getUniformVariable(UniformHandle u) const {
34 return fUniforms.item(u.toIndex()).fVariable;
35 }
36
getUniformCStr(UniformHandle u) const37 const char* GrSPIRVUniformHandler::getUniformCStr(UniformHandle u) const {
38 return fUniforms.item(u.toIndex()).fVariable.getName().c_str();
39 }
40
41 // FIXME: this code was ripped from GrVkUniformHandler; should be refactored.
42 namespace {
43
sksltype_to_alignment_mask(SkSLType type)44 uint32_t sksltype_to_alignment_mask(SkSLType type) {
45 switch(type) {
46 case SkSLType::kShort: // fall through
47 case SkSLType::kUShort:
48 return 0x1;
49 case SkSLType::kShort2: // fall through
50 case SkSLType::kUShort2:
51 return 0x3;
52 case SkSLType::kShort3: // fall through
53 case SkSLType::kShort4:
54 case SkSLType::kUShort3:
55 case SkSLType::kUShort4:
56 return 0x7;
57 case SkSLType::kInt:
58 case SkSLType::kUInt:
59 return 0x3;
60 case SkSLType::kInt2:
61 case SkSLType::kUInt2:
62 return 0x7;
63 case SkSLType::kInt3:
64 case SkSLType::kUInt3:
65 case SkSLType::kInt4:
66 case SkSLType::kUInt4:
67 return 0xF;
68 case SkSLType::kHalf: // fall through
69 case SkSLType::kFloat:
70 return 0x3;
71 case SkSLType::kHalf2: // fall through
72 case SkSLType::kFloat2:
73 return 0x7;
74 case SkSLType::kHalf3: // fall through
75 case SkSLType::kFloat3:
76 return 0xF;
77 case SkSLType::kHalf4: // fall through
78 case SkSLType::kFloat4:
79 return 0xF;
80 case SkSLType::kHalf2x2: // fall through
81 case SkSLType::kFloat2x2:
82 return 0x7;
83 case SkSLType::kHalf3x3: // fall through
84 case SkSLType::kFloat3x3:
85 return 0xF;
86 case SkSLType::kHalf4x4: // fall through
87 case SkSLType::kFloat4x4:
88 return 0xF;
89
90 // This query is only valid for certain types.
91 case SkSLType::kVoid:
92 case SkSLType::kBool:
93 case SkSLType::kBool2:
94 case SkSLType::kBool3:
95 case SkSLType::kBool4:
96 case SkSLType::kTexture2DSampler:
97 case SkSLType::kTextureExternalSampler:
98 case SkSLType::kTexture2DRectSampler:
99 case SkSLType::kTexture2D:
100 case SkSLType::kSampler:
101 case SkSLType::kInput:
102 break;
103 }
104 SK_ABORT("Unexpected type");
105 }
106
sksltype_to_size(SkSLType type)107 static inline uint32_t sksltype_to_size(SkSLType type) {
108 switch(type) {
109 case SkSLType::kShort:
110 return sizeof(int16_t);
111 case SkSLType::kShort2:
112 return 2 * sizeof(int16_t);
113 case SkSLType::kShort3:
114 return 3 * sizeof(int16_t);
115 case SkSLType::kShort4:
116 return 4 * sizeof(int16_t);
117 case SkSLType::kUShort:
118 return sizeof(uint16_t);
119 case SkSLType::kUShort2:
120 return 2 * sizeof(uint16_t);
121 case SkSLType::kUShort3:
122 return 3 * sizeof(uint16_t);
123 case SkSLType::kUShort4:
124 return 4 * sizeof(uint16_t);
125 case SkSLType::kHalf: // fall through
126 case SkSLType::kFloat:
127 return sizeof(float);
128 case SkSLType::kHalf2: // fall through
129 case SkSLType::kFloat2:
130 return 2 * sizeof(float);
131 case SkSLType::kHalf3: // fall through
132 case SkSLType::kFloat3:
133 return 3 * sizeof(float);
134 case SkSLType::kHalf4: // fall through
135 case SkSLType::kFloat4:
136 return 4 * sizeof(float);
137 case SkSLType::kInt: // fall through
138 case SkSLType::kUInt:
139 return sizeof(int32_t);
140 case SkSLType::kInt2: // fall through
141 case SkSLType::kUInt2:
142 return 2 * sizeof(int32_t);
143 case SkSLType::kInt3: // fall through
144 case SkSLType::kUInt3:
145 return 3 * sizeof(int32_t);
146 case SkSLType::kInt4: // fall through
147 case SkSLType::kUInt4:
148 return 4 * sizeof(int32_t);
149 case SkSLType::kHalf2x2: // fall through
150 case SkSLType::kFloat2x2:
151 //TODO: this will be 4 * szof(float) on std430.
152 return 8 * sizeof(float);
153 case SkSLType::kHalf3x3: // fall through
154 case SkSLType::kFloat3x3:
155 return 12 * sizeof(float);
156 case SkSLType::kHalf4x4: // fall through
157 case SkSLType::kFloat4x4:
158 return 16 * sizeof(float);
159
160 // This query is only valid for certain types.
161 case SkSLType::kVoid:
162 case SkSLType::kBool:
163 case SkSLType::kBool2:
164 case SkSLType::kBool3:
165 case SkSLType::kBool4:
166 case SkSLType::kTexture2DSampler:
167 case SkSLType::kTextureExternalSampler:
168 case SkSLType::kTexture2DRectSampler:
169 case SkSLType::kTexture2D:
170 case SkSLType::kSampler:
171 case SkSLType::kInput:
172 break;
173 }
174 SK_ABORT("Unexpected type");
175 }
176
get_ubo_offset(uint32_t * currentOffset,SkSLType type,int arrayCount)177 uint32_t get_ubo_offset(uint32_t* currentOffset, SkSLType type, int arrayCount) {
178 uint32_t alignmentMask = sksltype_to_alignment_mask(type);
179 // We want to use the std140 layout here, so we must make arrays align to 16 bytes.
180 // TODO(skia:13380): make sure 2x3 and 3x2 matrices are handled properly once SkSLType adds
181 // support for non-square matrices
182 if (arrayCount || type == SkSLType::kFloat2x2 || type == SkSLType::kHalf2x2) {
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, sksltype_to_size(type));
193 SkASSERT(0 == (elementSize & 0xF));
194 *currentOffset = uniformOffset + elementSize * arrayCount;
195 } else {
196 *currentOffset = uniformOffset + sksltype_to_size(type);
197 }
198 return uniformOffset;
199 }
200
201 } // namespace
202
internalAddUniformArray(const GrProcessor * owner,uint32_t visibility,SkSLType type,const char * name,bool mangleName,int arrayCount,const char ** outName)203 GrGLSLUniformHandler::UniformHandle GrSPIRVUniformHandler::internalAddUniformArray(
204 const GrProcessor* owner,
205 uint32_t visibility,
206 SkSLType type,
207 const char* name,
208 bool mangleName,
209 int arrayCount,
210 const char** outName) {
211 char prefix = 'u';
212 if ('u' == name[0] || !strncmp(name, GR_NO_MANGLE_PREFIX, strlen(GR_NO_MANGLE_PREFIX))) {
213 prefix = '\0';
214 }
215 SkString resolvedName = fProgramBuilder->nameVariable(prefix, name, mangleName);
216
217 int offset = get_ubo_offset(&fCurrentUBOOffset, type, arrayCount);
218 SkString layoutQualifier;
219 layoutQualifier.appendf("offset = %d", offset);
220
221 SPIRVUniformInfo tempInfo;
222 tempInfo.fVariable = GrShaderVar{std::move(resolvedName),
223 type,
224 GrShaderVar::TypeModifier::None,
225 arrayCount,
226 std::move(layoutQualifier),
227 SkString()};
228
229 tempInfo.fVisibility = visibility;
230 tempInfo.fOwner = owner;
231 tempInfo.fRawName = SkString(name);
232 tempInfo.fUBOOffset = offset;
233
234 fUniforms.push_back(tempInfo);
235
236 if (outName) {
237 *outName = fUniforms.back().fVariable.c_str();
238 }
239 return GrGLSLUniformHandler::UniformHandle(fUniforms.count() - 1);
240 }
241
addSampler(const GrBackendFormat & backendFormat,GrSamplerState,const skgpu::Swizzle & swizzle,const char * name,const GrShaderCaps * caps)242 GrGLSLUniformHandler::SamplerHandle GrSPIRVUniformHandler::addSampler(
243 const GrBackendFormat& backendFormat,
244 GrSamplerState,
245 const skgpu::Swizzle& swizzle,
246 const char* name,
247 const GrShaderCaps* caps) {
248 SkASSERT(name && strlen(name));
249
250 int binding = fSamplers.count() * 2;
251
252 SkString mangleName = fProgramBuilder->nameVariable('u', name, /*mangle=*/true);
253 SkString layoutQualifier = SkStringPrintf("direct3d, set = %d, sampler = %d, texture = %d",
254 kSamplerTextureDescriptorSet,
255 binding,
256 binding + 1);
257
258 SPIRVUniformInfo& uniformInfo = fSamplers.emplace_back();
259 uniformInfo.fVariable =
260 GrShaderVar{std::move(mangleName),
261 SkSLCombinedSamplerTypeForTextureType(backendFormat.textureType()),
262 GrShaderVar::TypeModifier::None,
263 GrShaderVar::kNonArray,
264 std::move(layoutQualifier),
265 SkString()};
266
267 uniformInfo.fVisibility = kFragment_GrShaderFlag;
268 uniformInfo.fOwner = nullptr;
269 uniformInfo.fRawName = SkString(name);
270 uniformInfo.fUBOOffset = 0;
271
272 fSamplerSwizzles.push_back(swizzle);
273 SkASSERT(fSamplerSwizzles.size() == fSamplers.count());
274
275 return GrGLSLUniformHandler::SamplerHandle(fSamplers.count() - 1);
276 }
277
samplerVariable(GrGLSLUniformHandler::SamplerHandle handle) const278 const char* GrSPIRVUniformHandler::samplerVariable(
279 GrGLSLUniformHandler::SamplerHandle handle) const {
280 return fSamplers.item(handle.toIndex()).fVariable.getName().c_str();
281 }
282
samplerSwizzle(GrGLSLUniformHandler::SamplerHandle handle) const283 skgpu::Swizzle GrSPIRVUniformHandler::samplerSwizzle(
284 GrGLSLUniformHandler::SamplerHandle handle) const {
285 return fSamplerSwizzles[handle.toIndex()];
286 }
287
appendUniformDecls(GrShaderFlags visibility,SkString * out) const288 void GrSPIRVUniformHandler::appendUniformDecls(GrShaderFlags visibility, SkString* out) const {
289 for (const SPIRVUniformInfo& sampler : fSamplers.items()) {
290 if (sampler.fVisibility & visibility) {
291 sampler.fVariable.appendDecl(fProgramBuilder->shaderCaps(), out);
292 out->append(";\n");
293 }
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(¤tOffset, SkSLType::kFloat2, 0);
312 }
313