1 // Copyright 2018 The SwiftShader Authors. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <spirv/unified1/spirv.hpp> 16 #include "SpirvShader.hpp" 17 #include "System/Math.hpp" 18 #include "Vulkan/VkDebug.hpp" 19 #include "Device/Config.hpp" 20 21 namespace sw 22 { 23 volatile int SpirvShader::serialCounter = 1; // Start at 1, 0 is invalid shader. 24 SpirvShader(InsnStore const & insns)25 SpirvShader::SpirvShader(InsnStore const &insns) 26 : insns{insns}, inputs{MAX_INTERFACE_COMPONENTS}, 27 outputs{MAX_INTERFACE_COMPONENTS}, 28 serialID{serialCounter++}, modes{} 29 { 30 // Simplifying assumptions (to be satisfied by earlier transformations) 31 // - There is exactly one entrypoint in the module, and it's the one we want 32 // - The only input/output OpVariables present are those used by the entrypoint 33 34 for (auto insn : *this) 35 { 36 switch (insn.opcode()) 37 { 38 case spv::OpExecutionMode: 39 ProcessExecutionMode(insn); 40 break; 41 42 case spv::OpDecorate: 43 { 44 auto targetId = insn.word(1); 45 decorations[targetId].Apply( 46 static_cast<spv::Decoration>(insn.word(2)), 47 insn.wordCount() > 3 ? insn.word(3) : 0); 48 break; 49 } 50 51 case spv::OpMemberDecorate: 52 { 53 auto targetId = insn.word(1); 54 auto memberIndex = insn.word(2); 55 auto &d = memberDecorations[targetId]; 56 if (memberIndex >= d.size()) 57 d.resize(memberIndex + 1); // on demand; exact size would require another pass... 58 d[memberIndex].Apply( 59 static_cast<spv::Decoration>(insn.word(3)), 60 insn.wordCount() > 4 ? insn.word(4) : 0); 61 break; 62 } 63 64 case spv::OpDecorationGroup: 65 // Nothing to do here. We don't need to record the definition of the group; we'll just have 66 // the bundle of decorations float around. If we were to ever walk the decorations directly, 67 // we might think about introducing this as a real Object. 68 break; 69 70 case spv::OpGroupDecorate: 71 { 72 auto const &srcDecorations = decorations[insn.word(1)]; 73 for (auto i = 2u; i < insn.wordCount(); i++) 74 { 75 // remaining operands are targets to apply the group to. 76 decorations[insn.word(i)].Apply(srcDecorations); 77 } 78 break; 79 } 80 81 case spv::OpGroupMemberDecorate: 82 { 83 auto const &srcDecorations = decorations[insn.word(1)]; 84 for (auto i = 2u; i < insn.wordCount(); i += 2) 85 { 86 // remaining operands are pairs of <id>, literal for members to apply to. 87 auto &d = memberDecorations[insn.word(i)]; 88 auto memberIndex = insn.word(i + 1); 89 if (memberIndex >= d.size()) 90 d.resize(memberIndex + 1); // on demand resize, see above... 91 d[memberIndex].Apply(srcDecorations); 92 } 93 break; 94 } 95 96 case spv::OpTypeVoid: 97 case spv::OpTypeBool: 98 case spv::OpTypeInt: 99 case spv::OpTypeFloat: 100 case spv::OpTypeVector: 101 case spv::OpTypeMatrix: 102 case spv::OpTypeImage: 103 case spv::OpTypeSampler: 104 case spv::OpTypeSampledImage: 105 case spv::OpTypeArray: 106 case spv::OpTypeRuntimeArray: 107 case spv::OpTypeStruct: 108 case spv::OpTypePointer: 109 case spv::OpTypeFunction: 110 { 111 auto resultId = insn.word(1); 112 auto &object = types[resultId]; 113 object.kind = Object::Kind::Type; 114 object.definition = insn; 115 object.sizeInComponents = ComputeTypeSize(insn); 116 117 // A structure is a builtin block if it has a builtin 118 // member. All members of such a structure are builtins. 119 if (insn.opcode() == spv::OpTypeStruct) 120 { 121 auto d = memberDecorations.find(resultId); 122 if (d != memberDecorations.end()) 123 { 124 for (auto &m : d->second) 125 { 126 if (m.HasBuiltIn) 127 { 128 object.isBuiltInBlock = true; 129 break; 130 } 131 } 132 } 133 } 134 else if (insn.opcode() == spv::OpTypePointer) 135 { 136 auto pointeeType = insn.word(3); 137 object.isBuiltInBlock = getType(pointeeType).isBuiltInBlock; 138 } 139 break; 140 } 141 142 case spv::OpVariable: 143 { 144 auto typeId = insn.word(1); 145 auto resultId = insn.word(2); 146 auto storageClass = static_cast<spv::StorageClass>(insn.word(3)); 147 if (insn.wordCount() > 4) 148 UNIMPLEMENTED("Variable initializers not yet supported"); 149 150 auto &object = defs[resultId]; 151 object.kind = Object::Kind::Variable; 152 object.definition = insn; 153 object.storageClass = storageClass; 154 155 auto &type = getType(typeId); 156 157 object.sizeInComponents = type.sizeInComponents; 158 object.isBuiltInBlock = type.isBuiltInBlock; 159 160 // Register builtins 161 162 if (storageClass == spv::StorageClassInput || storageClass == spv::StorageClassOutput) 163 { 164 ProcessInterfaceVariable(object); 165 } 166 break; 167 } 168 169 case spv::OpConstant: 170 case spv::OpConstantComposite: 171 case spv::OpConstantFalse: 172 case spv::OpConstantTrue: 173 case spv::OpConstantNull: 174 { 175 auto typeId = insn.word(1); 176 auto resultId = insn.word(2); 177 auto &object = defs[resultId]; 178 object.kind = Object::Kind::Constant; 179 object.definition = insn; 180 object.sizeInComponents = getType(typeId).sizeInComponents; 181 break; 182 } 183 184 case spv::OpCapability: 185 // Various capabilities will be declared, but none affect our code generation at this point. 186 case spv::OpMemoryModel: 187 // Memory model does not affect our code generation until we decide to do Vulkan Memory Model support. 188 case spv::OpEntryPoint: 189 // Due to preprocessing, the entrypoint provides no value. 190 break; 191 192 default: 193 break; // This is OK, these passes are intentionally partial 194 } 195 } 196 } 197 ProcessInterfaceVariable(Object & object)198 void SpirvShader::ProcessInterfaceVariable(Object &object) 199 { 200 assert(object.storageClass == spv::StorageClassInput || object.storageClass == spv::StorageClassOutput); 201 202 auto &builtinInterface = (object.storageClass == spv::StorageClassInput) ? inputBuiltins : outputBuiltins; 203 auto &userDefinedInterface = (object.storageClass == spv::StorageClassInput) ? inputs : outputs; 204 205 auto resultId = object.definition.word(2); 206 if (object.isBuiltInBlock) 207 { 208 // walk the builtin block, registering each of its members separately. 209 auto ptrType = getType(object.definition.word(1)).definition; 210 assert(ptrType.opcode() == spv::OpTypePointer); 211 auto pointeeType = ptrType.word(3); 212 auto m = memberDecorations.find(pointeeType); 213 assert(m != memberDecorations.end()); // otherwise we wouldn't have marked the type chain 214 auto &structType = getType(pointeeType).definition; 215 auto offset = 0u; 216 auto word = 2u; 217 for (auto &member : m->second) 218 { 219 auto &memberType = getType(structType.word(word)); 220 221 if (member.HasBuiltIn) 222 { 223 builtinInterface[member.BuiltIn] = {resultId, offset, memberType.sizeInComponents}; 224 } 225 226 offset += memberType.sizeInComponents; 227 ++word; 228 } 229 return; 230 } 231 232 auto d = decorations.find(resultId); 233 if (d != decorations.end() && d->second.HasBuiltIn) 234 { 235 builtinInterface[d->second.BuiltIn] = {resultId, 0, object.sizeInComponents}; 236 } 237 else 238 { 239 object.kind = Object::Kind::InterfaceVariable; 240 PopulateInterface(&userDefinedInterface, resultId); 241 } 242 } 243 ProcessExecutionMode(InsnIterator insn)244 void SpirvShader::ProcessExecutionMode(InsnIterator insn) 245 { 246 auto mode = static_cast<spv::ExecutionMode>(insn.word(2)); 247 switch (mode) 248 { 249 case spv::ExecutionModeEarlyFragmentTests: 250 modes.EarlyFragmentTests = true; 251 break; 252 case spv::ExecutionModeDepthReplacing: 253 modes.DepthReplacing = true; 254 break; 255 case spv::ExecutionModeDepthGreater: 256 modes.DepthGreater = true; 257 break; 258 case spv::ExecutionModeDepthLess: 259 modes.DepthLess = true; 260 break; 261 case spv::ExecutionModeDepthUnchanged: 262 modes.DepthUnchanged = true; 263 break; 264 case spv::ExecutionModeLocalSize: 265 modes.LocalSizeX = insn.word(3); 266 modes.LocalSizeZ = insn.word(5); 267 modes.LocalSizeY = insn.word(4); 268 break; 269 case spv::ExecutionModeOriginUpperLeft: 270 // This is always the case for a Vulkan shader. Do nothing. 271 break; 272 default: 273 UNIMPLEMENTED("No other execution modes are permitted"); 274 } 275 } 276 ComputeTypeSize(sw::SpirvShader::InsnIterator insn)277 uint32_t SpirvShader::ComputeTypeSize(sw::SpirvShader::InsnIterator insn) 278 { 279 // Types are always built from the bottom up (with the exception of forward ptrs, which 280 // don't appear in Vulkan shaders. Therefore, we can always assume our component parts have 281 // already been described (and so their sizes determined) 282 switch (insn.opcode()) 283 { 284 case spv::OpTypeVoid: 285 case spv::OpTypeSampler: 286 case spv::OpTypeImage: 287 case spv::OpTypeSampledImage: 288 case spv::OpTypeFunction: 289 case spv::OpTypeRuntimeArray: 290 // Objects that don't consume any space. 291 // Descriptor-backed objects currently only need exist at compile-time. 292 // Runtime arrays don't appear in places where their size would be interesting 293 return 0; 294 295 case spv::OpTypeBool: 296 case spv::OpTypeFloat: 297 case spv::OpTypeInt: 298 // All the fundamental types are 1 component. If we ever add support for 8/16/64-bit components, 299 // we might need to change this, but only 32 bit components are required for Vulkan 1.1. 300 return 1; 301 302 case spv::OpTypeVector: 303 case spv::OpTypeMatrix: 304 // Vectors and matrices both consume element count * element size. 305 return getType(insn.word(2)).sizeInComponents * insn.word(3); 306 307 case spv::OpTypeArray: 308 { 309 // Element count * element size. Array sizes come from constant ids. 310 auto arraySize = GetConstantInt(insn.word(3)); 311 return getType(insn.word(2)).sizeInComponents * arraySize; 312 } 313 314 case spv::OpTypeStruct: 315 { 316 uint32_t size = 0; 317 for (uint32_t i = 2u; i < insn.wordCount(); i++) 318 { 319 size += getType(insn.word(i)).sizeInComponents; 320 } 321 return size; 322 } 323 324 case spv::OpTypePointer: 325 // Pointer 'size' is just pointee size 326 // TODO: this isn't really correct. we should look through pointers as appropriate. 327 return getType(insn.word(3)).sizeInComponents; 328 329 default: 330 // Some other random insn. 331 UNIMPLEMENTED("Only types are supported"); 332 } 333 } 334 PopulateInterfaceSlot(std::vector<InterfaceComponent> * iface,Decorations const & d,AttribType type)335 void SpirvShader::PopulateInterfaceSlot(std::vector<InterfaceComponent> *iface, Decorations const &d, AttribType type) 336 { 337 // Populate a single scalar slot in the interface from a collection of decorations and the intended component type. 338 auto scalarSlot = (d.Location << 2) | d.Component; 339 340 auto &slot = (*iface)[scalarSlot]; 341 slot.Type = type; 342 slot.Flat = d.Flat; 343 slot.NoPerspective = d.NoPerspective; 344 slot.Centroid = d.Centroid; 345 } 346 PopulateInterfaceInner(std::vector<InterfaceComponent> * iface,uint32_t id,Decorations d)347 int SpirvShader::PopulateInterfaceInner(std::vector<InterfaceComponent> *iface, uint32_t id, Decorations d) 348 { 349 // Recursively walks variable definition and its type tree, taking into account 350 // any explicit Location or Component decorations encountered; where explicit 351 // Locations or Components are not specified, assigns them sequentially. 352 // Collected decorations are carried down toward the leaves and across 353 // siblings; Effect of decorations intentionally does not flow back up the tree. 354 // 355 // Returns the next available location. 356 357 // This covers the rules in Vulkan 1.1 spec, 14.1.4 Location Assignment. 358 359 auto const it = decorations.find(id); 360 if (it != decorations.end()) 361 { 362 d.Apply(it->second); 363 } 364 365 auto const &obj = getType(id); 366 switch (obj.definition.opcode()) 367 { 368 case spv::OpTypePointer: 369 return PopulateInterfaceInner(iface, obj.definition.word(3), d); 370 case spv::OpTypeMatrix: 371 for (auto i = 0u; i < obj.definition.word(3); i++, d.Location++) 372 { 373 // consumes same components of N consecutive locations 374 PopulateInterfaceInner(iface, obj.definition.word(2), d); 375 } 376 return d.Location; 377 case spv::OpTypeVector: 378 for (auto i = 0u; i < obj.definition.word(3); i++, d.Component++) 379 { 380 // consumes N consecutive components in the same location 381 PopulateInterfaceInner(iface, obj.definition.word(2), d); 382 } 383 return d.Location + 1; 384 case spv::OpTypeFloat: 385 PopulateInterfaceSlot(iface, d, ATTRIBTYPE_FLOAT); 386 return d.Location + 1; 387 case spv::OpTypeInt: 388 PopulateInterfaceSlot(iface, d, obj.definition.word(3) ? ATTRIBTYPE_INT : ATTRIBTYPE_UINT); 389 return d.Location + 1; 390 case spv::OpTypeBool: 391 PopulateInterfaceSlot(iface, d, ATTRIBTYPE_UINT); 392 return d.Location + 1; 393 case spv::OpTypeStruct: 394 { 395 auto const memberDecorationsIt = memberDecorations.find(id); 396 // iterate over members, which may themselves have Location/Component decorations 397 for (auto i = 0u; i < obj.definition.wordCount() - 2; i++) 398 { 399 // Apply any member decorations for this member to the carried state. 400 if (memberDecorationsIt != memberDecorations.end() && i < memberDecorationsIt->second.size()) 401 { 402 d.Apply(memberDecorationsIt->second[i]); 403 } 404 d.Location = PopulateInterfaceInner(iface, obj.definition.word(i + 2), d); 405 d.Component = 0; // Implicit locations always have component=0 406 } 407 return d.Location; 408 } 409 case spv::OpTypeArray: 410 { 411 auto arraySize = GetConstantInt(obj.definition.word(3)); 412 for (auto i = 0u; i < arraySize; i++) 413 { 414 d.Location = PopulateInterfaceInner(iface, obj.definition.word(2), d); 415 } 416 return d.Location; 417 } 418 default: 419 // Intentionally partial; most opcodes do not participate in type hierarchies 420 return 0; 421 } 422 } 423 PopulateInterface(std::vector<InterfaceComponent> * iface,uint32_t id)424 void SpirvShader::PopulateInterface(std::vector<InterfaceComponent> *iface, uint32_t id) 425 { 426 // Walk a variable definition and populate the interface from it. 427 Decorations d{}; 428 429 auto const it = decorations.find(id); 430 if (it != decorations.end()) 431 { 432 d.Apply(it->second); 433 } 434 435 auto def = getObject(id).definition; 436 assert(def.opcode() == spv::OpVariable); 437 PopulateInterfaceInner(iface, def.word(1), d); 438 } 439 Apply(spv::Decoration decoration,uint32_t arg)440 void SpirvShader::Decorations::Apply(spv::Decoration decoration, uint32_t arg) 441 { 442 switch (decoration) 443 { 444 case spv::DecorationLocation: 445 HasLocation = true; 446 Location = static_cast<int32_t>(arg); 447 break; 448 case spv::DecorationComponent: 449 HasComponent = true; 450 Component = arg; 451 break; 452 case spv::DecorationBuiltIn: 453 HasBuiltIn = true; 454 BuiltIn = static_cast<spv::BuiltIn>(arg); 455 break; 456 case spv::DecorationFlat: 457 Flat = true; 458 break; 459 case spv::DecorationNoPerspective: 460 NoPerspective = true; 461 break; 462 case spv::DecorationCentroid: 463 Centroid = true; 464 break; 465 case spv::DecorationBlock: 466 Block = true; 467 break; 468 case spv::DecorationBufferBlock: 469 BufferBlock = true; 470 break; 471 default: 472 // Intentionally partial, there are many decorations we just don't care about. 473 break; 474 } 475 } 476 Apply(const sw::SpirvShader::Decorations & src)477 void SpirvShader::Decorations::Apply(const sw::SpirvShader::Decorations &src) 478 { 479 // Apply a decoration group to this set of decorations 480 if (src.HasBuiltIn) 481 { 482 HasBuiltIn = true; 483 BuiltIn = src.BuiltIn; 484 } 485 486 if (src.HasLocation) 487 { 488 HasLocation = true; 489 Location = src.Location; 490 } 491 492 if (src.HasComponent) 493 { 494 HasComponent = true; 495 Component = src.Component; 496 } 497 498 Flat |= src.Flat; 499 NoPerspective |= src.NoPerspective; 500 Centroid |= src.Centroid; 501 Block |= src.Block; 502 BufferBlock |= src.BufferBlock; 503 } 504 GetConstantInt(uint32_t id)505 uint32_t SpirvShader::GetConstantInt(uint32_t id) 506 { 507 // Slightly hackish access to constants very early in translation. 508 // General consumption of constants by other instructions should 509 // probably be just lowered to Reactor. 510 511 // TODO: not encountered yet since we only use this for array sizes etc, 512 // but is possible to construct integer constant 0 via OpConstantNull. 513 auto insn = defs[id].definition; 514 assert(insn.opcode() == spv::OpConstant); 515 assert(getType(insn.word(1)).definition.opcode() == spv::OpTypeInt); 516 return insn.word(3); 517 } 518 } 519