1 /*
2 * Copyright 2016 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 "GrVkUniformHandler.h"
9 #include "glsl/GrGLSLProgramBuilder.h"
10 
11 // To determine whether a current offset is aligned, we can just 'and' the lowest bits with the
12 // alignment mask. A value of 0 means aligned, any other value is how many bytes past alignment we
13 // are. This works since all alignments are powers of 2. The mask is always (alignment - 1).
grsltype_to_alignment_mask(GrSLType type)14 uint32_t grsltype_to_alignment_mask(GrSLType type) {
15     SkASSERT(GrSLTypeIsFloatType(type));
16     static const uint32_t kAlignments[kGrSLTypeCount] = {
17         0x0, // kVoid_GrSLType, should never return this
18         0x3, // kFloat_GrSLType
19         0x7, // kVec2f_GrSLType
20         0xF, // kVec3f_GrSLType
21         0xF, // kVec4f_GrSLType
22         0xF, // kMat33f_GrSLType
23         0xF, // kMat44f_GrSLType
24         0x0, // Sampler2D_GrSLType, should never return this
25         0x0, // SamplerExternal_GrSLType, should never return this
26     };
27     GR_STATIC_ASSERT(0 == kVoid_GrSLType);
28     GR_STATIC_ASSERT(1 == kFloat_GrSLType);
29     GR_STATIC_ASSERT(2 == kVec2f_GrSLType);
30     GR_STATIC_ASSERT(3 == kVec3f_GrSLType);
31     GR_STATIC_ASSERT(4 == kVec4f_GrSLType);
32     GR_STATIC_ASSERT(5 == kMat33f_GrSLType);
33     GR_STATIC_ASSERT(6 == kMat44f_GrSLType);
34     GR_STATIC_ASSERT(7 == kSampler2D_GrSLType);
35     GR_STATIC_ASSERT(8 == kSamplerExternal_GrSLType);
36     GR_STATIC_ASSERT(SK_ARRAY_COUNT(kAlignments) == kGrSLTypeCount);
37     return kAlignments[type];
38 }
39 
40 // Given the current offset into the ubo, calculate the offset for the uniform we're trying to add
41 // taking into consideration all alignment requirements. The uniformOffset is set to the offset for
42 // the new uniform, and currentOffset is updated to be the offset to the end of the new uniform.
get_ubo_aligned_offset(uint32_t * uniformOffset,uint32_t * currentOffset,GrSLType type,int arrayCount)43 void get_ubo_aligned_offset(uint32_t* uniformOffset,
44                             uint32_t* currentOffset,
45                             GrSLType type,
46                             int arrayCount) {
47     uint32_t alignmentMask = grsltype_to_alignment_mask(type);
48     uint32_t offsetDiff = *currentOffset & alignmentMask;
49     if (offsetDiff != 0) {
50         offsetDiff = alignmentMask - offsetDiff + 1;
51     }
52     *uniformOffset = *currentOffset + offsetDiff;
53     SkASSERT(sizeof(float) == 4);
54     // We use a 0 arrayCount to indicate it is not an array type but we still need to count the one
55     // object.
56     int count = arrayCount ? arrayCount : 1;
57     *currentOffset = *uniformOffset + count * (uint32_t)GrSLTypeSize(type);
58 }
59 
internalAddUniformArray(uint32_t visibility,GrSLType type,GrSLPrecision precision,const char * name,bool mangleName,int arrayCount,const char ** outName)60 GrGLSLUniformHandler::UniformHandle GrVkUniformHandler::internalAddUniformArray(
61                                                                             uint32_t visibility,
62                                                                             GrSLType type,
63                                                                             GrSLPrecision precision,
64                                                                             const char* name,
65                                                                             bool mangleName,
66                                                                             int arrayCount,
67                                                                             const char** outName) {
68     SkASSERT(name && strlen(name));
69     SkDEBUGCODE(static const uint32_t kVisibilityMask = kVertex_GrShaderFlag|kFragment_GrShaderFlag);
70     SkASSERT(0 == (~kVisibilityMask & visibility));
71     SkASSERT(0 != visibility);
72     SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeIsFloatType(type));
73 
74     UniformInfo& uni = fUniforms.push_back();
75     uni.fVariable.setType(type);
76     // TODO this is a bit hacky, lets think of a better way.  Basically we need to be able to use
77     // the uniform view matrix name in the GP, and the GP is immutable so it has to tell the PB
78     // exactly what name it wants to use for the uniform view matrix.  If we prefix anythings, then
79     // the names will mismatch.  I think the correct solution is to have all GPs which need the
80     // uniform view matrix, they should upload the view matrix in their setData along with regular
81     // uniforms.
82     char prefix = 'u';
83     if ('u' == name[0]) {
84         prefix = '\0';
85     }
86     fProgramBuilder->nameVariable(uni.fVariable.accessName(), prefix, name, mangleName);
87     uni.fVariable.setArrayCount(arrayCount);
88     // For now asserting the the visibility is either only vertex or only fragment
89     SkASSERT(kVertex_GrShaderFlag == visibility || kFragment_GrShaderFlag == visibility);
90     uni.fVisibility = visibility;
91     uni.fVariable.setPrecision(precision);
92     if (GrSLTypeIsFloatType(type)) {
93         // When outputing the GLSL, only the outer uniform block will get the Uniform modifier. Thus
94         // we set the modifier to none for all uniforms declared inside the block.
95         uni.fVariable.setTypeModifier(GrGLSLShaderVar::kNone_TypeModifier);
96 
97         uint32_t* currentOffset = kVertex_GrShaderFlag == visibility ? &fCurrentVertexUBOOffset
98                                                                      : &fCurrentFragmentUBOOffset;
99         get_ubo_aligned_offset(&uni.fUBOffset, currentOffset, type, arrayCount);
100         uni.fSetNumber = kUniformBufferDescSet;
101         uni.fBinding = kVertex_GrShaderFlag == visibility ? kVertexBinding : kFragBinding;
102 
103         if (outName) {
104             *outName = uni.fVariable.c_str();
105         }
106     } else {
107         SkASSERT(type == kSampler2D_GrSLType);
108         uni.fVariable.setTypeModifier(GrGLSLShaderVar::kUniform_TypeModifier);
109 
110         uni.fSetNumber = kSamplerDescSet;
111         uni.fBinding = fCurrentSamplerBinding++;
112         uni.fUBOffset = 0; // This value will be ignored, but initializing to avoid any errors.
113         SkString layoutQualifier;
114         layoutQualifier.appendf("set=%d, binding=%d", uni.fSetNumber, uni.fBinding);
115         uni.fVariable.setLayoutQualifier(layoutQualifier.c_str());
116     }
117 
118     return GrGLSLUniformHandler::UniformHandle(fUniforms.count() - 1);
119 }
120 
appendUniformDecls(GrShaderFlags visibility,SkString * out) const121 void GrVkUniformHandler::appendUniformDecls(GrShaderFlags visibility, SkString* out) const {
122     SkTArray<UniformInfo*> uniformBufferUniform;
123     // Used to collect all the variables that will be place inside the uniform buffer
124     SkString uniformsString;
125     SkASSERT(kVertex_GrShaderFlag == visibility || kFragment_GrShaderFlag == visibility);
126     uint32_t uniformBinding = (visibility == kVertex_GrShaderFlag) ? kVertexBinding : kFragBinding;
127     for (int i = 0; i < fUniforms.count(); ++i) {
128         const UniformInfo& localUniform = fUniforms[i];
129         if (visibility == localUniform.fVisibility) {
130             if (GrSLTypeIsFloatType(localUniform.fVariable.getType())) {
131                 SkASSERT(uniformBinding == localUniform.fBinding);
132                 SkASSERT(kUniformBufferDescSet == localUniform.fSetNumber);
133                 localUniform.fVariable.appendDecl(fProgramBuilder->glslCaps(), &uniformsString);
134                 uniformsString.append(";\n");
135             } else {
136                 SkASSERT(localUniform.fVariable.getType() == kSampler2D_GrSLType);
137                 SkASSERT(kSamplerDescSet == localUniform.fSetNumber);
138                 localUniform.fVariable.appendDecl(fProgramBuilder->glslCaps(), out);
139                 out->append(";\n");
140             }
141         }
142     }
143     if (!uniformsString.isEmpty()) {
144         const char* stage = (visibility == kVertex_GrShaderFlag) ? "vertex" : "fragment";
145         out->appendf("layout (set=%d, binding=%d) uniform %sUniformBuffer\n{\n",
146                      kUniformBufferDescSet, uniformBinding, stage);
147         out->appendf("%s\n};\n", uniformsString.c_str());
148     }
149 }