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 kShort_GrSLType: // fall through
34        case kUShort_GrSLType:
35            return 0x1;
36        case kShort2_GrSLType: // fall through
37        case kUShort2_GrSLType:
38            return 0x3;
39        case kShort3_GrSLType: // fall through
40        case kShort4_GrSLType:
41        case kUShort3_GrSLType:
42        case kUShort4_GrSLType:
43            return 0x7;
44        case kInt_GrSLType:
45        case kUInt_GrSLType:
46            return 0x3;
47        case kInt2_GrSLType:
48        case kUInt2_GrSLType:
49            return 0x7;
50        case kInt3_GrSLType:
51        case kUInt3_GrSLType:
52        case kInt4_GrSLType:
53        case kUInt4_GrSLType:
54            return 0xF;
55        case kHalf_GrSLType: // fall through
56        case kFloat_GrSLType:
57            return 0x3;
58        case kHalf2_GrSLType: // fall through
59        case kFloat2_GrSLType:
60            return 0x7;
61        case kHalf3_GrSLType: // fall through
62        case kFloat3_GrSLType:
63            return 0xF;
64        case kHalf4_GrSLType: // fall through
65        case kFloat4_GrSLType:
66            return 0xF;
67        case kHalf2x2_GrSLType: // fall through
68        case kFloat2x2_GrSLType:
69            return 0x7;
70        case kHalf3x3_GrSLType: // fall through
71        case kFloat3x3_GrSLType:
72            return 0xF;
73        case kHalf4x4_GrSLType: // fall through
74        case kFloat4x4_GrSLType:
75            return 0xF;
76
77        // This query is only valid for certain types.
78        case kVoid_GrSLType:
79        case kBool_GrSLType:
80        case kBool2_GrSLType:
81        case kBool3_GrSLType:
82        case kBool4_GrSLType:
83        case kTexture2DSampler_GrSLType:
84        case kTextureExternalSampler_GrSLType:
85        case kTexture2DRectSampler_GrSLType:
86        case kTexture2D_GrSLType:
87        case kSampler_GrSLType:
88        case kInput_GrSLType:
89            break;
90    }
91    SK_ABORT("Unexpected type");
92}
93
94static inline uint32_t grsltype_to_size(GrSLType type) {
95    switch(type) {
96        case kShort_GrSLType:
97            return sizeof(int16_t);
98        case kShort2_GrSLType:
99            return 2 * sizeof(int16_t);
100        case kShort3_GrSLType:
101            return 3 * sizeof(int16_t);
102        case kShort4_GrSLType:
103            return 4 * sizeof(int16_t);
104        case kUShort_GrSLType:
105            return sizeof(uint16_t);
106        case kUShort2_GrSLType:
107            return 2 * sizeof(uint16_t);
108        case kUShort3_GrSLType:
109            return 3 * sizeof(uint16_t);
110        case kUShort4_GrSLType:
111            return 4 * sizeof(uint16_t);
112        case kHalf_GrSLType: // fall through
113        case kFloat_GrSLType:
114            return sizeof(float);
115        case kHalf2_GrSLType: // fall through
116        case kFloat2_GrSLType:
117            return 2 * sizeof(float);
118        case kHalf3_GrSLType: // fall through
119        case kFloat3_GrSLType:
120            return 3 * sizeof(float);
121        case kHalf4_GrSLType: // fall through
122        case kFloat4_GrSLType:
123            return 4 * sizeof(float);
124        case kInt_GrSLType: // fall through
125        case kUInt_GrSLType:
126            return sizeof(int32_t);
127        case kInt2_GrSLType: // fall through
128        case kUInt2_GrSLType:
129            return 2 * sizeof(int32_t);
130        case kInt3_GrSLType: // fall through
131        case kUInt3_GrSLType:
132            return 3 * sizeof(int32_t);
133        case kInt4_GrSLType: // fall through
134        case kUInt4_GrSLType:
135            return 4 * sizeof(int32_t);
136        case kHalf2x2_GrSLType: // fall through
137        case kFloat2x2_GrSLType:
138            //TODO: this will be 4 * szof(float) on std430.
139            return 8 * sizeof(float);
140        case kHalf3x3_GrSLType: // fall through
141        case kFloat3x3_GrSLType:
142            return 12 * sizeof(float);
143        case kHalf4x4_GrSLType: // fall through
144        case kFloat4x4_GrSLType:
145            return 16 * sizeof(float);
146
147        // This query is only valid for certain types.
148        case kVoid_GrSLType:
149        case kBool_GrSLType:
150        case kBool2_GrSLType:
151        case kBool3_GrSLType:
152        case kBool4_GrSLType:
153        case kTexture2DSampler_GrSLType:
154        case kTextureExternalSampler_GrSLType:
155        case kTexture2DRectSampler_GrSLType:
156        case kTexture2D_GrSLType:
157        case kSampler_GrSLType:
158        case kInput_GrSLType:
159            break;
160    }
161    SK_ABORT("Unexpected type");
162}
163
164uint32_t get_ubo_offset(uint32_t* currentOffset, GrSLType type, int arrayCount) {
165    uint32_t alignmentMask = grsltype_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 == kFloat2x2_GrSLType) {
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, grsltype_to_size(type));
178        SkASSERT(0 == (elementSize & 0xF));
179        *currentOffset = uniformOffset + elementSize * arrayCount;
180    } else {
181        *currentOffset = uniformOffset + grsltype_to_size(type);
182    }
183    return uniformOffset;
184}
185
186}  // namespace
187
188GrGLSLUniformHandler::UniformHandle GrSPIRVUniformHandler::internalAddUniformArray(
189        const GrFragmentProcessor* owner,
190        uint32_t visibility,
191        GrSLType 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
227GrGLSLUniformHandler::SamplerHandle GrSPIRVUniformHandler::addSampler(const GrBackendFormat&,
228                                                                     GrSamplerState,
229                                                                     const GrSwizzle& 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                                     kSampler_GrSLType,
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                                     kTexture2D_GrSLType,
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
274const char* GrSPIRVUniformHandler::samplerVariable(
275        GrGLSLUniformHandler::SamplerHandle handle) const {
276    return fSamplerReferences[handle.toIndex()].c_str();
277}
278
279GrSwizzle GrSPIRVUniformHandler::samplerSwizzle(GrGLSLUniformHandler::SamplerHandle handle) const {
280    return fSamplerSwizzles[handle.toIndex()];
281}
282
283void GrSPIRVUniformHandler::appendUniformDecls(GrShaderFlags visibility, SkString* out) const {
284    auto textures = fTextures.items().begin();
285    for (const SPIRVUniformInfo& sampler : fSamplers.items()) {
286        if (sampler.fVisibility & visibility) {
287            sampler.fVariable.appendDecl(fProgramBuilder->shaderCaps(), out);
288            out->append(";\n");
289            (*textures).fVariable.appendDecl(fProgramBuilder->shaderCaps(), out);
290            out->append(";\n");
291        }
292        ++textures;
293    }
294    SkString uniformsString;
295    for (const UniformInfo& uniform : fUniforms.items()) {
296        if (uniform.fVisibility & visibility) {
297            uniform.fVariable.appendDecl(fProgramBuilder->shaderCaps(), &uniformsString);
298            uniformsString.append(";\n");
299        }
300    }
301    if (!uniformsString.isEmpty()) {
302        out->appendf("layout (set = %d, binding = %d) uniform UniformBuffer\n{\n",
303                     kUniformDescriptorSet, kUniformBinding);
304        out->appendf("%s\n};\n", uniformsString.c_str());
305    }
306}
307
308uint32_t GrSPIRVUniformHandler::getRTFlipOffset() const {
309    uint32_t currentOffset = fCurrentUBOOffset;
310    return get_ubo_offset(&currentOffset, kFloat2_GrSLType, 0);
311}
312