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 10 #include "GrTexturePriv.h" 11 #include "GrVkGpu.h" 12 #include "GrVkPipelineStateBuilder.h" 13 #include "GrVkTexture.h" 14 #include "glsl/GrGLSLProgramBuilder.h" 15 16 // To determine whether a current offset is aligned, we can just 'and' the lowest bits with the 17 // alignment mask. A value of 0 means aligned, any other value is how many bytes past alignment we 18 // are. This works since all alignments are powers of 2. The mask is always (alignment - 1). 19 // This alignment mask will give correct alignments for using the std430 block layout. If you want 20 // the std140 alignment, you can use this, but then make sure if you have an array type it is 21 // aligned to 16 bytes (i.e. has mask of 0xF). 22 // These are designated in the Vulkan spec, section 14.5.4 "Offset and Stride Assignment". 23 // https://www.khronos.org/registry/vulkan/specs/1.0-wsi_extensions/html/vkspec.html#interfaces-resources-layout 24 static uint32_t grsltype_to_alignment_mask(GrSLType type) { 25 switch(type) { 26 case kByte_GrSLType: // fall through 27 case kUByte_GrSLType: 28 return 0x0; 29 case kByte2_GrSLType: // fall through 30 case kUByte2_GrSLType: 31 return 0x1; 32 case kByte3_GrSLType: // fall through 33 case kByte4_GrSLType: 34 case kUByte3_GrSLType: 35 case kUByte4_GrSLType: 36 return 0x3; 37 case kShort_GrSLType: // fall through 38 case kUShort_GrSLType: 39 return 0x1; 40 case kShort2_GrSLType: // fall through 41 case kUShort2_GrSLType: 42 return 0x3; 43 case kShort3_GrSLType: // fall through 44 case kShort4_GrSLType: 45 case kUShort3_GrSLType: 46 case kUShort4_GrSLType: 47 return 0x7; 48 case kInt_GrSLType: 49 case kUint_GrSLType: 50 return 0x3; 51 case kHalf_GrSLType: // fall through 52 case kFloat_GrSLType: 53 return 0x3; 54 case kHalf2_GrSLType: // fall through 55 case kFloat2_GrSLType: 56 return 0x7; 57 case kHalf3_GrSLType: // fall through 58 case kFloat3_GrSLType: 59 return 0xF; 60 case kHalf4_GrSLType: // fall through 61 case kFloat4_GrSLType: 62 return 0xF; 63 case kUint2_GrSLType: 64 return 0x7; 65 case kInt2_GrSLType: 66 return 0x7; 67 case kInt3_GrSLType: 68 return 0xF; 69 case kInt4_GrSLType: 70 return 0xF; 71 case kHalf2x2_GrSLType: // fall through 72 case kFloat2x2_GrSLType: 73 return 0x7; 74 case kHalf3x3_GrSLType: // fall through 75 case kFloat3x3_GrSLType: 76 return 0xF; 77 case kHalf4x4_GrSLType: // fall through 78 case kFloat4x4_GrSLType: 79 return 0xF; 80 81 // This query is only valid for certain types. 82 case kVoid_GrSLType: 83 case kBool_GrSLType: 84 case kTexture2DSampler_GrSLType: 85 case kTextureExternalSampler_GrSLType: 86 case kTexture2DRectSampler_GrSLType: 87 break; 88 } 89 SK_ABORT("Unexpected type"); 90 return 0; 91 } 92 93 /** Returns the size in bytes taken up in vulkanbuffers for GrSLTypes. */ 94 static inline uint32_t grsltype_to_vk_size(GrSLType type) { 95 switch(type) { 96 case kByte_GrSLType: 97 return sizeof(int8_t); 98 case kByte2_GrSLType: 99 return 2 * sizeof(int8_t); 100 case kByte3_GrSLType: 101 return 3 * sizeof(int8_t); 102 case kByte4_GrSLType: 103 return 4 * sizeof(int8_t); 104 case kUByte_GrSLType: 105 return sizeof(uint8_t); 106 case kUByte2_GrSLType: 107 return 2 * sizeof(uint8_t); 108 case kUByte3_GrSLType: 109 return 3 * sizeof(uint8_t); 110 case kUByte4_GrSLType: 111 return 4 * sizeof(uint8_t); 112 case kShort_GrSLType: 113 return sizeof(int16_t); 114 case kShort2_GrSLType: 115 return 2 * sizeof(int16_t); 116 case kShort3_GrSLType: 117 return 3 * sizeof(int16_t); 118 case kShort4_GrSLType: 119 return 4 * sizeof(int16_t); 120 case kUShort_GrSLType: 121 return sizeof(uint16_t); 122 case kUShort2_GrSLType: 123 return 2 * sizeof(uint16_t); 124 case kUShort3_GrSLType: 125 return 3 * sizeof(uint16_t); 126 case kUShort4_GrSLType: 127 return 4 * sizeof(uint16_t); 128 case kInt_GrSLType: 129 return sizeof(int32_t); 130 case kUint_GrSLType: 131 return sizeof(int32_t); 132 case kHalf_GrSLType: // fall through 133 case kFloat_GrSLType: 134 return sizeof(float); 135 case kHalf2_GrSLType: // fall through 136 case kFloat2_GrSLType: 137 return 2 * sizeof(float); 138 case kHalf3_GrSLType: // fall through 139 case kFloat3_GrSLType: 140 return 3 * sizeof(float); 141 case kHalf4_GrSLType: // fall through 142 case kFloat4_GrSLType: 143 return 4 * sizeof(float); 144 case kUint2_GrSLType: 145 return 2 * sizeof(uint32_t); 146 case kInt2_GrSLType: 147 return 2 * sizeof(int32_t); 148 case kInt3_GrSLType: 149 return 3 * sizeof(int32_t); 150 case kInt4_GrSLType: 151 return 4 * sizeof(int32_t); 152 case kHalf2x2_GrSLType: // fall through 153 case kFloat2x2_GrSLType: 154 //TODO: this will be 4 * szof(float) on std430. 155 return 8 * sizeof(float); 156 case kHalf3x3_GrSLType: // fall through 157 case kFloat3x3_GrSLType: 158 return 12 * sizeof(float); 159 case kHalf4x4_GrSLType: // fall through 160 case kFloat4x4_GrSLType: 161 return 16 * sizeof(float); 162 163 // This query is only valid for certain types. 164 case kVoid_GrSLType: 165 case kBool_GrSLType: 166 case kTexture2DSampler_GrSLType: 167 case kTextureExternalSampler_GrSLType: 168 case kTexture2DRectSampler_GrSLType: 169 break; 170 } 171 SK_ABORT("Unexpected type"); 172 return 0; 173 } 174 175 176 // Given the current offset into the ubo, calculate the offset for the uniform we're trying to add 177 // taking into consideration all alignment requirements. The uniformOffset is set to the offset for 178 // the new uniform, and currentOffset is updated to be the offset to the end of the new uniform. 179 static void get_ubo_aligned_offset(uint32_t* uniformOffset, 180 uint32_t* currentOffset, 181 GrSLType type, 182 int arrayCount) { 183 uint32_t alignmentMask = grsltype_to_alignment_mask(type); 184 // We want to use the std140 layout here, so we must make arrays align to 16 bytes. 185 if (arrayCount || type == kFloat2x2_GrSLType) { 186 alignmentMask = 0xF; 187 } 188 uint32_t offsetDiff = *currentOffset & alignmentMask; 189 if (offsetDiff != 0) { 190 offsetDiff = alignmentMask - offsetDiff + 1; 191 } 192 *uniformOffset = *currentOffset + offsetDiff; 193 SkASSERT(sizeof(float) == 4); 194 if (arrayCount) { 195 uint32_t elementSize = SkTMax<uint32_t>(16, grsltype_to_vk_size(type)); 196 SkASSERT(0 == (elementSize & 0xF)); 197 *currentOffset = *uniformOffset + elementSize * arrayCount; 198 } else { 199 *currentOffset = *uniformOffset + grsltype_to_vk_size(type); 200 } 201 } 202 203 GrGLSLUniformHandler::UniformHandle GrVkUniformHandler::internalAddUniformArray( 204 uint32_t visibility, 205 GrSLType type, 206 const char* name, 207 bool mangleName, 208 int arrayCount, 209 const char** outName) { 210 SkASSERT(name && strlen(name)); 211 // For now asserting the the visibility is either geometry types (vertex, tesselation, geometry, 212 // etc.) or only fragment. 213 SkASSERT(kVertex_GrShaderFlag == visibility || 214 kGeometry_GrShaderFlag == visibility || 215 (kVertex_GrShaderFlag | kGeometry_GrShaderFlag) == visibility || 216 kFragment_GrShaderFlag == visibility); 217 GrSLTypeIsFloatType(type); 218 219 UniformInfo& uni = fUniforms.push_back(); 220 uni.fVariable.setType(type); 221 // TODO this is a bit hacky, lets think of a better way. Basically we need to be able to use 222 // the uniform view matrix name in the GP, and the GP is immutable so it has to tell the PB 223 // exactly what name it wants to use for the uniform view matrix. If we prefix anythings, then 224 // the names will mismatch. I think the correct solution is to have all GPs which need the 225 // uniform view matrix, they should upload the view matrix in their setData along with regular 226 // uniforms. 227 char prefix = 'u'; 228 if ('u' == name[0] || !strncmp(name, GR_NO_MANGLE_PREFIX, strlen(GR_NO_MANGLE_PREFIX))) { 229 prefix = '\0'; 230 } 231 fProgramBuilder->nameVariable(uni.fVariable.accessName(), prefix, name, mangleName); 232 uni.fVariable.setArrayCount(arrayCount); 233 uni.fVisibility = visibility; 234 // When outputing the GLSL, only the outer uniform block will get the Uniform modifier. Thus 235 // we set the modifier to none for all uniforms declared inside the block. 236 uni.fVariable.setTypeModifier(GrShaderVar::kNone_TypeModifier); 237 238 uint32_t* currentOffset; 239 uint32_t geomStages = kVertex_GrShaderFlag | kGeometry_GrShaderFlag; 240 if (geomStages & visibility) { 241 currentOffset = &fCurrentGeometryUBOOffset; 242 } else { 243 SkASSERT(kFragment_GrShaderFlag == visibility); 244 currentOffset = &fCurrentFragmentUBOOffset; 245 } 246 get_ubo_aligned_offset(&uni.fUBOffset, currentOffset, type, arrayCount); 247 248 SkString layoutQualifier; 249 layoutQualifier.appendf("offset=%d", uni.fUBOffset); 250 uni.fVariable.addLayoutQualifier(layoutQualifier.c_str()); 251 252 if (outName) { 253 *outName = uni.fVariable.c_str(); 254 } 255 256 return GrGLSLUniformHandler::UniformHandle(fUniforms.count() - 1); 257 } 258 259 GrGLSLUniformHandler::SamplerHandle GrVkUniformHandler::addSampler(const GrTexture* texture, 260 const GrSamplerState& state, 261 const char* name, 262 const GrShaderCaps* shaderCaps) { 263 SkASSERT(name && strlen(name)); 264 SkString mangleName; 265 char prefix = 'u'; 266 fProgramBuilder->nameVariable(&mangleName, prefix, name, true); 267 268 GrSwizzle swizzle = shaderCaps->configTextureSwizzle(texture->config()); 269 GrTextureType type = texture->texturePriv().textureType(); 270 271 UniformInfo& info = fSamplers.push_back(); 272 info.fVariable.setType(GrSLCombinedSamplerTypeForTextureType(type)); 273 info.fVariable.setTypeModifier(GrShaderVar::kUniform_TypeModifier); 274 info.fVariable.setName(mangleName); 275 SkString layoutQualifier; 276 layoutQualifier.appendf("set=%d, binding=%d", kSamplerDescSet, fSamplers.count() - 1); 277 info.fVariable.addLayoutQualifier(layoutQualifier.c_str()); 278 info.fVisibility = kFragment_GrShaderFlag; 279 info.fUBOffset = 0; 280 281 // Check if we are dealing with an external texture and store the needed information if so 282 const GrVkTexture* vkTexture = static_cast<const GrVkTexture*>(texture); 283 if (vkTexture->ycbcrConversionInfo().isValid()) { 284 SkASSERT(type == GrTextureType::kExternal); 285 GrVkGpu* gpu = static_cast<GrVkPipelineStateBuilder*>(fProgramBuilder)->gpu(); 286 info.fImmutableSampler = gpu->resourceProvider().findOrCreateCompatibleSampler( 287 state, vkTexture->ycbcrConversionInfo()); 288 SkASSERT(info.fImmutableSampler); 289 } 290 291 fSamplerSwizzles.push_back(swizzle); 292 SkASSERT(fSamplerSwizzles.count() == fSamplers.count()); 293 return GrGLSLUniformHandler::SamplerHandle(fSamplers.count() - 1); 294 } 295 296 void GrVkUniformHandler::appendUniformDecls(GrShaderFlags visibility, SkString* out) const { 297 SkASSERT(kVertex_GrShaderFlag == visibility || 298 kGeometry_GrShaderFlag == visibility || 299 kFragment_GrShaderFlag == visibility); 300 301 for (int i = 0; i < fSamplers.count(); ++i) { 302 const UniformInfo& sampler = fSamplers[i]; 303 SkASSERT(sampler.fVariable.getType() == kTexture2DSampler_GrSLType); 304 if (visibility == sampler.fVisibility) { 305 sampler.fVariable.appendDecl(fProgramBuilder->shaderCaps(), out); 306 out->append(";\n"); 307 } 308 } 309 310 #ifdef SK_DEBUG 311 bool firstGeomOffsetCheck = false; 312 bool firstFragOffsetCheck = false; 313 for (int i = 0; i < fUniforms.count(); ++i) { 314 const UniformInfo& localUniform = fUniforms[i]; 315 if (kVertex_GrShaderFlag == localUniform.fVisibility || 316 kGeometry_GrShaderFlag == localUniform.fVisibility || 317 (kVertex_GrShaderFlag | kGeometry_GrShaderFlag) == localUniform.fVisibility) { 318 if (!firstGeomOffsetCheck) { 319 // Check to make sure we are starting our offset at 0 so the offset qualifier we 320 // set on each variable in the uniform block is valid. 321 SkASSERT(0 == localUniform.fUBOffset); 322 firstGeomOffsetCheck = true; 323 } 324 } else { 325 SkASSERT(kFragment_GrShaderFlag == localUniform.fVisibility); 326 if (!firstFragOffsetCheck) { 327 // Check to make sure we are starting our offset at 0 so the offset qualifier we 328 // set on each variable in the uniform block is valid. 329 SkASSERT(0 == localUniform.fUBOffset); 330 firstFragOffsetCheck = true; 331 } 332 } 333 } 334 #endif 335 336 SkString uniformsString; 337 for (int i = 0; i < fUniforms.count(); ++i) { 338 const UniformInfo& localUniform = fUniforms[i]; 339 if (visibility & localUniform.fVisibility) { 340 if (GrSLTypeIsFloatType(localUniform.fVariable.getType())) { 341 localUniform.fVariable.appendDecl(fProgramBuilder->shaderCaps(), &uniformsString); 342 uniformsString.append(";\n"); 343 } 344 } 345 } 346 347 if (!uniformsString.isEmpty()) { 348 uint32_t uniformBinding; 349 const char* stage; 350 if (kVertex_GrShaderFlag == visibility) { 351 uniformBinding = kGeometryBinding; 352 stage = "vertex"; 353 } else if (kGeometry_GrShaderFlag == visibility) { 354 uniformBinding = kGeometryBinding; 355 stage = "geometry"; 356 } else { 357 SkASSERT(kFragment_GrShaderFlag == visibility); 358 uniformBinding = kFragBinding; 359 stage = "fragment"; 360 } 361 out->appendf("layout (set=%d, binding=%d) uniform %sUniformBuffer\n{\n", 362 kUniformBufferDescSet, uniformBinding, stage); 363 out->appendf("%s\n};\n", uniformsString.c_str()); 364 } 365 } 366