1// 2//Copyright (C) 2014-2016 LunarG, Inc. 3//Copyright (C) 2015-2016 Google, Inc. 4// 5//All rights reserved. 6// 7//Redistribution and use in source and binary forms, with or without 8//modification, are permitted provided that the following conditions 9//are met: 10// 11// Redistributions of source code must retain the above copyright 12// notice, this list of conditions and the following disclaimer. 13// 14// Redistributions in binary form must reproduce the above 15// copyright notice, this list of conditions and the following 16// disclaimer in the documentation and/or other materials provided 17// with the distribution. 18// 19// Neither the name of 3Dlabs Inc. Ltd. nor the names of its 20// contributors may be used to endorse or promote products derived 21// from this software without specific prior written permission. 22// 23//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 33//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34//POSSIBILITY OF SUCH DAMAGE. 35 36// 37// Visit the nodes in the glslang intermediate tree representation to 38// translate them to SPIR-V. 39// 40 41#include "spirv.hpp" 42#include "GlslangToSpv.h" 43#include "SpvBuilder.h" 44namespace spv { 45 #include "GLSL.std.450.h" 46} 47 48// Glslang includes 49#include "../glslang/MachineIndependent/localintermediate.h" 50#include "../glslang/MachineIndependent/SymbolTable.h" 51#include "../glslang/Include/Common.h" 52#include "../glslang/Include/revision.h" 53 54#include <fstream> 55#include <iomanip> 56#include <list> 57#include <map> 58#include <stack> 59#include <string> 60#include <vector> 61 62namespace { 63 64// For low-order part of the generator's magic number. Bump up 65// when there is a change in the style (e.g., if SSA form changes, 66// or a different instruction sequence to do something gets used). 67const int GeneratorVersion = 1; 68 69namespace { 70class SpecConstantOpModeGuard { 71public: 72 SpecConstantOpModeGuard(spv::Builder* builder) 73 : builder_(builder) { 74 previous_flag_ = builder->isInSpecConstCodeGenMode(); 75 } 76 ~SpecConstantOpModeGuard() { 77 previous_flag_ ? builder_->setToSpecConstCodeGenMode() 78 : builder_->setToNormalCodeGenMode(); 79 } 80 void turnOnSpecConstantOpMode() { 81 builder_->setToSpecConstCodeGenMode(); 82 } 83 84private: 85 spv::Builder* builder_; 86 bool previous_flag_; 87}; 88} 89 90// 91// The main holder of information for translating glslang to SPIR-V. 92// 93// Derives from the AST walking base class. 94// 95class TGlslangToSpvTraverser : public glslang::TIntermTraverser { 96public: 97 TGlslangToSpvTraverser(const glslang::TIntermediate*, spv::SpvBuildLogger* logger); 98 virtual ~TGlslangToSpvTraverser(); 99 100 bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate*); 101 bool visitBinary(glslang::TVisit, glslang::TIntermBinary*); 102 void visitConstantUnion(glslang::TIntermConstantUnion*); 103 bool visitSelection(glslang::TVisit, glslang::TIntermSelection*); 104 bool visitSwitch(glslang::TVisit, glslang::TIntermSwitch*); 105 void visitSymbol(glslang::TIntermSymbol* symbol); 106 bool visitUnary(glslang::TVisit, glslang::TIntermUnary*); 107 bool visitLoop(glslang::TVisit, glslang::TIntermLoop*); 108 bool visitBranch(glslang::TVisit visit, glslang::TIntermBranch*); 109 110 void dumpSpv(std::vector<unsigned int>& out); 111 112protected: 113 spv::Decoration TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier); 114 spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable, bool memberDeclaration); 115 spv::ImageFormat TranslateImageFormat(const glslang::TType& type); 116 spv::Id createSpvVariable(const glslang::TIntermSymbol*); 117 spv::Id getSampledType(const glslang::TSampler&); 118 spv::Id convertGlslangToSpvType(const glslang::TType& type); 119 spv::Id convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking, const glslang::TQualifier&); 120 spv::Id convertGlslangStructToSpvType(const glslang::TType&, const glslang::TTypeList* glslangStruct, 121 glslang::TLayoutPacking, const glslang::TQualifier&); 122 void decorateStructType(const glslang::TType&, const glslang::TTypeList* glslangStruct, glslang::TLayoutPacking, 123 const glslang::TQualifier&, spv::Id); 124 spv::Id makeArraySizeId(const glslang::TArraySizes&, int dim); 125 spv::Id accessChainLoad(const glslang::TType& type); 126 void accessChainStore(const glslang::TType& type, spv::Id rvalue); 127 glslang::TLayoutPacking getExplicitLayout(const glslang::TType& type) const; 128 int getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking, glslang::TLayoutMatrix); 129 int getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking, glslang::TLayoutMatrix); 130 void updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset, int& nextOffset, glslang::TLayoutPacking, glslang::TLayoutMatrix); 131 void declareUseOfStructMember(const glslang::TTypeList& members, int glslangMember); 132 133 bool isShaderEntrypoint(const glslang::TIntermAggregate* node); 134 void makeFunctions(const glslang::TIntermSequence&); 135 void makeGlobalInitializers(const glslang::TIntermSequence&); 136 void visitFunctions(const glslang::TIntermSequence&); 137 void handleFunctionEntry(const glslang::TIntermAggregate* node); 138 void translateArguments(const glslang::TIntermAggregate& node, std::vector<spv::Id>& arguments); 139 void translateArguments(glslang::TIntermUnary& node, std::vector<spv::Id>& arguments); 140 spv::Id createImageTextureFunctionCall(glslang::TIntermOperator* node); 141 spv::Id handleUserFunctionCall(const glslang::TIntermAggregate*); 142 143 spv::Id createBinaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id left, spv::Id right, glslang::TBasicType typeProxy, bool reduceComparison = true); 144 spv::Id createBinaryMatrixOperation(spv::Op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id left, spv::Id right); 145 spv::Id createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id operand,glslang::TBasicType typeProxy); 146 spv::Id createUnaryMatrixOperation(spv::Op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id operand,glslang::TBasicType typeProxy); 147 spv::Id createConversion(glslang::TOperator op, spv::Decoration precision, spv::Decoration noContraction, spv::Id destTypeId, spv::Id operand, glslang::TBasicType typeProxy); 148 spv::Id makeSmearedConstant(spv::Id constant, int vectorSize); 149 spv::Id createAtomicOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy); 150 spv::Id createInvocationsOperation(glslang::TOperator, spv::Id typeId, spv::Id operand); 151 spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy); 152 spv::Id createNoArgOperation(glslang::TOperator op); 153 spv::Id getSymbolId(const glslang::TIntermSymbol* node); 154 void addDecoration(spv::Id id, spv::Decoration dec); 155 void addDecoration(spv::Id id, spv::Decoration dec, unsigned value); 156 void addMemberDecoration(spv::Id id, int member, spv::Decoration dec); 157 void addMemberDecoration(spv::Id id, int member, spv::Decoration dec, unsigned value); 158 spv::Id createSpvConstant(const glslang::TIntermTyped&); 159 spv::Id createSpvConstantFromConstUnionArray(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst, bool specConstant); 160 bool isTrivialLeaf(const glslang::TIntermTyped* node); 161 bool isTrivial(const glslang::TIntermTyped* node); 162 spv::Id createShortCircuit(glslang::TOperator, glslang::TIntermTyped& left, glslang::TIntermTyped& right); 163 164 spv::Function* shaderEntry; 165 spv::Instruction* entryPoint; 166 int sequenceDepth; 167 168 spv::SpvBuildLogger* logger; 169 170 // There is a 1:1 mapping between a spv builder and a module; this is thread safe 171 spv::Builder builder; 172 bool inMain; 173 bool mainTerminated; 174 bool linkageOnly; // true when visiting the set of objects in the AST present only for establishing interface, whether or not they were statically used 175 std::set<spv::Id> iOSet; // all input/output variables from either static use or declaration of interface 176 const glslang::TIntermediate* glslangIntermediate; 177 spv::Id stdBuiltins; 178 179 std::unordered_map<int, spv::Id> symbolValues; 180 std::unordered_set<int> constReadOnlyParameters; // set of formal function parameters that have glslang qualifier constReadOnly, so we know they are not local function "const" that are write-once 181 std::unordered_map<std::string, spv::Function*> functionMap; 182 std::unordered_map<const glslang::TTypeList*, spv::Id> structMap[glslang::ElpCount][glslang::ElmCount]; 183 std::unordered_map<const glslang::TTypeList*, std::vector<int> > memberRemapper; // for mapping glslang block indices to spv indices (e.g., due to hidden members) 184 std::stack<bool> breakForLoop; // false means break for switch 185}; 186 187// 188// Helper functions for translating glslang representations to SPIR-V enumerants. 189// 190 191// Translate glslang profile to SPIR-V source language. 192spv::SourceLanguage TranslateSourceLanguage(glslang::EShSource source, EProfile profile) 193{ 194 switch (source) { 195 case glslang::EShSourceGlsl: 196 switch (profile) { 197 case ENoProfile: 198 case ECoreProfile: 199 case ECompatibilityProfile: 200 return spv::SourceLanguageGLSL; 201 case EEsProfile: 202 return spv::SourceLanguageESSL; 203 default: 204 return spv::SourceLanguageUnknown; 205 } 206 case glslang::EShSourceHlsl: 207 return spv::SourceLanguageHLSL; 208 default: 209 return spv::SourceLanguageUnknown; 210 } 211} 212 213// Translate glslang language (stage) to SPIR-V execution model. 214spv::ExecutionModel TranslateExecutionModel(EShLanguage stage) 215{ 216 switch (stage) { 217 case EShLangVertex: return spv::ExecutionModelVertex; 218 case EShLangTessControl: return spv::ExecutionModelTessellationControl; 219 case EShLangTessEvaluation: return spv::ExecutionModelTessellationEvaluation; 220 case EShLangGeometry: return spv::ExecutionModelGeometry; 221 case EShLangFragment: return spv::ExecutionModelFragment; 222 case EShLangCompute: return spv::ExecutionModelGLCompute; 223 default: 224 assert(0); 225 return spv::ExecutionModelFragment; 226 } 227} 228 229// Translate glslang type to SPIR-V storage class. 230spv::StorageClass TranslateStorageClass(const glslang::TType& type) 231{ 232 if (type.getQualifier().isPipeInput()) 233 return spv::StorageClassInput; 234 else if (type.getQualifier().isPipeOutput()) 235 return spv::StorageClassOutput; 236 else if (type.getBasicType() == glslang::EbtSampler) 237 return spv::StorageClassUniformConstant; 238 else if (type.getBasicType() == glslang::EbtAtomicUint) 239 return spv::StorageClassAtomicCounter; 240 else if (type.getQualifier().isUniformOrBuffer()) { 241 if (type.getQualifier().layoutPushConstant) 242 return spv::StorageClassPushConstant; 243 if (type.getBasicType() == glslang::EbtBlock) 244 return spv::StorageClassUniform; 245 else 246 return spv::StorageClassUniformConstant; 247 // TODO: how are we distinguishing between default and non-default non-writable uniforms? Do default uniforms even exist? 248 } else { 249 switch (type.getQualifier().storage) { 250 case glslang::EvqShared: return spv::StorageClassWorkgroup; break; 251 case glslang::EvqGlobal: return spv::StorageClassPrivate; 252 case glslang::EvqConstReadOnly: return spv::StorageClassFunction; 253 case glslang::EvqTemporary: return spv::StorageClassFunction; 254 default: 255 assert(0); 256 return spv::StorageClassFunction; 257 } 258 } 259} 260 261// Translate glslang sampler type to SPIR-V dimensionality. 262spv::Dim TranslateDimensionality(const glslang::TSampler& sampler) 263{ 264 switch (sampler.dim) { 265 case glslang::Esd1D: return spv::Dim1D; 266 case glslang::Esd2D: return spv::Dim2D; 267 case glslang::Esd3D: return spv::Dim3D; 268 case glslang::EsdCube: return spv::DimCube; 269 case glslang::EsdRect: return spv::DimRect; 270 case glslang::EsdBuffer: return spv::DimBuffer; 271 case glslang::EsdSubpass: return spv::DimSubpassData; 272 default: 273 assert(0); 274 return spv::Dim2D; 275 } 276} 277 278// Translate glslang type to SPIR-V precision decorations. 279spv::Decoration TranslatePrecisionDecoration(const glslang::TType& type) 280{ 281 switch (type.getQualifier().precision) { 282 case glslang::EpqLow: return spv::DecorationRelaxedPrecision; 283 case glslang::EpqMedium: return spv::DecorationRelaxedPrecision; 284 default: 285 return spv::NoPrecision; 286 } 287} 288 289// Translate glslang type to SPIR-V block decorations. 290spv::Decoration TranslateBlockDecoration(const glslang::TType& type) 291{ 292 if (type.getBasicType() == glslang::EbtBlock) { 293 switch (type.getQualifier().storage) { 294 case glslang::EvqUniform: return spv::DecorationBlock; 295 case glslang::EvqBuffer: return spv::DecorationBufferBlock; 296 case glslang::EvqVaryingIn: return spv::DecorationBlock; 297 case glslang::EvqVaryingOut: return spv::DecorationBlock; 298 default: 299 assert(0); 300 break; 301 } 302 } 303 304 return spv::DecorationMax; 305} 306 307// Translate glslang type to SPIR-V memory decorations. 308void TranslateMemoryDecoration(const glslang::TQualifier& qualifier, std::vector<spv::Decoration>& memory) 309{ 310 if (qualifier.coherent) 311 memory.push_back(spv::DecorationCoherent); 312 if (qualifier.volatil) 313 memory.push_back(spv::DecorationVolatile); 314 if (qualifier.restrict) 315 memory.push_back(spv::DecorationRestrict); 316 if (qualifier.readonly) 317 memory.push_back(spv::DecorationNonWritable); 318 if (qualifier.writeonly) 319 memory.push_back(spv::DecorationNonReadable); 320} 321 322// Translate glslang type to SPIR-V layout decorations. 323spv::Decoration TranslateLayoutDecoration(const glslang::TType& type, glslang::TLayoutMatrix matrixLayout) 324{ 325 if (type.isMatrix()) { 326 switch (matrixLayout) { 327 case glslang::ElmRowMajor: 328 return spv::DecorationRowMajor; 329 case glslang::ElmColumnMajor: 330 return spv::DecorationColMajor; 331 default: 332 // opaque layouts don't need a majorness 333 return spv::DecorationMax; 334 } 335 } else { 336 switch (type.getBasicType()) { 337 default: 338 return spv::DecorationMax; 339 break; 340 case glslang::EbtBlock: 341 switch (type.getQualifier().storage) { 342 case glslang::EvqUniform: 343 case glslang::EvqBuffer: 344 switch (type.getQualifier().layoutPacking) { 345 case glslang::ElpShared: return spv::DecorationGLSLShared; 346 case glslang::ElpPacked: return spv::DecorationGLSLPacked; 347 default: 348 return spv::DecorationMax; 349 } 350 case glslang::EvqVaryingIn: 351 case glslang::EvqVaryingOut: 352 assert(type.getQualifier().layoutPacking == glslang::ElpNone); 353 return spv::DecorationMax; 354 default: 355 assert(0); 356 return spv::DecorationMax; 357 } 358 } 359 } 360} 361 362// Translate glslang type to SPIR-V interpolation decorations. 363// Returns spv::DecorationMax when no decoration 364// should be applied. 365spv::Decoration TranslateInterpolationDecoration(const glslang::TQualifier& qualifier) 366{ 367 if (qualifier.smooth) 368 // Smooth decoration doesn't exist in SPIR-V 1.0 369 return spv::DecorationMax; 370 else if (qualifier.nopersp) 371 return spv::DecorationNoPerspective; 372 else if (qualifier.flat) 373 return spv::DecorationFlat; 374 else 375 return spv::DecorationMax; 376} 377 378// Translate glslang type to SPIR-V auxiliary storage decorations. 379// Returns spv::DecorationMax when no decoration 380// should be applied. 381spv::Decoration TGlslangToSpvTraverser::TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier) 382{ 383 if (qualifier.patch) 384 return spv::DecorationPatch; 385 else if (qualifier.centroid) 386 return spv::DecorationCentroid; 387 else if (qualifier.sample) { 388 builder.addCapability(spv::CapabilitySampleRateShading); 389 return spv::DecorationSample; 390 } else 391 return spv::DecorationMax; 392} 393 394// If glslang type is invariant, return SPIR-V invariant decoration. 395spv::Decoration TranslateInvariantDecoration(const glslang::TQualifier& qualifier) 396{ 397 if (qualifier.invariant) 398 return spv::DecorationInvariant; 399 else 400 return spv::DecorationMax; 401} 402 403// If glslang type is noContraction, return SPIR-V NoContraction decoration. 404spv::Decoration TranslateNoContractionDecoration(const glslang::TQualifier& qualifier) 405{ 406 if (qualifier.noContraction) 407 return spv::DecorationNoContraction; 408 else 409 return spv::DecorationMax; 410} 411 412// Translate a glslang built-in variable to a SPIR-V built in decoration. Also generate 413// associated capabilities when required. For some built-in variables, a capability 414// is generated only when using the variable in an executable instruction, but not when 415// just declaring a struct member variable with it. This is true for PointSize, 416// ClipDistance, and CullDistance. 417spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn, bool memberDeclaration) 418{ 419 switch (builtIn) { 420 case glslang::EbvPointSize: 421 // Defer adding the capability until the built-in is actually used. 422 if (! memberDeclaration) { 423 switch (glslangIntermediate->getStage()) { 424 case EShLangGeometry: 425 builder.addCapability(spv::CapabilityGeometryPointSize); 426 break; 427 case EShLangTessControl: 428 case EShLangTessEvaluation: 429 builder.addCapability(spv::CapabilityTessellationPointSize); 430 break; 431 default: 432 break; 433 } 434 } 435 return spv::BuiltInPointSize; 436 437 // These *Distance capabilities logically belong here, but if the member is declared and 438 // then never used, consumers of SPIR-V prefer the capability not be declared. 439 // They are now generated when used, rather than here when declared. 440 // Potentially, the specification should be more clear what the minimum 441 // use needed is to trigger the capability. 442 // 443 case glslang::EbvClipDistance: 444 if (!memberDeclaration) 445 builder.addCapability(spv::CapabilityClipDistance); 446 return spv::BuiltInClipDistance; 447 448 case glslang::EbvCullDistance: 449 if (!memberDeclaration) 450 builder.addCapability(spv::CapabilityCullDistance); 451 return spv::BuiltInCullDistance; 452 453 case glslang::EbvViewportIndex: 454 builder.addCapability(spv::CapabilityMultiViewport); 455 return spv::BuiltInViewportIndex; 456 457 case glslang::EbvSampleId: 458 builder.addCapability(spv::CapabilitySampleRateShading); 459 return spv::BuiltInSampleId; 460 461 case glslang::EbvSamplePosition: 462 builder.addCapability(spv::CapabilitySampleRateShading); 463 return spv::BuiltInSamplePosition; 464 465 case glslang::EbvSampleMask: 466 builder.addCapability(spv::CapabilitySampleRateShading); 467 return spv::BuiltInSampleMask; 468 469 case glslang::EbvLayer: 470 builder.addCapability(spv::CapabilityGeometry); 471 return spv::BuiltInLayer; 472 473 case glslang::EbvPosition: return spv::BuiltInPosition; 474 case glslang::EbvVertexId: return spv::BuiltInVertexId; 475 case glslang::EbvInstanceId: return spv::BuiltInInstanceId; 476 case glslang::EbvVertexIndex: return spv::BuiltInVertexIndex; 477 case glslang::EbvInstanceIndex: return spv::BuiltInInstanceIndex; 478 case glslang::EbvBaseVertex: 479 case glslang::EbvBaseInstance: 480 case glslang::EbvDrawId: 481 // TODO: Add SPIR-V builtin ID. 482 logger->missingFunctionality("shader draw parameters"); 483 return spv::BuiltInMax; 484 case glslang::EbvPrimitiveId: return spv::BuiltInPrimitiveId; 485 case glslang::EbvInvocationId: return spv::BuiltInInvocationId; 486 case glslang::EbvTessLevelInner: return spv::BuiltInTessLevelInner; 487 case glslang::EbvTessLevelOuter: return spv::BuiltInTessLevelOuter; 488 case glslang::EbvTessCoord: return spv::BuiltInTessCoord; 489 case glslang::EbvPatchVertices: return spv::BuiltInPatchVertices; 490 case glslang::EbvFragCoord: return spv::BuiltInFragCoord; 491 case glslang::EbvPointCoord: return spv::BuiltInPointCoord; 492 case glslang::EbvFace: return spv::BuiltInFrontFacing; 493 case glslang::EbvFragDepth: return spv::BuiltInFragDepth; 494 case glslang::EbvHelperInvocation: return spv::BuiltInHelperInvocation; 495 case glslang::EbvNumWorkGroups: return spv::BuiltInNumWorkgroups; 496 case glslang::EbvWorkGroupSize: return spv::BuiltInWorkgroupSize; 497 case glslang::EbvWorkGroupId: return spv::BuiltInWorkgroupId; 498 case glslang::EbvLocalInvocationId: return spv::BuiltInLocalInvocationId; 499 case glslang::EbvLocalInvocationIndex: return spv::BuiltInLocalInvocationIndex; 500 case glslang::EbvGlobalInvocationId: return spv::BuiltInGlobalInvocationId; 501 case glslang::EbvSubGroupSize: 502 case glslang::EbvSubGroupInvocation: 503 case glslang::EbvSubGroupEqMask: 504 case glslang::EbvSubGroupGeMask: 505 case glslang::EbvSubGroupGtMask: 506 case glslang::EbvSubGroupLeMask: 507 case glslang::EbvSubGroupLtMask: 508 // TODO: Add SPIR-V builtin ID. 509 logger->missingFunctionality("shader ballot"); 510 return spv::BuiltInMax; 511 default: return spv::BuiltInMax; 512 } 513} 514 515// Translate glslang image layout format to SPIR-V image format. 516spv::ImageFormat TGlslangToSpvTraverser::TranslateImageFormat(const glslang::TType& type) 517{ 518 assert(type.getBasicType() == glslang::EbtSampler); 519 520 // Check for capabilities 521 switch (type.getQualifier().layoutFormat) { 522 case glslang::ElfRg32f: 523 case glslang::ElfRg16f: 524 case glslang::ElfR11fG11fB10f: 525 case glslang::ElfR16f: 526 case glslang::ElfRgba16: 527 case glslang::ElfRgb10A2: 528 case glslang::ElfRg16: 529 case glslang::ElfRg8: 530 case glslang::ElfR16: 531 case glslang::ElfR8: 532 case glslang::ElfRgba16Snorm: 533 case glslang::ElfRg16Snorm: 534 case glslang::ElfRg8Snorm: 535 case glslang::ElfR16Snorm: 536 case glslang::ElfR8Snorm: 537 538 case glslang::ElfRg32i: 539 case glslang::ElfRg16i: 540 case glslang::ElfRg8i: 541 case glslang::ElfR16i: 542 case glslang::ElfR8i: 543 544 case glslang::ElfRgb10a2ui: 545 case glslang::ElfRg32ui: 546 case glslang::ElfRg16ui: 547 case glslang::ElfRg8ui: 548 case glslang::ElfR16ui: 549 case glslang::ElfR8ui: 550 builder.addCapability(spv::CapabilityStorageImageExtendedFormats); 551 break; 552 553 default: 554 break; 555 } 556 557 // do the translation 558 switch (type.getQualifier().layoutFormat) { 559 case glslang::ElfNone: return spv::ImageFormatUnknown; 560 case glslang::ElfRgba32f: return spv::ImageFormatRgba32f; 561 case glslang::ElfRgba16f: return spv::ImageFormatRgba16f; 562 case glslang::ElfR32f: return spv::ImageFormatR32f; 563 case glslang::ElfRgba8: return spv::ImageFormatRgba8; 564 case glslang::ElfRgba8Snorm: return spv::ImageFormatRgba8Snorm; 565 case glslang::ElfRg32f: return spv::ImageFormatRg32f; 566 case glslang::ElfRg16f: return spv::ImageFormatRg16f; 567 case glslang::ElfR11fG11fB10f: return spv::ImageFormatR11fG11fB10f; 568 case glslang::ElfR16f: return spv::ImageFormatR16f; 569 case glslang::ElfRgba16: return spv::ImageFormatRgba16; 570 case glslang::ElfRgb10A2: return spv::ImageFormatRgb10A2; 571 case glslang::ElfRg16: return spv::ImageFormatRg16; 572 case glslang::ElfRg8: return spv::ImageFormatRg8; 573 case glslang::ElfR16: return spv::ImageFormatR16; 574 case glslang::ElfR8: return spv::ImageFormatR8; 575 case glslang::ElfRgba16Snorm: return spv::ImageFormatRgba16Snorm; 576 case glslang::ElfRg16Snorm: return spv::ImageFormatRg16Snorm; 577 case glslang::ElfRg8Snorm: return spv::ImageFormatRg8Snorm; 578 case glslang::ElfR16Snorm: return spv::ImageFormatR16Snorm; 579 case glslang::ElfR8Snorm: return spv::ImageFormatR8Snorm; 580 case glslang::ElfRgba32i: return spv::ImageFormatRgba32i; 581 case glslang::ElfRgba16i: return spv::ImageFormatRgba16i; 582 case glslang::ElfRgba8i: return spv::ImageFormatRgba8i; 583 case glslang::ElfR32i: return spv::ImageFormatR32i; 584 case glslang::ElfRg32i: return spv::ImageFormatRg32i; 585 case glslang::ElfRg16i: return spv::ImageFormatRg16i; 586 case glslang::ElfRg8i: return spv::ImageFormatRg8i; 587 case glslang::ElfR16i: return spv::ImageFormatR16i; 588 case glslang::ElfR8i: return spv::ImageFormatR8i; 589 case glslang::ElfRgba32ui: return spv::ImageFormatRgba32ui; 590 case glslang::ElfRgba16ui: return spv::ImageFormatRgba16ui; 591 case glslang::ElfRgba8ui: return spv::ImageFormatRgba8ui; 592 case glslang::ElfR32ui: return spv::ImageFormatR32ui; 593 case glslang::ElfRg32ui: return spv::ImageFormatRg32ui; 594 case glslang::ElfRg16ui: return spv::ImageFormatRg16ui; 595 case glslang::ElfRgb10a2ui: return spv::ImageFormatRgb10a2ui; 596 case glslang::ElfRg8ui: return spv::ImageFormatRg8ui; 597 case glslang::ElfR16ui: return spv::ImageFormatR16ui; 598 case glslang::ElfR8ui: return spv::ImageFormatR8ui; 599 default: return spv::ImageFormatMax; 600 } 601} 602 603// Return whether or not the given type is something that should be tied to a 604// descriptor set. 605bool IsDescriptorResource(const glslang::TType& type) 606{ 607 // uniform and buffer blocks are included, unless it is a push_constant 608 if (type.getBasicType() == glslang::EbtBlock) 609 return type.getQualifier().isUniformOrBuffer() && ! type.getQualifier().layoutPushConstant; 610 611 // non block... 612 // basically samplerXXX/subpass/sampler/texture are all included 613 // if they are the global-scope-class, not the function parameter 614 // (or local, if they ever exist) class. 615 if (type.getBasicType() == glslang::EbtSampler) 616 return type.getQualifier().isUniformOrBuffer(); 617 618 // None of the above. 619 return false; 620} 621 622void InheritQualifiers(glslang::TQualifier& child, const glslang::TQualifier& parent) 623{ 624 if (child.layoutMatrix == glslang::ElmNone) 625 child.layoutMatrix = parent.layoutMatrix; 626 627 if (parent.invariant) 628 child.invariant = true; 629 if (parent.nopersp) 630 child.nopersp = true; 631 if (parent.flat) 632 child.flat = true; 633 if (parent.centroid) 634 child.centroid = true; 635 if (parent.patch) 636 child.patch = true; 637 if (parent.sample) 638 child.sample = true; 639 if (parent.coherent) 640 child.coherent = true; 641 if (parent.volatil) 642 child.volatil = true; 643 if (parent.restrict) 644 child.restrict = true; 645 if (parent.readonly) 646 child.readonly = true; 647 if (parent.writeonly) 648 child.writeonly = true; 649} 650 651bool HasNonLayoutQualifiers(const glslang::TQualifier& qualifier) 652{ 653 // This should list qualifiers that simultaneous satisfy: 654 // - struct members can inherit from a struct declaration 655 // - affect decorations on the struct members (note smooth does not, and expecting something like volatile to effect the whole object) 656 // - are not part of the offset/st430/etc or row/column-major layout 657 return qualifier.invariant || qualifier.hasLocation(); 658} 659 660// 661// Implement the TGlslangToSpvTraverser class. 662// 663 664TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* glslangIntermediate, spv::SpvBuildLogger* buildLogger) 665 : TIntermTraverser(true, false, true), shaderEntry(0), sequenceDepth(0), logger(buildLogger), 666 builder((glslang::GetKhronosToolId() << 16) | GeneratorVersion, logger), 667 inMain(false), mainTerminated(false), linkageOnly(false), 668 glslangIntermediate(glslangIntermediate) 669{ 670 spv::ExecutionModel executionModel = TranslateExecutionModel(glslangIntermediate->getStage()); 671 672 builder.clearAccessChain(); 673 builder.setSource(TranslateSourceLanguage(glslangIntermediate->getSource(), glslangIntermediate->getProfile()), glslangIntermediate->getVersion()); 674 stdBuiltins = builder.import("GLSL.std.450"); 675 builder.setMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450); 676 shaderEntry = builder.makeEntrypoint(glslangIntermediate->getEntryPoint().c_str()); 677 entryPoint = builder.addEntryPoint(executionModel, shaderEntry, glslangIntermediate->getEntryPoint().c_str()); 678 679 // Add the source extensions 680 const auto& sourceExtensions = glslangIntermediate->getRequestedExtensions(); 681 for (auto it = sourceExtensions.begin(); it != sourceExtensions.end(); ++it) 682 builder.addSourceExtension(it->c_str()); 683 684 // Add the top-level modes for this shader. 685 686 if (glslangIntermediate->getXfbMode()) { 687 builder.addCapability(spv::CapabilityTransformFeedback); 688 builder.addExecutionMode(shaderEntry, spv::ExecutionModeXfb); 689 } 690 691 unsigned int mode; 692 switch (glslangIntermediate->getStage()) { 693 case EShLangVertex: 694 builder.addCapability(spv::CapabilityShader); 695 break; 696 697 case EShLangTessControl: 698 builder.addCapability(spv::CapabilityTessellation); 699 builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices()); 700 break; 701 702 case EShLangTessEvaluation: 703 builder.addCapability(spv::CapabilityTessellation); 704 switch (glslangIntermediate->getInputPrimitive()) { 705 case glslang::ElgTriangles: mode = spv::ExecutionModeTriangles; break; 706 case glslang::ElgQuads: mode = spv::ExecutionModeQuads; break; 707 case glslang::ElgIsolines: mode = spv::ExecutionModeIsolines; break; 708 default: mode = spv::ExecutionModeMax; break; 709 } 710 if (mode != spv::ExecutionModeMax) 711 builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode); 712 713 switch (glslangIntermediate->getVertexSpacing()) { 714 case glslang::EvsEqual: mode = spv::ExecutionModeSpacingEqual; break; 715 case glslang::EvsFractionalEven: mode = spv::ExecutionModeSpacingFractionalEven; break; 716 case glslang::EvsFractionalOdd: mode = spv::ExecutionModeSpacingFractionalOdd; break; 717 default: mode = spv::ExecutionModeMax; break; 718 } 719 if (mode != spv::ExecutionModeMax) 720 builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode); 721 722 switch (glslangIntermediate->getVertexOrder()) { 723 case glslang::EvoCw: mode = spv::ExecutionModeVertexOrderCw; break; 724 case glslang::EvoCcw: mode = spv::ExecutionModeVertexOrderCcw; break; 725 default: mode = spv::ExecutionModeMax; break; 726 } 727 if (mode != spv::ExecutionModeMax) 728 builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode); 729 730 if (glslangIntermediate->getPointMode()) 731 builder.addExecutionMode(shaderEntry, spv::ExecutionModePointMode); 732 break; 733 734 case EShLangGeometry: 735 builder.addCapability(spv::CapabilityGeometry); 736 switch (glslangIntermediate->getInputPrimitive()) { 737 case glslang::ElgPoints: mode = spv::ExecutionModeInputPoints; break; 738 case glslang::ElgLines: mode = spv::ExecutionModeInputLines; break; 739 case glslang::ElgLinesAdjacency: mode = spv::ExecutionModeInputLinesAdjacency; break; 740 case glslang::ElgTriangles: mode = spv::ExecutionModeTriangles; break; 741 case glslang::ElgTrianglesAdjacency: mode = spv::ExecutionModeInputTrianglesAdjacency; break; 742 default: mode = spv::ExecutionModeMax; break; 743 } 744 if (mode != spv::ExecutionModeMax) 745 builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode); 746 747 builder.addExecutionMode(shaderEntry, spv::ExecutionModeInvocations, glslangIntermediate->getInvocations()); 748 749 switch (glslangIntermediate->getOutputPrimitive()) { 750 case glslang::ElgPoints: mode = spv::ExecutionModeOutputPoints; break; 751 case glslang::ElgLineStrip: mode = spv::ExecutionModeOutputLineStrip; break; 752 case glslang::ElgTriangleStrip: mode = spv::ExecutionModeOutputTriangleStrip; break; 753 default: mode = spv::ExecutionModeMax; break; 754 } 755 if (mode != spv::ExecutionModeMax) 756 builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode); 757 builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices()); 758 break; 759 760 case EShLangFragment: 761 builder.addCapability(spv::CapabilityShader); 762 if (glslangIntermediate->getPixelCenterInteger()) 763 builder.addExecutionMode(shaderEntry, spv::ExecutionModePixelCenterInteger); 764 765 if (glslangIntermediate->getOriginUpperLeft()) 766 builder.addExecutionMode(shaderEntry, spv::ExecutionModeOriginUpperLeft); 767 else 768 builder.addExecutionMode(shaderEntry, spv::ExecutionModeOriginLowerLeft); 769 770 if (glslangIntermediate->getEarlyFragmentTests()) 771 builder.addExecutionMode(shaderEntry, spv::ExecutionModeEarlyFragmentTests); 772 773 switch(glslangIntermediate->getDepth()) { 774 case glslang::EldGreater: mode = spv::ExecutionModeDepthGreater; break; 775 case glslang::EldLess: mode = spv::ExecutionModeDepthLess; break; 776 default: mode = spv::ExecutionModeMax; break; 777 } 778 if (mode != spv::ExecutionModeMax) 779 builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode); 780 781 if (glslangIntermediate->getDepth() != glslang::EldUnchanged && glslangIntermediate->isDepthReplacing()) 782 builder.addExecutionMode(shaderEntry, spv::ExecutionModeDepthReplacing); 783 break; 784 785 case EShLangCompute: 786 builder.addCapability(spv::CapabilityShader); 787 builder.addExecutionMode(shaderEntry, spv::ExecutionModeLocalSize, glslangIntermediate->getLocalSize(0), 788 glslangIntermediate->getLocalSize(1), 789 glslangIntermediate->getLocalSize(2)); 790 break; 791 792 default: 793 break; 794 } 795 796} 797 798// Finish everything and dump 799void TGlslangToSpvTraverser::dumpSpv(std::vector<unsigned int>& out) 800{ 801 // finish off the entry-point SPV instruction by adding the Input/Output <id> 802 for (auto it = iOSet.cbegin(); it != iOSet.cend(); ++it) 803 entryPoint->addIdOperand(*it); 804 805 builder.eliminateDeadDecorations(); 806 builder.dump(out); 807} 808 809TGlslangToSpvTraverser::~TGlslangToSpvTraverser() 810{ 811 if (! mainTerminated) { 812 spv::Block* lastMainBlock = shaderEntry->getLastBlock(); 813 builder.setBuildPoint(lastMainBlock); 814 builder.leaveFunction(); 815 } 816} 817 818// 819// Implement the traversal functions. 820// 821// Return true from interior nodes to have the external traversal 822// continue on to children. Return false if children were 823// already processed. 824// 825 826// 827// Symbols can turn into 828// - uniform/input reads 829// - output writes 830// - complex lvalue base setups: foo.bar[3].... , where we see foo and start up an access chain 831// - something simple that degenerates into the last bullet 832// 833void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol) 834{ 835 SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder); 836 if (symbol->getType().getQualifier().isSpecConstant()) 837 spec_constant_op_mode_setter.turnOnSpecConstantOpMode(); 838 839 // getSymbolId() will set up all the IO decorations on the first call. 840 // Formal function parameters were mapped during makeFunctions(). 841 spv::Id id = getSymbolId(symbol); 842 843 // Include all "static use" and "linkage only" interface variables on the OpEntryPoint instruction 844 if (builder.isPointer(id)) { 845 spv::StorageClass sc = builder.getStorageClass(id); 846 if (sc == spv::StorageClassInput || sc == spv::StorageClassOutput) 847 iOSet.insert(id); 848 } 849 850 // Only process non-linkage-only nodes for generating actual static uses 851 if (! linkageOnly || symbol->getQualifier().isSpecConstant()) { 852 // Prepare to generate code for the access 853 854 // L-value chains will be computed left to right. We're on the symbol now, 855 // which is the left-most part of the access chain, so now is "clear" time, 856 // followed by setting the base. 857 builder.clearAccessChain(); 858 859 // For now, we consider all user variables as being in memory, so they are pointers, 860 // except for 861 // A) "const in" arguments to a function, which are an intermediate object. 862 // See comments in handleUserFunctionCall(). 863 // B) Specialization constants (normal constant don't even come in as a variable), 864 // These are also pure R-values. 865 glslang::TQualifier qualifier = symbol->getQualifier(); 866 if ((qualifier.storage == glslang::EvqConstReadOnly && constReadOnlyParameters.find(symbol->getId()) != constReadOnlyParameters.end()) || 867 qualifier.isSpecConstant()) 868 builder.setAccessChainRValue(id); 869 else 870 builder.setAccessChainLValue(id); 871 } 872} 873 874bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::TIntermBinary* node) 875{ 876 SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder); 877 if (node->getType().getQualifier().isSpecConstant()) 878 spec_constant_op_mode_setter.turnOnSpecConstantOpMode(); 879 880 // First, handle special cases 881 switch (node->getOp()) { 882 case glslang::EOpAssign: 883 case glslang::EOpAddAssign: 884 case glslang::EOpSubAssign: 885 case glslang::EOpMulAssign: 886 case glslang::EOpVectorTimesMatrixAssign: 887 case glslang::EOpVectorTimesScalarAssign: 888 case glslang::EOpMatrixTimesScalarAssign: 889 case glslang::EOpMatrixTimesMatrixAssign: 890 case glslang::EOpDivAssign: 891 case glslang::EOpModAssign: 892 case glslang::EOpAndAssign: 893 case glslang::EOpInclusiveOrAssign: 894 case glslang::EOpExclusiveOrAssign: 895 case glslang::EOpLeftShiftAssign: 896 case glslang::EOpRightShiftAssign: 897 // A bin-op assign "a += b" means the same thing as "a = a + b" 898 // where a is evaluated before b. For a simple assignment, GLSL 899 // says to evaluate the left before the right. So, always, left 900 // node then right node. 901 { 902 // get the left l-value, save it away 903 builder.clearAccessChain(); 904 node->getLeft()->traverse(this); 905 spv::Builder::AccessChain lValue = builder.getAccessChain(); 906 907 // evaluate the right 908 builder.clearAccessChain(); 909 node->getRight()->traverse(this); 910 spv::Id rValue = accessChainLoad(node->getRight()->getType()); 911 912 if (node->getOp() != glslang::EOpAssign) { 913 // the left is also an r-value 914 builder.setAccessChain(lValue); 915 spv::Id leftRValue = accessChainLoad(node->getLeft()->getType()); 916 917 // do the operation 918 rValue = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()), 919 TranslateNoContractionDecoration(node->getType().getQualifier()), 920 convertGlslangToSpvType(node->getType()), leftRValue, rValue, 921 node->getType().getBasicType()); 922 923 // these all need their counterparts in createBinaryOperation() 924 assert(rValue != spv::NoResult); 925 } 926 927 // store the result 928 builder.setAccessChain(lValue); 929 accessChainStore(node->getType(), rValue); 930 931 // assignments are expressions having an rValue after they are evaluated... 932 builder.clearAccessChain(); 933 builder.setAccessChainRValue(rValue); 934 } 935 return false; 936 case glslang::EOpIndexDirect: 937 case glslang::EOpIndexDirectStruct: 938 { 939 // Get the left part of the access chain. 940 node->getLeft()->traverse(this); 941 942 // Add the next element in the chain 943 944 const int glslangIndex = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst(); 945 if (! node->getLeft()->getType().isArray() && 946 node->getLeft()->getType().isVector() && 947 node->getOp() == glslang::EOpIndexDirect) { 948 // This is essentially a hard-coded vector swizzle of size 1, 949 // so short circuit the access-chain stuff with a swizzle. 950 std::vector<unsigned> swizzle; 951 swizzle.push_back(glslangIndex); 952 builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType())); 953 } else { 954 int spvIndex = glslangIndex; 955 if (node->getLeft()->getBasicType() == glslang::EbtBlock && 956 node->getOp() == glslang::EOpIndexDirectStruct) 957 { 958 // This may be, e.g., an anonymous block-member selection, which generally need 959 // index remapping due to hidden members in anonymous blocks. 960 std::vector<int>& remapper = memberRemapper[node->getLeft()->getType().getStruct()]; 961 assert(remapper.size() > 0); 962 spvIndex = remapper[glslangIndex]; 963 } 964 965 // normal case for indexing array or structure or block 966 builder.accessChainPush(builder.makeIntConstant(spvIndex)); 967 968 // Add capabilities here for accessing PointSize and clip/cull distance. 969 // We have deferred generation of associated capabilities until now. 970 if (node->getLeft()->getType().isStruct() && ! node->getLeft()->getType().isArray()) 971 declareUseOfStructMember(*(node->getLeft()->getType().getStruct()), glslangIndex); 972 } 973 } 974 return false; 975 case glslang::EOpIndexIndirect: 976 { 977 // Structure or array or vector indirection. 978 // Will use native SPIR-V access-chain for struct and array indirection; 979 // matrices are arrays of vectors, so will also work for a matrix. 980 // Will use the access chain's 'component' for variable index into a vector. 981 982 // This adapter is building access chains left to right. 983 // Set up the access chain to the left. 984 node->getLeft()->traverse(this); 985 986 // save it so that computing the right side doesn't trash it 987 spv::Builder::AccessChain partial = builder.getAccessChain(); 988 989 // compute the next index in the chain 990 builder.clearAccessChain(); 991 node->getRight()->traverse(this); 992 spv::Id index = accessChainLoad(node->getRight()->getType()); 993 994 // restore the saved access chain 995 builder.setAccessChain(partial); 996 997 if (! node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector()) 998 builder.accessChainPushComponent(index, convertGlslangToSpvType(node->getLeft()->getType())); 999 else 1000 builder.accessChainPush(index); 1001 } 1002 return false; 1003 case glslang::EOpVectorSwizzle: 1004 { 1005 node->getLeft()->traverse(this); 1006 glslang::TIntermSequence& swizzleSequence = node->getRight()->getAsAggregate()->getSequence(); 1007 std::vector<unsigned> swizzle; 1008 for (int i = 0; i < (int)swizzleSequence.size(); ++i) 1009 swizzle.push_back(swizzleSequence[i]->getAsConstantUnion()->getConstArray()[0].getIConst()); 1010 builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType())); 1011 } 1012 return false; 1013 case glslang::EOpLogicalOr: 1014 case glslang::EOpLogicalAnd: 1015 { 1016 1017 // These may require short circuiting, but can sometimes be done as straight 1018 // binary operations. The right operand must be short circuited if it has 1019 // side effects, and should probably be if it is complex. 1020 if (isTrivial(node->getRight()->getAsTyped())) 1021 break; // handle below as a normal binary operation 1022 // otherwise, we need to do dynamic short circuiting on the right operand 1023 spv::Id result = createShortCircuit(node->getOp(), *node->getLeft()->getAsTyped(), *node->getRight()->getAsTyped()); 1024 builder.clearAccessChain(); 1025 builder.setAccessChainRValue(result); 1026 } 1027 return false; 1028 default: 1029 break; 1030 } 1031 1032 // Assume generic binary op... 1033 1034 // get right operand 1035 builder.clearAccessChain(); 1036 node->getLeft()->traverse(this); 1037 spv::Id left = accessChainLoad(node->getLeft()->getType()); 1038 1039 // get left operand 1040 builder.clearAccessChain(); 1041 node->getRight()->traverse(this); 1042 spv::Id right = accessChainLoad(node->getRight()->getType()); 1043 1044 // get result 1045 spv::Id result = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()), 1046 TranslateNoContractionDecoration(node->getType().getQualifier()), 1047 convertGlslangToSpvType(node->getType()), left, right, 1048 node->getLeft()->getType().getBasicType()); 1049 1050 builder.clearAccessChain(); 1051 if (! result) { 1052 logger->missingFunctionality("unknown glslang binary operation"); 1053 return true; // pick up a child as the place-holder result 1054 } else { 1055 builder.setAccessChainRValue(result); 1056 return false; 1057 } 1058} 1059 1060bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node) 1061{ 1062 SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder); 1063 if (node->getType().getQualifier().isSpecConstant()) 1064 spec_constant_op_mode_setter.turnOnSpecConstantOpMode(); 1065 1066 spv::Id result = spv::NoResult; 1067 1068 // try texturing first 1069 result = createImageTextureFunctionCall(node); 1070 if (result != spv::NoResult) { 1071 builder.clearAccessChain(); 1072 builder.setAccessChainRValue(result); 1073 1074 return false; // done with this node 1075 } 1076 1077 // Non-texturing. 1078 1079 if (node->getOp() == glslang::EOpArrayLength) { 1080 // Quite special; won't want to evaluate the operand. 1081 1082 // Normal .length() would have been constant folded by the front-end. 1083 // So, this has to be block.lastMember.length(). 1084 // SPV wants "block" and member number as the operands, go get them. 1085 assert(node->getOperand()->getType().isRuntimeSizedArray()); 1086 glslang::TIntermTyped* block = node->getOperand()->getAsBinaryNode()->getLeft(); 1087 block->traverse(this); 1088 unsigned int member = node->getOperand()->getAsBinaryNode()->getRight()->getAsConstantUnion()->getConstArray()[0].getUConst(); 1089 spv::Id length = builder.createArrayLength(builder.accessChainGetLValue(), member); 1090 1091 builder.clearAccessChain(); 1092 builder.setAccessChainRValue(length); 1093 1094 return false; 1095 } 1096 1097 // Start by evaluating the operand 1098 1099 builder.clearAccessChain(); 1100 node->getOperand()->traverse(this); 1101 1102 spv::Id operand = spv::NoResult; 1103 1104 if (node->getOp() == glslang::EOpAtomicCounterIncrement || 1105 node->getOp() == glslang::EOpAtomicCounterDecrement || 1106 node->getOp() == glslang::EOpAtomicCounter || 1107 node->getOp() == glslang::EOpInterpolateAtCentroid) 1108 operand = builder.accessChainGetLValue(); // Special case l-value operands 1109 else 1110 operand = accessChainLoad(node->getOperand()->getType()); 1111 1112 spv::Decoration precision = TranslatePrecisionDecoration(node->getType()); 1113 spv::Decoration noContraction = TranslateNoContractionDecoration(node->getType().getQualifier()); 1114 1115 // it could be a conversion 1116 if (! result) 1117 result = createConversion(node->getOp(), precision, noContraction, convertGlslangToSpvType(node->getType()), operand, node->getOperand()->getBasicType()); 1118 1119 // if not, then possibly an operation 1120 if (! result) 1121 result = createUnaryOperation(node->getOp(), precision, noContraction, convertGlslangToSpvType(node->getType()), operand, node->getOperand()->getBasicType()); 1122 1123 if (result) { 1124 builder.clearAccessChain(); 1125 builder.setAccessChainRValue(result); 1126 1127 return false; // done with this node 1128 } 1129 1130 // it must be a special case, check... 1131 switch (node->getOp()) { 1132 case glslang::EOpPostIncrement: 1133 case glslang::EOpPostDecrement: 1134 case glslang::EOpPreIncrement: 1135 case glslang::EOpPreDecrement: 1136 { 1137 // we need the integer value "1" or the floating point "1.0" to add/subtract 1138 spv::Id one = 0; 1139 if (node->getBasicType() == glslang::EbtFloat) 1140 one = builder.makeFloatConstant(1.0F); 1141 else if (node->getBasicType() == glslang::EbtInt64 || node->getBasicType() == glslang::EbtUint64) 1142 one = builder.makeInt64Constant(1); 1143 else 1144 one = builder.makeIntConstant(1); 1145 glslang::TOperator op; 1146 if (node->getOp() == glslang::EOpPreIncrement || 1147 node->getOp() == glslang::EOpPostIncrement) 1148 op = glslang::EOpAdd; 1149 else 1150 op = glslang::EOpSub; 1151 1152 spv::Id result = createBinaryOperation(op, TranslatePrecisionDecoration(node->getType()), 1153 TranslateNoContractionDecoration(node->getType().getQualifier()), 1154 convertGlslangToSpvType(node->getType()), operand, one, 1155 node->getType().getBasicType()); 1156 assert(result != spv::NoResult); 1157 1158 // The result of operation is always stored, but conditionally the 1159 // consumed result. The consumed result is always an r-value. 1160 builder.accessChainStore(result); 1161 builder.clearAccessChain(); 1162 if (node->getOp() == glslang::EOpPreIncrement || 1163 node->getOp() == glslang::EOpPreDecrement) 1164 builder.setAccessChainRValue(result); 1165 else 1166 builder.setAccessChainRValue(operand); 1167 } 1168 1169 return false; 1170 1171 case glslang::EOpEmitStreamVertex: 1172 builder.createNoResultOp(spv::OpEmitStreamVertex, operand); 1173 return false; 1174 case glslang::EOpEndStreamPrimitive: 1175 builder.createNoResultOp(spv::OpEndStreamPrimitive, operand); 1176 return false; 1177 1178 default: 1179 logger->missingFunctionality("unknown glslang unary"); 1180 return true; // pick up operand as placeholder result 1181 } 1182} 1183 1184bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TIntermAggregate* node) 1185{ 1186 SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder); 1187 if (node->getType().getQualifier().isSpecConstant()) 1188 spec_constant_op_mode_setter.turnOnSpecConstantOpMode(); 1189 1190 spv::Id result = spv::NoResult; 1191 1192 // try texturing 1193 result = createImageTextureFunctionCall(node); 1194 if (result != spv::NoResult) { 1195 builder.clearAccessChain(); 1196 builder.setAccessChainRValue(result); 1197 1198 return false; 1199 } else if (node->getOp() == glslang::EOpImageStore) { 1200 // "imageStore" is a special case, which has no result 1201 return false; 1202 } 1203 1204 glslang::TOperator binOp = glslang::EOpNull; 1205 bool reduceComparison = true; 1206 bool isMatrix = false; 1207 bool noReturnValue = false; 1208 bool atomic = false; 1209 1210 assert(node->getOp()); 1211 1212 spv::Decoration precision = TranslatePrecisionDecoration(node->getType()); 1213 1214 switch (node->getOp()) { 1215 case glslang::EOpSequence: 1216 { 1217 if (preVisit) 1218 ++sequenceDepth; 1219 else 1220 --sequenceDepth; 1221 1222 if (sequenceDepth == 1) { 1223 // If this is the parent node of all the functions, we want to see them 1224 // early, so all call points have actual SPIR-V functions to reference. 1225 // In all cases, still let the traverser visit the children for us. 1226 makeFunctions(node->getAsAggregate()->getSequence()); 1227 1228 // Also, we want all globals initializers to go into the entry of main(), before 1229 // anything else gets there, so visit out of order, doing them all now. 1230 makeGlobalInitializers(node->getAsAggregate()->getSequence()); 1231 1232 // Initializers are done, don't want to visit again, but functions link objects need to be processed, 1233 // so do them manually. 1234 visitFunctions(node->getAsAggregate()->getSequence()); 1235 1236 return false; 1237 } 1238 1239 return true; 1240 } 1241 case glslang::EOpLinkerObjects: 1242 { 1243 if (visit == glslang::EvPreVisit) 1244 linkageOnly = true; 1245 else 1246 linkageOnly = false; 1247 1248 return true; 1249 } 1250 case glslang::EOpComma: 1251 { 1252 // processing from left to right naturally leaves the right-most 1253 // lying around in the access chain 1254 glslang::TIntermSequence& glslangOperands = node->getSequence(); 1255 for (int i = 0; i < (int)glslangOperands.size(); ++i) 1256 glslangOperands[i]->traverse(this); 1257 1258 return false; 1259 } 1260 case glslang::EOpFunction: 1261 if (visit == glslang::EvPreVisit) { 1262 if (isShaderEntrypoint(node)) { 1263 inMain = true; 1264 builder.setBuildPoint(shaderEntry->getLastBlock()); 1265 } else { 1266 handleFunctionEntry(node); 1267 } 1268 } else { 1269 if (inMain) 1270 mainTerminated = true; 1271 builder.leaveFunction(); 1272 inMain = false; 1273 } 1274 1275 return true; 1276 case glslang::EOpParameters: 1277 // Parameters will have been consumed by EOpFunction processing, but not 1278 // the body, so we still visited the function node's children, making this 1279 // child redundant. 1280 return false; 1281 case glslang::EOpFunctionCall: 1282 { 1283 if (node->isUserDefined()) 1284 result = handleUserFunctionCall(node); 1285 //assert(result); // this can happen for bad shaders because the call graph completeness checking is not yet done 1286 if (result) { 1287 builder.clearAccessChain(); 1288 builder.setAccessChainRValue(result); 1289 } else 1290 logger->missingFunctionality("missing user function; linker needs to catch that"); 1291 1292 return false; 1293 } 1294 case glslang::EOpConstructMat2x2: 1295 case glslang::EOpConstructMat2x3: 1296 case glslang::EOpConstructMat2x4: 1297 case glslang::EOpConstructMat3x2: 1298 case glslang::EOpConstructMat3x3: 1299 case glslang::EOpConstructMat3x4: 1300 case glslang::EOpConstructMat4x2: 1301 case glslang::EOpConstructMat4x3: 1302 case glslang::EOpConstructMat4x4: 1303 case glslang::EOpConstructDMat2x2: 1304 case glslang::EOpConstructDMat2x3: 1305 case glslang::EOpConstructDMat2x4: 1306 case glslang::EOpConstructDMat3x2: 1307 case glslang::EOpConstructDMat3x3: 1308 case glslang::EOpConstructDMat3x4: 1309 case glslang::EOpConstructDMat4x2: 1310 case glslang::EOpConstructDMat4x3: 1311 case glslang::EOpConstructDMat4x4: 1312 isMatrix = true; 1313 // fall through 1314 case glslang::EOpConstructFloat: 1315 case glslang::EOpConstructVec2: 1316 case glslang::EOpConstructVec3: 1317 case glslang::EOpConstructVec4: 1318 case glslang::EOpConstructDouble: 1319 case glslang::EOpConstructDVec2: 1320 case glslang::EOpConstructDVec3: 1321 case glslang::EOpConstructDVec4: 1322 case glslang::EOpConstructBool: 1323 case glslang::EOpConstructBVec2: 1324 case glslang::EOpConstructBVec3: 1325 case glslang::EOpConstructBVec4: 1326 case glslang::EOpConstructInt: 1327 case glslang::EOpConstructIVec2: 1328 case glslang::EOpConstructIVec3: 1329 case glslang::EOpConstructIVec4: 1330 case glslang::EOpConstructUint: 1331 case glslang::EOpConstructUVec2: 1332 case glslang::EOpConstructUVec3: 1333 case glslang::EOpConstructUVec4: 1334 case glslang::EOpConstructInt64: 1335 case glslang::EOpConstructI64Vec2: 1336 case glslang::EOpConstructI64Vec3: 1337 case glslang::EOpConstructI64Vec4: 1338 case glslang::EOpConstructUint64: 1339 case glslang::EOpConstructU64Vec2: 1340 case glslang::EOpConstructU64Vec3: 1341 case glslang::EOpConstructU64Vec4: 1342 case glslang::EOpConstructStruct: 1343 case glslang::EOpConstructTextureSampler: 1344 { 1345 std::vector<spv::Id> arguments; 1346 translateArguments(*node, arguments); 1347 spv::Id resultTypeId = convertGlslangToSpvType(node->getType()); 1348 spv::Id constructed; 1349 if (node->getOp() == glslang::EOpConstructTextureSampler) 1350 constructed = builder.createOp(spv::OpSampledImage, resultTypeId, arguments); 1351 else if (node->getOp() == glslang::EOpConstructStruct || node->getType().isArray()) { 1352 std::vector<spv::Id> constituents; 1353 for (int c = 0; c < (int)arguments.size(); ++c) 1354 constituents.push_back(arguments[c]); 1355 constructed = builder.createCompositeConstruct(resultTypeId, constituents); 1356 } else if (isMatrix) 1357 constructed = builder.createMatrixConstructor(precision, arguments, resultTypeId); 1358 else 1359 constructed = builder.createConstructor(precision, arguments, resultTypeId); 1360 1361 builder.clearAccessChain(); 1362 builder.setAccessChainRValue(constructed); 1363 1364 return false; 1365 } 1366 1367 // These six are component-wise compares with component-wise results. 1368 // Forward on to createBinaryOperation(), requesting a vector result. 1369 case glslang::EOpLessThan: 1370 case glslang::EOpGreaterThan: 1371 case glslang::EOpLessThanEqual: 1372 case glslang::EOpGreaterThanEqual: 1373 case glslang::EOpVectorEqual: 1374 case glslang::EOpVectorNotEqual: 1375 { 1376 // Map the operation to a binary 1377 binOp = node->getOp(); 1378 reduceComparison = false; 1379 switch (node->getOp()) { 1380 case glslang::EOpVectorEqual: binOp = glslang::EOpVectorEqual; break; 1381 case glslang::EOpVectorNotEqual: binOp = glslang::EOpVectorNotEqual; break; 1382 default: binOp = node->getOp(); break; 1383 } 1384 1385 break; 1386 } 1387 case glslang::EOpMul: 1388 // compontent-wise matrix multiply 1389 binOp = glslang::EOpMul; 1390 break; 1391 case glslang::EOpOuterProduct: 1392 // two vectors multiplied to make a matrix 1393 binOp = glslang::EOpOuterProduct; 1394 break; 1395 case glslang::EOpDot: 1396 { 1397 // for scalar dot product, use multiply 1398 glslang::TIntermSequence& glslangOperands = node->getSequence(); 1399 if (glslangOperands[0]->getAsTyped()->getVectorSize() == 1) 1400 binOp = glslang::EOpMul; 1401 break; 1402 } 1403 case glslang::EOpMod: 1404 // when an aggregate, this is the floating-point mod built-in function, 1405 // which can be emitted by the one in createBinaryOperation() 1406 binOp = glslang::EOpMod; 1407 break; 1408 case glslang::EOpEmitVertex: 1409 case glslang::EOpEndPrimitive: 1410 case glslang::EOpBarrier: 1411 case glslang::EOpMemoryBarrier: 1412 case glslang::EOpMemoryBarrierAtomicCounter: 1413 case glslang::EOpMemoryBarrierBuffer: 1414 case glslang::EOpMemoryBarrierImage: 1415 case glslang::EOpMemoryBarrierShared: 1416 case glslang::EOpGroupMemoryBarrier: 1417 case glslang::EOpAllMemoryBarrierWithGroupSync: 1418 case glslang::EOpGroupMemoryBarrierWithGroupSync: 1419 case glslang::EOpWorkgroupMemoryBarrier: 1420 case glslang::EOpWorkgroupMemoryBarrierWithGroupSync: 1421 noReturnValue = true; 1422 // These all have 0 operands and will naturally finish up in the code below for 0 operands 1423 break; 1424 1425 case glslang::EOpAtomicAdd: 1426 case glslang::EOpAtomicMin: 1427 case glslang::EOpAtomicMax: 1428 case glslang::EOpAtomicAnd: 1429 case glslang::EOpAtomicOr: 1430 case glslang::EOpAtomicXor: 1431 case glslang::EOpAtomicExchange: 1432 case glslang::EOpAtomicCompSwap: 1433 atomic = true; 1434 break; 1435 1436 default: 1437 break; 1438 } 1439 1440 // 1441 // See if it maps to a regular operation. 1442 // 1443 if (binOp != glslang::EOpNull) { 1444 glslang::TIntermTyped* left = node->getSequence()[0]->getAsTyped(); 1445 glslang::TIntermTyped* right = node->getSequence()[1]->getAsTyped(); 1446 assert(left && right); 1447 1448 builder.clearAccessChain(); 1449 left->traverse(this); 1450 spv::Id leftId = accessChainLoad(left->getType()); 1451 1452 builder.clearAccessChain(); 1453 right->traverse(this); 1454 spv::Id rightId = accessChainLoad(right->getType()); 1455 1456 result = createBinaryOperation(binOp, precision, TranslateNoContractionDecoration(node->getType().getQualifier()), 1457 convertGlslangToSpvType(node->getType()), leftId, rightId, 1458 left->getType().getBasicType(), reduceComparison); 1459 1460 // code above should only make binOp that exists in createBinaryOperation 1461 assert(result != spv::NoResult); 1462 builder.clearAccessChain(); 1463 builder.setAccessChainRValue(result); 1464 1465 return false; 1466 } 1467 1468 // 1469 // Create the list of operands. 1470 // 1471 glslang::TIntermSequence& glslangOperands = node->getSequence(); 1472 std::vector<spv::Id> operands; 1473 for (int arg = 0; arg < (int)glslangOperands.size(); ++arg) { 1474 builder.clearAccessChain(); 1475 glslangOperands[arg]->traverse(this); 1476 1477 // special case l-value operands; there are just a few 1478 bool lvalue = false; 1479 switch (node->getOp()) { 1480 case glslang::EOpFrexp: 1481 case glslang::EOpModf: 1482 if (arg == 1) 1483 lvalue = true; 1484 break; 1485 case glslang::EOpInterpolateAtSample: 1486 case glslang::EOpInterpolateAtOffset: 1487 if (arg == 0) 1488 lvalue = true; 1489 break; 1490 case glslang::EOpAtomicAdd: 1491 case glslang::EOpAtomicMin: 1492 case glslang::EOpAtomicMax: 1493 case glslang::EOpAtomicAnd: 1494 case glslang::EOpAtomicOr: 1495 case glslang::EOpAtomicXor: 1496 case glslang::EOpAtomicExchange: 1497 case glslang::EOpAtomicCompSwap: 1498 if (arg == 0) 1499 lvalue = true; 1500 break; 1501 case glslang::EOpAddCarry: 1502 case glslang::EOpSubBorrow: 1503 if (arg == 2) 1504 lvalue = true; 1505 break; 1506 case glslang::EOpUMulExtended: 1507 case glslang::EOpIMulExtended: 1508 if (arg >= 2) 1509 lvalue = true; 1510 break; 1511 default: 1512 break; 1513 } 1514 if (lvalue) 1515 operands.push_back(builder.accessChainGetLValue()); 1516 else 1517 operands.push_back(accessChainLoad(glslangOperands[arg]->getAsTyped()->getType())); 1518 } 1519 1520 if (atomic) { 1521 // Handle all atomics 1522 result = createAtomicOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands, node->getBasicType()); 1523 } else { 1524 // Pass through to generic operations. 1525 switch (glslangOperands.size()) { 1526 case 0: 1527 result = createNoArgOperation(node->getOp()); 1528 break; 1529 case 1: 1530 result = createUnaryOperation( 1531 node->getOp(), precision, 1532 TranslateNoContractionDecoration(node->getType().getQualifier()), 1533 convertGlslangToSpvType(node->getType()), operands.front(), 1534 glslangOperands[0]->getAsTyped()->getBasicType()); 1535 break; 1536 default: 1537 result = createMiscOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands, node->getBasicType()); 1538 break; 1539 } 1540 } 1541 1542 if (noReturnValue) 1543 return false; 1544 1545 if (! result) { 1546 logger->missingFunctionality("unknown glslang aggregate"); 1547 return true; // pick up a child as a placeholder operand 1548 } else { 1549 builder.clearAccessChain(); 1550 builder.setAccessChainRValue(result); 1551 return false; 1552 } 1553} 1554 1555bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang::TIntermSelection* node) 1556{ 1557 // This path handles both if-then-else and ?: 1558 // The if-then-else has a node type of void, while 1559 // ?: has a non-void node type 1560 spv::Id result = 0; 1561 if (node->getBasicType() != glslang::EbtVoid) { 1562 // don't handle this as just on-the-fly temporaries, because there will be two names 1563 // and better to leave SSA to later passes 1564 result = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(node->getType())); 1565 } 1566 1567 // emit the condition before doing anything with selection 1568 node->getCondition()->traverse(this); 1569 1570 // make an "if" based on the value created by the condition 1571 spv::Builder::If ifBuilder(accessChainLoad(node->getCondition()->getType()), builder); 1572 1573 if (node->getTrueBlock()) { 1574 // emit the "then" statement 1575 node->getTrueBlock()->traverse(this); 1576 if (result) 1577 builder.createStore(accessChainLoad(node->getTrueBlock()->getAsTyped()->getType()), result); 1578 } 1579 1580 if (node->getFalseBlock()) { 1581 ifBuilder.makeBeginElse(); 1582 // emit the "else" statement 1583 node->getFalseBlock()->traverse(this); 1584 if (result) 1585 builder.createStore(accessChainLoad(node->getFalseBlock()->getAsTyped()->getType()), result); 1586 } 1587 1588 ifBuilder.makeEndIf(); 1589 1590 if (result) { 1591 // GLSL only has r-values as the result of a :?, but 1592 // if we have an l-value, that can be more efficient if it will 1593 // become the base of a complex r-value expression, because the 1594 // next layer copies r-values into memory to use the access-chain mechanism 1595 builder.clearAccessChain(); 1596 builder.setAccessChainLValue(result); 1597 } 1598 1599 return false; 1600} 1601 1602bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::TIntermSwitch* node) 1603{ 1604 // emit and get the condition before doing anything with switch 1605 node->getCondition()->traverse(this); 1606 spv::Id selector = accessChainLoad(node->getCondition()->getAsTyped()->getType()); 1607 1608 // browse the children to sort out code segments 1609 int defaultSegment = -1; 1610 std::vector<TIntermNode*> codeSegments; 1611 glslang::TIntermSequence& sequence = node->getBody()->getSequence(); 1612 std::vector<int> caseValues; 1613 std::vector<int> valueIndexToSegment(sequence.size()); // note: probably not all are used, it is an overestimate 1614 for (glslang::TIntermSequence::iterator c = sequence.begin(); c != sequence.end(); ++c) { 1615 TIntermNode* child = *c; 1616 if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpDefault) 1617 defaultSegment = (int)codeSegments.size(); 1618 else if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpCase) { 1619 valueIndexToSegment[caseValues.size()] = (int)codeSegments.size(); 1620 caseValues.push_back(child->getAsBranchNode()->getExpression()->getAsConstantUnion()->getConstArray()[0].getIConst()); 1621 } else 1622 codeSegments.push_back(child); 1623 } 1624 1625 // handle the case where the last code segment is missing, due to no code 1626 // statements between the last case and the end of the switch statement 1627 if ((caseValues.size() && (int)codeSegments.size() == valueIndexToSegment[caseValues.size() - 1]) || 1628 (int)codeSegments.size() == defaultSegment) 1629 codeSegments.push_back(nullptr); 1630 1631 // make the switch statement 1632 std::vector<spv::Block*> segmentBlocks; // returned, as the blocks allocated in the call 1633 builder.makeSwitch(selector, (int)codeSegments.size(), caseValues, valueIndexToSegment, defaultSegment, segmentBlocks); 1634 1635 // emit all the code in the segments 1636 breakForLoop.push(false); 1637 for (unsigned int s = 0; s < codeSegments.size(); ++s) { 1638 builder.nextSwitchSegment(segmentBlocks, s); 1639 if (codeSegments[s]) 1640 codeSegments[s]->traverse(this); 1641 else 1642 builder.addSwitchBreak(); 1643 } 1644 breakForLoop.pop(); 1645 1646 builder.endSwitch(segmentBlocks); 1647 1648 return false; 1649} 1650 1651void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node) 1652{ 1653 int nextConst = 0; 1654 spv::Id constant = createSpvConstantFromConstUnionArray(node->getType(), node->getConstArray(), nextConst, false); 1655 1656 builder.clearAccessChain(); 1657 builder.setAccessChainRValue(constant); 1658} 1659 1660bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIntermLoop* node) 1661{ 1662 auto blocks = builder.makeNewLoop(); 1663 builder.createBranch(&blocks.head); 1664 // Spec requires back edges to target header blocks, and every header block 1665 // must dominate its merge block. Make a header block first to ensure these 1666 // conditions are met. By definition, it will contain OpLoopMerge, followed 1667 // by a block-ending branch. But we don't want to put any other body/test 1668 // instructions in it, since the body/test may have arbitrary instructions, 1669 // including merges of its own. 1670 builder.setBuildPoint(&blocks.head); 1671 builder.createLoopMerge(&blocks.merge, &blocks.continue_target, spv::LoopControlMaskNone); 1672 if (node->testFirst() && node->getTest()) { 1673 spv::Block& test = builder.makeNewBlock(); 1674 builder.createBranch(&test); 1675 1676 builder.setBuildPoint(&test); 1677 node->getTest()->traverse(this); 1678 spv::Id condition = 1679 accessChainLoad(node->getTest()->getType()); 1680 builder.createConditionalBranch(condition, &blocks.body, &blocks.merge); 1681 1682 builder.setBuildPoint(&blocks.body); 1683 breakForLoop.push(true); 1684 if (node->getBody()) 1685 node->getBody()->traverse(this); 1686 builder.createBranch(&blocks.continue_target); 1687 breakForLoop.pop(); 1688 1689 builder.setBuildPoint(&blocks.continue_target); 1690 if (node->getTerminal()) 1691 node->getTerminal()->traverse(this); 1692 builder.createBranch(&blocks.head); 1693 } else { 1694 builder.createBranch(&blocks.body); 1695 1696 breakForLoop.push(true); 1697 builder.setBuildPoint(&blocks.body); 1698 if (node->getBody()) 1699 node->getBody()->traverse(this); 1700 builder.createBranch(&blocks.continue_target); 1701 breakForLoop.pop(); 1702 1703 builder.setBuildPoint(&blocks.continue_target); 1704 if (node->getTerminal()) 1705 node->getTerminal()->traverse(this); 1706 if (node->getTest()) { 1707 node->getTest()->traverse(this); 1708 spv::Id condition = 1709 accessChainLoad(node->getTest()->getType()); 1710 builder.createConditionalBranch(condition, &blocks.head, &blocks.merge); 1711 } else { 1712 // TODO: unless there was a break/return/discard instruction 1713 // somewhere in the body, this is an infinite loop, so we should 1714 // issue a warning. 1715 builder.createBranch(&blocks.head); 1716 } 1717 } 1718 builder.setBuildPoint(&blocks.merge); 1719 builder.closeLoop(); 1720 return false; 1721} 1722 1723bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::TIntermBranch* node) 1724{ 1725 if (node->getExpression()) 1726 node->getExpression()->traverse(this); 1727 1728 switch (node->getFlowOp()) { 1729 case glslang::EOpKill: 1730 builder.makeDiscard(); 1731 break; 1732 case glslang::EOpBreak: 1733 if (breakForLoop.top()) 1734 builder.createLoopExit(); 1735 else 1736 builder.addSwitchBreak(); 1737 break; 1738 case glslang::EOpContinue: 1739 builder.createLoopContinue(); 1740 break; 1741 case glslang::EOpReturn: 1742 if (node->getExpression()) 1743 builder.makeReturn(false, accessChainLoad(node->getExpression()->getType())); 1744 else 1745 builder.makeReturn(false); 1746 1747 builder.clearAccessChain(); 1748 break; 1749 1750 default: 1751 assert(0); 1752 break; 1753 } 1754 1755 return false; 1756} 1757 1758spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* node) 1759{ 1760 // First, steer off constants, which are not SPIR-V variables, but 1761 // can still have a mapping to a SPIR-V Id. 1762 // This includes specialization constants. 1763 if (node->getQualifier().isConstant()) { 1764 return createSpvConstant(*node); 1765 } 1766 1767 // Now, handle actual variables 1768 spv::StorageClass storageClass = TranslateStorageClass(node->getType()); 1769 spv::Id spvType = convertGlslangToSpvType(node->getType()); 1770 1771 const char* name = node->getName().c_str(); 1772 if (glslang::IsAnonymous(name)) 1773 name = ""; 1774 1775 return builder.createVariable(storageClass, spvType, name); 1776} 1777 1778// Return type Id of the sampled type. 1779spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler) 1780{ 1781 switch (sampler.type) { 1782 case glslang::EbtFloat: return builder.makeFloatType(32); 1783 case glslang::EbtInt: return builder.makeIntType(32); 1784 case glslang::EbtUint: return builder.makeUintType(32); 1785 default: 1786 assert(0); 1787 return builder.makeFloatType(32); 1788 } 1789} 1790 1791// Convert from a glslang type to an SPV type, by calling into a 1792// recursive version of this function. This establishes the inherited 1793// layout state rooted from the top-level type. 1794spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type) 1795{ 1796 return convertGlslangToSpvType(type, getExplicitLayout(type), type.getQualifier()); 1797} 1798 1799// Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id. 1800// explicitLayout can be kept the same throughout the hierarchical recursive walk. 1801// Mutually recursive with convertGlslangStructToSpvType(). 1802spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking explicitLayout, const glslang::TQualifier& qualifier) 1803{ 1804 spv::Id spvType = spv::NoResult; 1805 1806 switch (type.getBasicType()) { 1807 case glslang::EbtVoid: 1808 spvType = builder.makeVoidType(); 1809 assert (! type.isArray()); 1810 break; 1811 case glslang::EbtFloat: 1812 spvType = builder.makeFloatType(32); 1813 break; 1814 case glslang::EbtDouble: 1815 spvType = builder.makeFloatType(64); 1816 break; 1817 case glslang::EbtBool: 1818 // "transparent" bool doesn't exist in SPIR-V. The GLSL convention is 1819 // a 32-bit int where non-0 means true. 1820 if (explicitLayout != glslang::ElpNone) 1821 spvType = builder.makeUintType(32); 1822 else 1823 spvType = builder.makeBoolType(); 1824 break; 1825 case glslang::EbtInt: 1826 spvType = builder.makeIntType(32); 1827 break; 1828 case glslang::EbtUint: 1829 spvType = builder.makeUintType(32); 1830 break; 1831 case glslang::EbtInt64: 1832 builder.addCapability(spv::CapabilityInt64); 1833 spvType = builder.makeIntType(64); 1834 break; 1835 case glslang::EbtUint64: 1836 builder.addCapability(spv::CapabilityInt64); 1837 spvType = builder.makeUintType(64); 1838 break; 1839 case glslang::EbtAtomicUint: 1840 builder.addCapability(spv::CapabilityAtomicStorage); 1841 spvType = builder.makeUintType(32); 1842 break; 1843 case glslang::EbtSampler: 1844 { 1845 const glslang::TSampler& sampler = type.getSampler(); 1846 if (sampler.sampler) { 1847 // pure sampler 1848 spvType = builder.makeSamplerType(); 1849 } else { 1850 // an image is present, make its type 1851 spvType = builder.makeImageType(getSampledType(sampler), TranslateDimensionality(sampler), sampler.shadow, sampler.arrayed, sampler.ms, 1852 sampler.image ? 2 : 1, TranslateImageFormat(type)); 1853 if (sampler.combined) { 1854 // already has both image and sampler, make the combined type 1855 spvType = builder.makeSampledImageType(spvType); 1856 } 1857 } 1858 } 1859 break; 1860 case glslang::EbtStruct: 1861 case glslang::EbtBlock: 1862 { 1863 // If we've seen this struct type, return it 1864 const glslang::TTypeList* glslangMembers = type.getStruct(); 1865 1866 // Try to share structs for different layouts, but not yet for other 1867 // kinds of qualification (primarily not yet including interpolant qualification). 1868 if (! HasNonLayoutQualifiers(qualifier)) 1869 spvType = structMap[explicitLayout][qualifier.layoutMatrix][glslangMembers]; 1870 if (spvType != spv::NoResult) 1871 break; 1872 1873 // else, we haven't seen it... 1874 if (type.getBasicType() == glslang::EbtBlock) 1875 memberRemapper[glslangMembers].resize(glslangMembers->size()); 1876 spvType = convertGlslangStructToSpvType(type, glslangMembers, explicitLayout, qualifier); 1877 } 1878 break; 1879 default: 1880 assert(0); 1881 break; 1882 } 1883 1884 if (type.isMatrix()) 1885 spvType = builder.makeMatrixType(spvType, type.getMatrixCols(), type.getMatrixRows()); 1886 else { 1887 // If this variable has a vector element count greater than 1, create a SPIR-V vector 1888 if (type.getVectorSize() > 1) 1889 spvType = builder.makeVectorType(spvType, type.getVectorSize()); 1890 } 1891 1892 if (type.isArray()) { 1893 int stride = 0; // keep this 0 unless doing an explicit layout; 0 will mean no decoration, no stride 1894 1895 // Do all but the outer dimension 1896 if (type.getArraySizes()->getNumDims() > 1) { 1897 // We need to decorate array strides for types needing explicit layout, except blocks. 1898 if (explicitLayout != glslang::ElpNone && type.getBasicType() != glslang::EbtBlock) { 1899 // Use a dummy glslang type for querying internal strides of 1900 // arrays of arrays, but using just a one-dimensional array. 1901 glslang::TType simpleArrayType(type, 0); // deference type of the array 1902 while (simpleArrayType.getArraySizes().getNumDims() > 1) 1903 simpleArrayType.getArraySizes().dereference(); 1904 1905 // Will compute the higher-order strides here, rather than making a whole 1906 // pile of types and doing repetitive recursion on their contents. 1907 stride = getArrayStride(simpleArrayType, explicitLayout, qualifier.layoutMatrix); 1908 } 1909 1910 // make the arrays 1911 for (int dim = type.getArraySizes()->getNumDims() - 1; dim > 0; --dim) { 1912 spvType = builder.makeArrayType(spvType, makeArraySizeId(*type.getArraySizes(), dim), stride); 1913 if (stride > 0) 1914 builder.addDecoration(spvType, spv::DecorationArrayStride, stride); 1915 stride *= type.getArraySizes()->getDimSize(dim); 1916 } 1917 } else { 1918 // single-dimensional array, and don't yet have stride 1919 1920 // We need to decorate array strides for types needing explicit layout, except blocks. 1921 if (explicitLayout != glslang::ElpNone && type.getBasicType() != glslang::EbtBlock) 1922 stride = getArrayStride(type, explicitLayout, qualifier.layoutMatrix); 1923 } 1924 1925 // Do the outer dimension, which might not be known for a runtime-sized array 1926 if (type.isRuntimeSizedArray()) { 1927 spvType = builder.makeRuntimeArray(spvType); 1928 } else { 1929 assert(type.getOuterArraySize() > 0); 1930 spvType = builder.makeArrayType(spvType, makeArraySizeId(*type.getArraySizes(), 0), stride); 1931 } 1932 if (stride > 0) 1933 builder.addDecoration(spvType, spv::DecorationArrayStride, stride); 1934 } 1935 1936 return spvType; 1937} 1938 1939 1940// Do full recursive conversion of a glslang structure (or block) type to a SPIR-V Id. 1941// explicitLayout can be kept the same throughout the hierarchical recursive walk. 1942// Mutually recursive with convertGlslangToSpvType(). 1943spv::Id TGlslangToSpvTraverser::convertGlslangStructToSpvType(const glslang::TType& type, 1944 const glslang::TTypeList* glslangMembers, 1945 glslang::TLayoutPacking explicitLayout, 1946 const glslang::TQualifier& qualifier) 1947{ 1948 // Create a vector of struct types for SPIR-V to consume 1949 std::vector<spv::Id> spvMembers; 1950 int memberDelta = 0; // how much the member's index changes from glslang to SPIR-V, normally 0, except sometimes for blocks 1951 int locationOffset = 0; // for use across struct members, when they are called recursively 1952 for (int i = 0; i < (int)glslangMembers->size(); i++) { 1953 glslang::TType& glslangMember = *(*glslangMembers)[i].type; 1954 if (glslangMember.hiddenMember()) { 1955 ++memberDelta; 1956 if (type.getBasicType() == glslang::EbtBlock) 1957 memberRemapper[glslangMembers][i] = -1; 1958 } else { 1959 if (type.getBasicType() == glslang::EbtBlock) 1960 memberRemapper[glslangMembers][i] = i - memberDelta; 1961 // modify just this child's view of the qualifier 1962 glslang::TQualifier memberQualifier = glslangMember.getQualifier(); 1963 InheritQualifiers(memberQualifier, qualifier); 1964 1965 // manually inherit location; it's more complex 1966 if (! memberQualifier.hasLocation() && qualifier.hasLocation()) 1967 memberQualifier.layoutLocation = qualifier.layoutLocation + locationOffset; 1968 if (qualifier.hasLocation()) 1969 locationOffset += glslangIntermediate->computeTypeLocationSize(glslangMember); 1970 1971 // recurse 1972 spvMembers.push_back(convertGlslangToSpvType(glslangMember, explicitLayout, memberQualifier)); 1973 } 1974 } 1975 1976 // Make the SPIR-V type 1977 spv::Id spvType = builder.makeStructType(spvMembers, type.getTypeName().c_str()); 1978 if (! HasNonLayoutQualifiers(qualifier)) 1979 structMap[explicitLayout][qualifier.layoutMatrix][glslangMembers] = spvType; 1980 1981 // Decorate it 1982 decorateStructType(type, glslangMembers, explicitLayout, qualifier, spvType); 1983 1984 return spvType; 1985} 1986 1987void TGlslangToSpvTraverser::decorateStructType(const glslang::TType& type, 1988 const glslang::TTypeList* glslangMembers, 1989 glslang::TLayoutPacking explicitLayout, 1990 const glslang::TQualifier& qualifier, 1991 spv::Id spvType) 1992{ 1993 // Name and decorate the non-hidden members 1994 int offset = -1; 1995 int locationOffset = 0; // for use within the members of this struct 1996 for (int i = 0; i < (int)glslangMembers->size(); i++) { 1997 glslang::TType& glslangMember = *(*glslangMembers)[i].type; 1998 int member = i; 1999 if (type.getBasicType() == glslang::EbtBlock) 2000 member = memberRemapper[glslangMembers][i]; 2001 2002 // modify just this child's view of the qualifier 2003 glslang::TQualifier memberQualifier = glslangMember.getQualifier(); 2004 InheritQualifiers(memberQualifier, qualifier); 2005 2006 // using -1 above to indicate a hidden member 2007 if (member >= 0) { 2008 builder.addMemberName(spvType, member, glslangMember.getFieldName().c_str()); 2009 addMemberDecoration(spvType, member, TranslateLayoutDecoration(glslangMember, memberQualifier.layoutMatrix)); 2010 addMemberDecoration(spvType, member, TranslatePrecisionDecoration(glslangMember)); 2011 // Add interpolation and auxiliary storage decorations only to top-level members of Input and Output storage classes 2012 if (type.getQualifier().storage == glslang::EvqVaryingIn || type.getQualifier().storage == glslang::EvqVaryingOut) { 2013 if (type.getBasicType() == glslang::EbtBlock) { 2014 addMemberDecoration(spvType, member, TranslateInterpolationDecoration(memberQualifier)); 2015 addMemberDecoration(spvType, member, TranslateAuxiliaryStorageDecoration(memberQualifier)); 2016 } 2017 } 2018 addMemberDecoration(spvType, member, TranslateInvariantDecoration(memberQualifier)); 2019 2020 if (qualifier.storage == glslang::EvqBuffer) { 2021 std::vector<spv::Decoration> memory; 2022 TranslateMemoryDecoration(memberQualifier, memory); 2023 for (unsigned int i = 0; i < memory.size(); ++i) 2024 addMemberDecoration(spvType, member, memory[i]); 2025 } 2026 2027 // Compute location decoration; tricky based on whether inheritance is at play and 2028 // what kind of container we have, etc. 2029 // TODO: This algorithm (and it's cousin above doing almost the same thing) should 2030 // probably move to the linker stage of the front end proper, and just have the 2031 // answer sitting already distributed throughout the individual member locations. 2032 int location = -1; // will only decorate if present or inherited 2033 // Ignore member locations if the container is an array, as that's 2034 // ill-specified and decisions have been made to not allow this anyway. 2035 // The object itself must have a location, and that comes out from decorating the object, 2036 // not the type (this code decorates types). 2037 if (! type.isArray()) { 2038 if (memberQualifier.hasLocation()) { // no inheritance, or override of inheritance 2039 // struct members should not have explicit locations 2040 assert(type.getBasicType() != glslang::EbtStruct); 2041 location = memberQualifier.layoutLocation; 2042 } else if (type.getBasicType() != glslang::EbtBlock) { 2043 // If it is a not a Block, (...) Its members are assigned consecutive locations (...) 2044 // The members, and their nested types, must not themselves have Location decorations. 2045 } else if (qualifier.hasLocation()) // inheritance 2046 location = qualifier.layoutLocation + locationOffset; 2047 } 2048 if (location >= 0) 2049 builder.addMemberDecoration(spvType, member, spv::DecorationLocation, location); 2050 2051 if (qualifier.hasLocation()) // track for upcoming inheritance 2052 locationOffset += glslangIntermediate->computeTypeLocationSize(glslangMember); 2053 2054 // component, XFB, others 2055 if (glslangMember.getQualifier().hasComponent()) 2056 builder.addMemberDecoration(spvType, member, spv::DecorationComponent, glslangMember.getQualifier().layoutComponent); 2057 if (glslangMember.getQualifier().hasXfbOffset()) 2058 builder.addMemberDecoration(spvType, member, spv::DecorationOffset, glslangMember.getQualifier().layoutXfbOffset); 2059 else if (explicitLayout != glslang::ElpNone) { 2060 // figure out what to do with offset, which is accumulating 2061 int nextOffset; 2062 updateMemberOffset(type, glslangMember, offset, nextOffset, explicitLayout, memberQualifier.layoutMatrix); 2063 if (offset >= 0) 2064 builder.addMemberDecoration(spvType, member, spv::DecorationOffset, offset); 2065 offset = nextOffset; 2066 } 2067 2068 if (glslangMember.isMatrix() && explicitLayout != glslang::ElpNone) 2069 builder.addMemberDecoration(spvType, member, spv::DecorationMatrixStride, getMatrixStride(glslangMember, explicitLayout, memberQualifier.layoutMatrix)); 2070 2071 // built-in variable decorations 2072 spv::BuiltIn builtIn = TranslateBuiltInDecoration(glslangMember.getQualifier().builtIn, true); 2073 if (builtIn != spv::BuiltInMax) 2074 addMemberDecoration(spvType, member, spv::DecorationBuiltIn, (int)builtIn); 2075 } 2076 } 2077 2078 // Decorate the structure 2079 addDecoration(spvType, TranslateLayoutDecoration(type, qualifier.layoutMatrix)); 2080 addDecoration(spvType, TranslateBlockDecoration(type)); 2081 if (type.getQualifier().hasStream() && glslangIntermediate->isMultiStream()) { 2082 builder.addCapability(spv::CapabilityGeometryStreams); 2083 builder.addDecoration(spvType, spv::DecorationStream, type.getQualifier().layoutStream); 2084 } 2085 if (glslangIntermediate->getXfbMode()) { 2086 builder.addCapability(spv::CapabilityTransformFeedback); 2087 if (type.getQualifier().hasXfbStride()) 2088 builder.addDecoration(spvType, spv::DecorationXfbStride, type.getQualifier().layoutXfbStride); 2089 if (type.getQualifier().hasXfbBuffer()) 2090 builder.addDecoration(spvType, spv::DecorationXfbBuffer, type.getQualifier().layoutXfbBuffer); 2091 } 2092} 2093 2094// Turn the expression forming the array size into an id. 2095// This is not quite trivial, because of specialization constants. 2096// Sometimes, a raw constant is turned into an Id, and sometimes 2097// a specialization constant expression is. 2098spv::Id TGlslangToSpvTraverser::makeArraySizeId(const glslang::TArraySizes& arraySizes, int dim) 2099{ 2100 // First, see if this is sized with a node, meaning a specialization constant: 2101 glslang::TIntermTyped* specNode = arraySizes.getDimNode(dim); 2102 if (specNode != nullptr) { 2103 builder.clearAccessChain(); 2104 specNode->traverse(this); 2105 return accessChainLoad(specNode->getAsTyped()->getType()); 2106 } 2107 2108 // Otherwise, need a compile-time (front end) size, get it: 2109 int size = arraySizes.getDimSize(dim); 2110 assert(size > 0); 2111 return builder.makeUintConstant(size); 2112} 2113 2114// Wrap the builder's accessChainLoad to: 2115// - localize handling of RelaxedPrecision 2116// - use the SPIR-V inferred type instead of another conversion of the glslang type 2117// (avoids unnecessary work and possible type punning for structures) 2118// - do conversion of concrete to abstract type 2119spv::Id TGlslangToSpvTraverser::accessChainLoad(const glslang::TType& type) 2120{ 2121 spv::Id nominalTypeId = builder.accessChainGetInferredType(); 2122 spv::Id loadedId = builder.accessChainLoad(TranslatePrecisionDecoration(type), nominalTypeId); 2123 2124 // Need to convert to abstract types when necessary 2125 if (type.getBasicType() == glslang::EbtBool) { 2126 if (builder.isScalarType(nominalTypeId)) { 2127 // Conversion for bool 2128 spv::Id boolType = builder.makeBoolType(); 2129 if (nominalTypeId != boolType) 2130 loadedId = builder.createBinOp(spv::OpINotEqual, boolType, loadedId, builder.makeUintConstant(0)); 2131 } else if (builder.isVectorType(nominalTypeId)) { 2132 // Conversion for bvec 2133 int vecSize = builder.getNumTypeComponents(nominalTypeId); 2134 spv::Id bvecType = builder.makeVectorType(builder.makeBoolType(), vecSize); 2135 if (nominalTypeId != bvecType) 2136 loadedId = builder.createBinOp(spv::OpINotEqual, bvecType, loadedId, makeSmearedConstant(builder.makeUintConstant(0), vecSize)); 2137 } 2138 } 2139 2140 return loadedId; 2141} 2142 2143// Wrap the builder's accessChainStore to: 2144// - do conversion of concrete to abstract type 2145void TGlslangToSpvTraverser::accessChainStore(const glslang::TType& type, spv::Id rvalue) 2146{ 2147 // Need to convert to abstract types when necessary 2148 if (type.getBasicType() == glslang::EbtBool) { 2149 spv::Id nominalTypeId = builder.accessChainGetInferredType(); 2150 2151 if (builder.isScalarType(nominalTypeId)) { 2152 // Conversion for bool 2153 spv::Id boolType = builder.makeBoolType(); 2154 if (nominalTypeId != boolType) { 2155 spv::Id zero = builder.makeUintConstant(0); 2156 spv::Id one = builder.makeUintConstant(1); 2157 rvalue = builder.createTriOp(spv::OpSelect, nominalTypeId, rvalue, one, zero); 2158 } 2159 } else if (builder.isVectorType(nominalTypeId)) { 2160 // Conversion for bvec 2161 int vecSize = builder.getNumTypeComponents(nominalTypeId); 2162 spv::Id bvecType = builder.makeVectorType(builder.makeBoolType(), vecSize); 2163 if (nominalTypeId != bvecType) { 2164 spv::Id zero = makeSmearedConstant(builder.makeUintConstant(0), vecSize); 2165 spv::Id one = makeSmearedConstant(builder.makeUintConstant(1), vecSize); 2166 rvalue = builder.createTriOp(spv::OpSelect, nominalTypeId, rvalue, one, zero); 2167 } 2168 } 2169 } 2170 2171 builder.accessChainStore(rvalue); 2172} 2173 2174// Decide whether or not this type should be 2175// decorated with offsets and strides, and if so 2176// whether std140 or std430 rules should be applied. 2177glslang::TLayoutPacking TGlslangToSpvTraverser::getExplicitLayout(const glslang::TType& type) const 2178{ 2179 // has to be a block 2180 if (type.getBasicType() != glslang::EbtBlock) 2181 return glslang::ElpNone; 2182 2183 // has to be a uniform or buffer block 2184 if (type.getQualifier().storage != glslang::EvqUniform && 2185 type.getQualifier().storage != glslang::EvqBuffer) 2186 return glslang::ElpNone; 2187 2188 // return the layout to use 2189 switch (type.getQualifier().layoutPacking) { 2190 case glslang::ElpStd140: 2191 case glslang::ElpStd430: 2192 return type.getQualifier().layoutPacking; 2193 default: 2194 return glslang::ElpNone; 2195 } 2196} 2197 2198// Given an array type, returns the integer stride required for that array 2199int TGlslangToSpvTraverser::getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout) 2200{ 2201 int size; 2202 int stride; 2203 glslangIntermediate->getBaseAlignment(arrayType, size, stride, explicitLayout == glslang::ElpStd140, matrixLayout == glslang::ElmRowMajor); 2204 2205 return stride; 2206} 2207 2208// Given a matrix type, or array (of array) of matrixes type, returns the integer stride required for that matrix 2209// when used as a member of an interface block 2210int TGlslangToSpvTraverser::getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout) 2211{ 2212 glslang::TType elementType; 2213 elementType.shallowCopy(matrixType); 2214 elementType.clearArraySizes(); 2215 2216 int size; 2217 int stride; 2218 glslangIntermediate->getBaseAlignment(elementType, size, stride, explicitLayout == glslang::ElpStd140, matrixLayout == glslang::ElmRowMajor); 2219 2220 return stride; 2221} 2222 2223// Given a member type of a struct, realign the current offset for it, and compute 2224// the next (not yet aligned) offset for the next member, which will get aligned 2225// on the next call. 2226// 'currentOffset' should be passed in already initialized, ready to modify, and reflecting 2227// the migration of data from nextOffset -> currentOffset. It should be -1 on the first call. 2228// -1 means a non-forced member offset (no decoration needed). 2229void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& /*structType*/, const glslang::TType& memberType, int& currentOffset, int& nextOffset, 2230 glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout) 2231{ 2232 // this will get a positive value when deemed necessary 2233 nextOffset = -1; 2234 2235 // override anything in currentOffset with user-set offset 2236 if (memberType.getQualifier().hasOffset()) 2237 currentOffset = memberType.getQualifier().layoutOffset; 2238 2239 // It could be that current linker usage in glslang updated all the layoutOffset, 2240 // in which case the following code does not matter. But, that's not quite right 2241 // once cross-compilation unit GLSL validation is done, as the original user 2242 // settings are needed in layoutOffset, and then the following will come into play. 2243 2244 if (explicitLayout == glslang::ElpNone) { 2245 if (! memberType.getQualifier().hasOffset()) 2246 currentOffset = -1; 2247 2248 return; 2249 } 2250 2251 // Getting this far means we need explicit offsets 2252 if (currentOffset < 0) 2253 currentOffset = 0; 2254 2255 // Now, currentOffset is valid (either 0, or from a previous nextOffset), 2256 // but possibly not yet correctly aligned. 2257 2258 int memberSize; 2259 int dummyStride; 2260 int memberAlignment = glslangIntermediate->getBaseAlignment(memberType, memberSize, dummyStride, explicitLayout == glslang::ElpStd140, matrixLayout == glslang::ElmRowMajor); 2261 glslang::RoundToPow2(currentOffset, memberAlignment); 2262 nextOffset = currentOffset + memberSize; 2263} 2264 2265void TGlslangToSpvTraverser::declareUseOfStructMember(const glslang::TTypeList& members, int glslangMember) 2266{ 2267 const glslang::TBuiltInVariable glslangBuiltIn = members[glslangMember].type->getQualifier().builtIn; 2268 switch (glslangBuiltIn) 2269 { 2270 case glslang::EbvClipDistance: 2271 case glslang::EbvCullDistance: 2272 case glslang::EbvPointSize: 2273 // Generate the associated capability. Delegate to TranslateBuiltInDecoration. 2274 // Alternately, we could just call this for any glslang built-in, since the 2275 // capability already guards against duplicates. 2276 TranslateBuiltInDecoration(glslangBuiltIn, false); 2277 break; 2278 default: 2279 // Capabilities were already generated when the struct was declared. 2280 break; 2281 } 2282} 2283 2284bool TGlslangToSpvTraverser::isShaderEntrypoint(const glslang::TIntermAggregate* node) 2285{ 2286 // have to ignore mangling and just look at the base name 2287 size_t firstOpen = node->getName().find('('); 2288 return node->getName().compare(0, firstOpen, glslangIntermediate->getEntryPoint().c_str()) == 0; 2289} 2290 2291// Make all the functions, skeletally, without actually visiting their bodies. 2292void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslFunctions) 2293{ 2294 for (int f = 0; f < (int)glslFunctions.size(); ++f) { 2295 glslang::TIntermAggregate* glslFunction = glslFunctions[f]->getAsAggregate(); 2296 if (! glslFunction || glslFunction->getOp() != glslang::EOpFunction || isShaderEntrypoint(glslFunction)) 2297 continue; 2298 2299 // We're on a user function. Set up the basic interface for the function now, 2300 // so that it's available to call. 2301 // Translating the body will happen later. 2302 // 2303 // Typically (except for a "const in" parameter), an address will be passed to the 2304 // function. What it is an address of varies: 2305 // 2306 // - "in" parameters not marked as "const" can be written to without modifying the argument, 2307 // so that write needs to be to a copy, hence the address of a copy works. 2308 // 2309 // - "const in" parameters can just be the r-value, as no writes need occur. 2310 // 2311 // - "out" and "inout" arguments can't be done as direct pointers, because GLSL has 2312 // copy-in/copy-out semantics. They can be handled though with a pointer to a copy. 2313 2314 std::vector<spv::Id> paramTypes; 2315 std::vector<spv::Decoration> paramPrecisions; 2316 glslang::TIntermSequence& parameters = glslFunction->getSequence()[0]->getAsAggregate()->getSequence(); 2317 2318 for (int p = 0; p < (int)parameters.size(); ++p) { 2319 const glslang::TType& paramType = parameters[p]->getAsTyped()->getType(); 2320 spv::Id typeId = convertGlslangToSpvType(paramType); 2321 if (paramType.isOpaque()) 2322 typeId = builder.makePointer(TranslateStorageClass(paramType), typeId); 2323 else if (paramType.getQualifier().storage != glslang::EvqConstReadOnly) 2324 typeId = builder.makePointer(spv::StorageClassFunction, typeId); 2325 else 2326 constReadOnlyParameters.insert(parameters[p]->getAsSymbolNode()->getId()); 2327 paramPrecisions.push_back(TranslatePrecisionDecoration(paramType)); 2328 paramTypes.push_back(typeId); 2329 } 2330 2331 spv::Block* functionBlock; 2332 spv::Function *function = builder.makeFunctionEntry(TranslatePrecisionDecoration(glslFunction->getType()), 2333 convertGlslangToSpvType(glslFunction->getType()), 2334 glslFunction->getName().c_str(), paramTypes, paramPrecisions, &functionBlock); 2335 2336 // Track function to emit/call later 2337 functionMap[glslFunction->getName().c_str()] = function; 2338 2339 // Set the parameter id's 2340 for (int p = 0; p < (int)parameters.size(); ++p) { 2341 symbolValues[parameters[p]->getAsSymbolNode()->getId()] = function->getParamId(p); 2342 // give a name too 2343 builder.addName(function->getParamId(p), parameters[p]->getAsSymbolNode()->getName().c_str()); 2344 } 2345 } 2346} 2347 2348// Process all the initializers, while skipping the functions and link objects 2349void TGlslangToSpvTraverser::makeGlobalInitializers(const glslang::TIntermSequence& initializers) 2350{ 2351 builder.setBuildPoint(shaderEntry->getLastBlock()); 2352 for (int i = 0; i < (int)initializers.size(); ++i) { 2353 glslang::TIntermAggregate* initializer = initializers[i]->getAsAggregate(); 2354 if (initializer && initializer->getOp() != glslang::EOpFunction && initializer->getOp() != glslang::EOpLinkerObjects) { 2355 2356 // We're on a top-level node that's not a function. Treat as an initializer, whose 2357 // code goes into the beginning of main. 2358 initializer->traverse(this); 2359 } 2360 } 2361} 2362 2363// Process all the functions, while skipping initializers. 2364void TGlslangToSpvTraverser::visitFunctions(const glslang::TIntermSequence& glslFunctions) 2365{ 2366 for (int f = 0; f < (int)glslFunctions.size(); ++f) { 2367 glslang::TIntermAggregate* node = glslFunctions[f]->getAsAggregate(); 2368 if (node && (node->getOp() == glslang::EOpFunction || node->getOp() == glslang ::EOpLinkerObjects)) 2369 node->traverse(this); 2370 } 2371} 2372 2373void TGlslangToSpvTraverser::handleFunctionEntry(const glslang::TIntermAggregate* node) 2374{ 2375 // SPIR-V functions should already be in the functionMap from the prepass 2376 // that called makeFunctions(). 2377 spv::Function* function = functionMap[node->getName().c_str()]; 2378 spv::Block* functionBlock = function->getEntryBlock(); 2379 builder.setBuildPoint(functionBlock); 2380} 2381 2382void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& node, std::vector<spv::Id>& arguments) 2383{ 2384 const glslang::TIntermSequence& glslangArguments = node.getSequence(); 2385 2386 glslang::TSampler sampler = {}; 2387 bool cubeCompare = false; 2388 if (node.isTexture() || node.isImage()) { 2389 sampler = glslangArguments[0]->getAsTyped()->getType().getSampler(); 2390 cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow; 2391 } 2392 2393 for (int i = 0; i < (int)glslangArguments.size(); ++i) { 2394 builder.clearAccessChain(); 2395 glslangArguments[i]->traverse(this); 2396 2397 // Special case l-value operands 2398 bool lvalue = false; 2399 switch (node.getOp()) { 2400 case glslang::EOpImageAtomicAdd: 2401 case glslang::EOpImageAtomicMin: 2402 case glslang::EOpImageAtomicMax: 2403 case glslang::EOpImageAtomicAnd: 2404 case glslang::EOpImageAtomicOr: 2405 case glslang::EOpImageAtomicXor: 2406 case glslang::EOpImageAtomicExchange: 2407 case glslang::EOpImageAtomicCompSwap: 2408 if (i == 0) 2409 lvalue = true; 2410 break; 2411 case glslang::EOpSparseImageLoad: 2412 if ((sampler.ms && i == 3) || (! sampler.ms && i == 2)) 2413 lvalue = true; 2414 break; 2415 case glslang::EOpSparseTexture: 2416 if ((cubeCompare && i == 3) || (! cubeCompare && i == 2)) 2417 lvalue = true; 2418 break; 2419 case glslang::EOpSparseTextureClamp: 2420 if ((cubeCompare && i == 4) || (! cubeCompare && i == 3)) 2421 lvalue = true; 2422 break; 2423 case glslang::EOpSparseTextureLod: 2424 case glslang::EOpSparseTextureOffset: 2425 if (i == 3) 2426 lvalue = true; 2427 break; 2428 case glslang::EOpSparseTextureFetch: 2429 if ((sampler.dim != glslang::EsdRect && i == 3) || (sampler.dim == glslang::EsdRect && i == 2)) 2430 lvalue = true; 2431 break; 2432 case glslang::EOpSparseTextureFetchOffset: 2433 if ((sampler.dim != glslang::EsdRect && i == 4) || (sampler.dim == glslang::EsdRect && i == 3)) 2434 lvalue = true; 2435 break; 2436 case glslang::EOpSparseTextureLodOffset: 2437 case glslang::EOpSparseTextureGrad: 2438 case glslang::EOpSparseTextureOffsetClamp: 2439 if (i == 4) 2440 lvalue = true; 2441 break; 2442 case glslang::EOpSparseTextureGradOffset: 2443 case glslang::EOpSparseTextureGradClamp: 2444 if (i == 5) 2445 lvalue = true; 2446 break; 2447 case glslang::EOpSparseTextureGradOffsetClamp: 2448 if (i == 6) 2449 lvalue = true; 2450 break; 2451 case glslang::EOpSparseTextureGather: 2452 if ((sampler.shadow && i == 3) || (! sampler.shadow && i == 2)) 2453 lvalue = true; 2454 break; 2455 case glslang::EOpSparseTextureGatherOffset: 2456 case glslang::EOpSparseTextureGatherOffsets: 2457 if ((sampler.shadow && i == 4) || (! sampler.shadow && i == 3)) 2458 lvalue = true; 2459 break; 2460 default: 2461 break; 2462 } 2463 2464 if (lvalue) 2465 arguments.push_back(builder.accessChainGetLValue()); 2466 else 2467 arguments.push_back(accessChainLoad(glslangArguments[i]->getAsTyped()->getType())); 2468 } 2469} 2470 2471void TGlslangToSpvTraverser::translateArguments(glslang::TIntermUnary& node, std::vector<spv::Id>& arguments) 2472{ 2473 builder.clearAccessChain(); 2474 node.getOperand()->traverse(this); 2475 arguments.push_back(accessChainLoad(node.getOperand()->getType())); 2476} 2477 2478spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermOperator* node) 2479{ 2480 if (! node->isImage() && ! node->isTexture()) { 2481 return spv::NoResult; 2482 } 2483 2484 // Process a GLSL texturing op (will be SPV image) 2485 const glslang::TSampler sampler = node->getAsAggregate() ? node->getAsAggregate()->getSequence()[0]->getAsTyped()->getType().getSampler() 2486 : node->getAsUnaryNode()->getOperand()->getAsTyped()->getType().getSampler(); 2487 std::vector<spv::Id> arguments; 2488 if (node->getAsAggregate()) 2489 translateArguments(*node->getAsAggregate(), arguments); 2490 else 2491 translateArguments(*node->getAsUnaryNode(), arguments); 2492 spv::Decoration precision = TranslatePrecisionDecoration(node->getType()); 2493 2494 spv::Builder::TextureParameters params = { }; 2495 params.sampler = arguments[0]; 2496 2497 glslang::TCrackedTextureOp cracked; 2498 node->crackTexture(sampler, cracked); 2499 2500 // Check for queries 2501 if (cracked.query) { 2502 // a sampled image needs to have the image extracted first 2503 if (builder.isSampledImage(params.sampler)) 2504 params.sampler = builder.createUnaryOp(spv::OpImage, builder.getImageType(params.sampler), params.sampler); 2505 switch (node->getOp()) { 2506 case glslang::EOpImageQuerySize: 2507 case glslang::EOpTextureQuerySize: 2508 if (arguments.size() > 1) { 2509 params.lod = arguments[1]; 2510 return builder.createTextureQueryCall(spv::OpImageQuerySizeLod, params); 2511 } else 2512 return builder.createTextureQueryCall(spv::OpImageQuerySize, params); 2513 case glslang::EOpImageQuerySamples: 2514 case glslang::EOpTextureQuerySamples: 2515 return builder.createTextureQueryCall(spv::OpImageQuerySamples, params); 2516 case glslang::EOpTextureQueryLod: 2517 params.coords = arguments[1]; 2518 return builder.createTextureQueryCall(spv::OpImageQueryLod, params); 2519 case glslang::EOpTextureQueryLevels: 2520 return builder.createTextureQueryCall(spv::OpImageQueryLevels, params); 2521 case glslang::EOpSparseTexelsResident: 2522 return builder.createUnaryOp(spv::OpImageSparseTexelsResident, builder.makeBoolType(), arguments[0]); 2523 default: 2524 assert(0); 2525 break; 2526 } 2527 } 2528 2529 // Check for image functions other than queries 2530 if (node->isImage()) { 2531 std::vector<spv::Id> operands; 2532 auto opIt = arguments.begin(); 2533 operands.push_back(*(opIt++)); 2534 2535 // Handle subpass operations 2536 // TODO: GLSL should change to have the "MS" only on the type rather than the 2537 // built-in function. 2538 if (cracked.subpass) { 2539 // add on the (0,0) coordinate 2540 spv::Id zero = builder.makeIntConstant(0); 2541 std::vector<spv::Id> comps; 2542 comps.push_back(zero); 2543 comps.push_back(zero); 2544 operands.push_back(builder.makeCompositeConstant(builder.makeVectorType(builder.makeIntType(32), 2), comps)); 2545 if (sampler.ms) { 2546 operands.push_back(spv::ImageOperandsSampleMask); 2547 operands.push_back(*(opIt++)); 2548 } 2549 return builder.createOp(spv::OpImageRead, convertGlslangToSpvType(node->getType()), operands); 2550 } 2551 2552 operands.push_back(*(opIt++)); 2553 if (node->getOp() == glslang::EOpImageLoad) { 2554 if (sampler.ms) { 2555 operands.push_back(spv::ImageOperandsSampleMask); 2556 operands.push_back(*opIt); 2557 } 2558 if (builder.getImageTypeFormat(builder.getImageType(operands.front())) == spv::ImageFormatUnknown) 2559 builder.addCapability(spv::CapabilityStorageImageReadWithoutFormat); 2560 return builder.createOp(spv::OpImageRead, convertGlslangToSpvType(node->getType()), operands); 2561 } else if (node->getOp() == glslang::EOpImageStore) { 2562 if (sampler.ms) { 2563 operands.push_back(*(opIt + 1)); 2564 operands.push_back(spv::ImageOperandsSampleMask); 2565 operands.push_back(*opIt); 2566 } else 2567 operands.push_back(*opIt); 2568 builder.createNoResultOp(spv::OpImageWrite, operands); 2569 if (builder.getImageTypeFormat(builder.getImageType(operands.front())) == spv::ImageFormatUnknown) 2570 builder.addCapability(spv::CapabilityStorageImageWriteWithoutFormat); 2571 return spv::NoResult; 2572 } else if (node->getOp() == glslang::EOpSparseImageLoad) { 2573 builder.addCapability(spv::CapabilitySparseResidency); 2574 if (builder.getImageTypeFormat(builder.getImageType(operands.front())) == spv::ImageFormatUnknown) 2575 builder.addCapability(spv::CapabilityStorageImageReadWithoutFormat); 2576 2577 if (sampler.ms) { 2578 operands.push_back(spv::ImageOperandsSampleMask); 2579 operands.push_back(*opIt++); 2580 } 2581 2582 // Create the return type that was a special structure 2583 spv::Id texelOut = *opIt; 2584 spv::Id typeId0 = convertGlslangToSpvType(node->getType()); 2585 spv::Id typeId1 = builder.getDerefTypeId(texelOut); 2586 spv::Id resultTypeId = builder.makeStructResultType(typeId0, typeId1); 2587 2588 spv::Id resultId = builder.createOp(spv::OpImageSparseRead, resultTypeId, operands); 2589 2590 // Decode the return type 2591 builder.createStore(builder.createCompositeExtract(resultId, typeId1, 1), texelOut); 2592 return builder.createCompositeExtract(resultId, typeId0, 0); 2593 } else { 2594 // Process image atomic operations 2595 2596 // GLSL "IMAGE_PARAMS" will involve in constructing an image texel pointer and this pointer, 2597 // as the first source operand, is required by SPIR-V atomic operations. 2598 operands.push_back(sampler.ms ? *(opIt++) : builder.makeUintConstant(0)); // For non-MS, the value should be 0 2599 2600 spv::Id resultTypeId = builder.makePointer(spv::StorageClassImage, convertGlslangToSpvType(node->getType())); 2601 spv::Id pointer = builder.createOp(spv::OpImageTexelPointer, resultTypeId, operands); 2602 2603 std::vector<spv::Id> operands; 2604 operands.push_back(pointer); 2605 for (; opIt != arguments.end(); ++opIt) 2606 operands.push_back(*opIt); 2607 2608 return createAtomicOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands, node->getBasicType()); 2609 } 2610 } 2611 2612 // Check for texture functions other than queries 2613 bool sparse = node->isSparseTexture(); 2614 bool cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow; 2615 2616 // check for bias argument 2617 bool bias = false; 2618 if (! cracked.lod && ! cracked.gather && ! cracked.grad && ! cracked.fetch && ! cubeCompare) { 2619 int nonBiasArgCount = 2; 2620 if (cracked.offset) 2621 ++nonBiasArgCount; 2622 if (cracked.grad) 2623 nonBiasArgCount += 2; 2624 if (cracked.lodClamp) 2625 ++nonBiasArgCount; 2626 if (sparse) 2627 ++nonBiasArgCount; 2628 2629 if ((int)arguments.size() > nonBiasArgCount) 2630 bias = true; 2631 } 2632 2633 // See if the sampler param should really be just the SPV image part 2634 if (cracked.fetch) { 2635 // a fetch needs to have the image extracted first 2636 if (builder.isSampledImage(params.sampler)) 2637 params.sampler = builder.createUnaryOp(spv::OpImage, builder.getImageType(params.sampler), params.sampler); 2638 } 2639 2640 // set the rest of the arguments 2641 2642 params.coords = arguments[1]; 2643 int extraArgs = 0; 2644 bool noImplicitLod = false; 2645 2646 // sort out where Dref is coming from 2647 if (cubeCompare) { 2648 params.Dref = arguments[2]; 2649 ++extraArgs; 2650 } else if (sampler.shadow && cracked.gather) { 2651 params.Dref = arguments[2]; 2652 ++extraArgs; 2653 } else if (sampler.shadow) { 2654 std::vector<spv::Id> indexes; 2655 int dRefComp; 2656 if (cracked.proj) 2657 dRefComp = 2; // "The resulting 3rd component of P in the shadow forms is used as Dref" 2658 else 2659 dRefComp = builder.getNumComponents(params.coords) - 1; 2660 indexes.push_back(dRefComp); 2661 params.Dref = builder.createCompositeExtract(params.coords, builder.getScalarTypeId(builder.getTypeId(params.coords)), indexes); 2662 } 2663 2664 // lod 2665 if (cracked.lod) { 2666 params.lod = arguments[2]; 2667 ++extraArgs; 2668 } else if (glslangIntermediate->getStage() != EShLangFragment) { 2669 // we need to invent the default lod for an explicit lod instruction for a non-fragment stage 2670 noImplicitLod = true; 2671 } 2672 2673 // multisample 2674 if (sampler.ms) { 2675 params.sample = arguments[2]; // For MS, "sample" should be specified 2676 ++extraArgs; 2677 } 2678 2679 // gradient 2680 if (cracked.grad) { 2681 params.gradX = arguments[2 + extraArgs]; 2682 params.gradY = arguments[3 + extraArgs]; 2683 extraArgs += 2; 2684 } 2685 2686 // offset and offsets 2687 if (cracked.offset) { 2688 params.offset = arguments[2 + extraArgs]; 2689 ++extraArgs; 2690 } else if (cracked.offsets) { 2691 params.offsets = arguments[2 + extraArgs]; 2692 ++extraArgs; 2693 } 2694 2695 // lod clamp 2696 if (cracked.lodClamp) { 2697 params.lodClamp = arguments[2 + extraArgs]; 2698 ++extraArgs; 2699 } 2700 2701 // sparse 2702 if (sparse) { 2703 params.texelOut = arguments[2 + extraArgs]; 2704 ++extraArgs; 2705 } 2706 2707 // bias 2708 if (bias) { 2709 params.bias = arguments[2 + extraArgs]; 2710 ++extraArgs; 2711 } 2712 2713 // gather component 2714 if (cracked.gather && ! sampler.shadow) { 2715 // default component is 0, if missing, otherwise an argument 2716 if (2 + extraArgs < (int)arguments.size()) { 2717 params.component = arguments[2 + extraArgs]; 2718 ++extraArgs; 2719 } else { 2720 params.component = builder.makeIntConstant(0); 2721 } 2722 } 2723 2724 // projective component (might not to move) 2725 // GLSL: "The texture coordinates consumed from P, not including the last component of P, 2726 // are divided by the last component of P." 2727 // SPIR-V: "... (u [, v] [, w], q)... It may be a vector larger than needed, but all 2728 // unused components will appear after all used components." 2729 if (cracked.proj) { 2730 int projSourceComp = builder.getNumComponents(params.coords) - 1; 2731 int projTargetComp; 2732 switch (sampler.dim) { 2733 case glslang::Esd1D: projTargetComp = 1; break; 2734 case glslang::Esd2D: projTargetComp = 2; break; 2735 case glslang::EsdRect: projTargetComp = 2; break; 2736 default: projTargetComp = projSourceComp; break; 2737 } 2738 // copy the projective coordinate if we have to 2739 if (projTargetComp != projSourceComp) { 2740 spv::Id projComp = builder.createCompositeExtract(params.coords, 2741 builder.getScalarTypeId(builder.getTypeId(params.coords)), 2742 projSourceComp); 2743 params.coords = builder.createCompositeInsert(projComp, params.coords, 2744 builder.getTypeId(params.coords), projTargetComp); 2745 } 2746 } 2747 2748 return builder.createTextureCall(precision, convertGlslangToSpvType(node->getType()), sparse, cracked.fetch, cracked.proj, cracked.gather, noImplicitLod, params); 2749} 2750 2751spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAggregate* node) 2752{ 2753 // Grab the function's pointer from the previously created function 2754 spv::Function* function = functionMap[node->getName().c_str()]; 2755 if (! function) 2756 return 0; 2757 2758 const glslang::TIntermSequence& glslangArgs = node->getSequence(); 2759 const glslang::TQualifierList& qualifiers = node->getQualifierList(); 2760 2761 // See comments in makeFunctions() for details about the semantics for parameter passing. 2762 // 2763 // These imply we need a four step process: 2764 // 1. Evaluate the arguments 2765 // 2. Allocate and make copies of in, out, and inout arguments 2766 // 3. Make the call 2767 // 4. Copy back the results 2768 2769 // 1. Evaluate the arguments 2770 std::vector<spv::Builder::AccessChain> lValues; 2771 std::vector<spv::Id> rValues; 2772 std::vector<const glslang::TType*> argTypes; 2773 for (int a = 0; a < (int)glslangArgs.size(); ++a) { 2774 const glslang::TType& paramType = glslangArgs[a]->getAsTyped()->getType(); 2775 // build l-value 2776 builder.clearAccessChain(); 2777 glslangArgs[a]->traverse(this); 2778 argTypes.push_back(¶mType); 2779 // keep outputs as and opaque objects l-values, evaluate input-only as r-values 2780 if (qualifiers[a] != glslang::EvqConstReadOnly || paramType.isOpaque()) { 2781 // save l-value 2782 lValues.push_back(builder.getAccessChain()); 2783 } else { 2784 // process r-value 2785 rValues.push_back(accessChainLoad(*argTypes.back())); 2786 } 2787 } 2788 2789 // 2. Allocate space for anything needing a copy, and if it's "in" or "inout" 2790 // copy the original into that space. 2791 // 2792 // Also, build up the list of actual arguments to pass in for the call 2793 int lValueCount = 0; 2794 int rValueCount = 0; 2795 std::vector<spv::Id> spvArgs; 2796 for (int a = 0; a < (int)glslangArgs.size(); ++a) { 2797 const glslang::TType& paramType = glslangArgs[a]->getAsTyped()->getType(); 2798 spv::Id arg; 2799 if (paramType.isOpaque()) { 2800 builder.setAccessChain(lValues[lValueCount]); 2801 arg = builder.accessChainGetLValue(); 2802 ++lValueCount; 2803 } else if (qualifiers[a] != glslang::EvqConstReadOnly) { 2804 // need space to hold the copy 2805 arg = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(paramType), "param"); 2806 if (qualifiers[a] == glslang::EvqIn || qualifiers[a] == glslang::EvqInOut) { 2807 // need to copy the input into output space 2808 builder.setAccessChain(lValues[lValueCount]); 2809 spv::Id copy = accessChainLoad(*argTypes[a]); 2810 builder.createStore(copy, arg); 2811 } 2812 ++lValueCount; 2813 } else { 2814 arg = rValues[rValueCount]; 2815 ++rValueCount; 2816 } 2817 spvArgs.push_back(arg); 2818 } 2819 2820 // 3. Make the call. 2821 spv::Id result = builder.createFunctionCall(function, spvArgs); 2822 builder.setPrecision(result, TranslatePrecisionDecoration(node->getType())); 2823 2824 // 4. Copy back out an "out" arguments. 2825 lValueCount = 0; 2826 for (int a = 0; a < (int)glslangArgs.size(); ++a) { 2827 if (qualifiers[a] != glslang::EvqConstReadOnly) { 2828 if (qualifiers[a] == glslang::EvqOut || qualifiers[a] == glslang::EvqInOut) { 2829 spv::Id copy = builder.createLoad(spvArgs[a]); 2830 builder.setAccessChain(lValues[lValueCount]); 2831 accessChainStore(glslangArgs[a]->getAsTyped()->getType(), copy); 2832 } 2833 ++lValueCount; 2834 } 2835 } 2836 2837 return result; 2838} 2839 2840// Translate AST operation to SPV operation, already having SPV-based operands/types. 2841spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv::Decoration precision, 2842 spv::Decoration noContraction, 2843 spv::Id typeId, spv::Id left, spv::Id right, 2844 glslang::TBasicType typeProxy, bool reduceComparison) 2845{ 2846 bool isUnsigned = typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64; 2847 bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble; 2848 bool isBool = typeProxy == glslang::EbtBool; 2849 2850 spv::Op binOp = spv::OpNop; 2851 bool needMatchingVectors = true; // for non-matrix ops, would a scalar need to smear to match a vector? 2852 bool comparison = false; 2853 2854 switch (op) { 2855 case glslang::EOpAdd: 2856 case glslang::EOpAddAssign: 2857 if (isFloat) 2858 binOp = spv::OpFAdd; 2859 else 2860 binOp = spv::OpIAdd; 2861 break; 2862 case glslang::EOpSub: 2863 case glslang::EOpSubAssign: 2864 if (isFloat) 2865 binOp = spv::OpFSub; 2866 else 2867 binOp = spv::OpISub; 2868 break; 2869 case glslang::EOpMul: 2870 case glslang::EOpMulAssign: 2871 if (isFloat) 2872 binOp = spv::OpFMul; 2873 else 2874 binOp = spv::OpIMul; 2875 break; 2876 case glslang::EOpVectorTimesScalar: 2877 case glslang::EOpVectorTimesScalarAssign: 2878 if (isFloat && (builder.isVector(left) || builder.isVector(right))) { 2879 if (builder.isVector(right)) 2880 std::swap(left, right); 2881 assert(builder.isScalar(right)); 2882 needMatchingVectors = false; 2883 binOp = spv::OpVectorTimesScalar; 2884 } else 2885 binOp = spv::OpIMul; 2886 break; 2887 case glslang::EOpVectorTimesMatrix: 2888 case glslang::EOpVectorTimesMatrixAssign: 2889 binOp = spv::OpVectorTimesMatrix; 2890 break; 2891 case glslang::EOpMatrixTimesVector: 2892 binOp = spv::OpMatrixTimesVector; 2893 break; 2894 case glslang::EOpMatrixTimesScalar: 2895 case glslang::EOpMatrixTimesScalarAssign: 2896 binOp = spv::OpMatrixTimesScalar; 2897 break; 2898 case glslang::EOpMatrixTimesMatrix: 2899 case glslang::EOpMatrixTimesMatrixAssign: 2900 binOp = spv::OpMatrixTimesMatrix; 2901 break; 2902 case glslang::EOpOuterProduct: 2903 binOp = spv::OpOuterProduct; 2904 needMatchingVectors = false; 2905 break; 2906 2907 case glslang::EOpDiv: 2908 case glslang::EOpDivAssign: 2909 if (isFloat) 2910 binOp = spv::OpFDiv; 2911 else if (isUnsigned) 2912 binOp = spv::OpUDiv; 2913 else 2914 binOp = spv::OpSDiv; 2915 break; 2916 case glslang::EOpMod: 2917 case glslang::EOpModAssign: 2918 if (isFloat) 2919 binOp = spv::OpFMod; 2920 else if (isUnsigned) 2921 binOp = spv::OpUMod; 2922 else 2923 binOp = spv::OpSMod; 2924 break; 2925 case glslang::EOpRightShift: 2926 case glslang::EOpRightShiftAssign: 2927 if (isUnsigned) 2928 binOp = spv::OpShiftRightLogical; 2929 else 2930 binOp = spv::OpShiftRightArithmetic; 2931 break; 2932 case glslang::EOpLeftShift: 2933 case glslang::EOpLeftShiftAssign: 2934 binOp = spv::OpShiftLeftLogical; 2935 break; 2936 case glslang::EOpAnd: 2937 case glslang::EOpAndAssign: 2938 binOp = spv::OpBitwiseAnd; 2939 break; 2940 case glslang::EOpLogicalAnd: 2941 needMatchingVectors = false; 2942 binOp = spv::OpLogicalAnd; 2943 break; 2944 case glslang::EOpInclusiveOr: 2945 case glslang::EOpInclusiveOrAssign: 2946 binOp = spv::OpBitwiseOr; 2947 break; 2948 case glslang::EOpLogicalOr: 2949 needMatchingVectors = false; 2950 binOp = spv::OpLogicalOr; 2951 break; 2952 case glslang::EOpExclusiveOr: 2953 case glslang::EOpExclusiveOrAssign: 2954 binOp = spv::OpBitwiseXor; 2955 break; 2956 case glslang::EOpLogicalXor: 2957 needMatchingVectors = false; 2958 binOp = spv::OpLogicalNotEqual; 2959 break; 2960 2961 case glslang::EOpLessThan: 2962 case glslang::EOpGreaterThan: 2963 case glslang::EOpLessThanEqual: 2964 case glslang::EOpGreaterThanEqual: 2965 case glslang::EOpEqual: 2966 case glslang::EOpNotEqual: 2967 case glslang::EOpVectorEqual: 2968 case glslang::EOpVectorNotEqual: 2969 comparison = true; 2970 break; 2971 default: 2972 break; 2973 } 2974 2975 // handle mapped binary operations (should be non-comparison) 2976 if (binOp != spv::OpNop) { 2977 assert(comparison == false); 2978 if (builder.isMatrix(left) || builder.isMatrix(right)) 2979 return createBinaryMatrixOperation(binOp, precision, noContraction, typeId, left, right); 2980 2981 // No matrix involved; make both operands be the same number of components, if needed 2982 if (needMatchingVectors) 2983 builder.promoteScalar(precision, left, right); 2984 2985 spv::Id result = builder.createBinOp(binOp, typeId, left, right); 2986 addDecoration(result, noContraction); 2987 return builder.setPrecision(result, precision); 2988 } 2989 2990 if (! comparison) 2991 return 0; 2992 2993 // Handle comparison instructions 2994 2995 if (reduceComparison && (builder.isVector(left) || builder.isMatrix(left) || builder.isAggregate(left))) { 2996 assert(op == glslang::EOpEqual || op == glslang::EOpNotEqual); 2997 2998 return builder.createCompositeCompare(precision, left, right, op == glslang::EOpEqual); 2999 } 3000 3001 switch (op) { 3002 case glslang::EOpLessThan: 3003 if (isFloat) 3004 binOp = spv::OpFOrdLessThan; 3005 else if (isUnsigned) 3006 binOp = spv::OpULessThan; 3007 else 3008 binOp = spv::OpSLessThan; 3009 break; 3010 case glslang::EOpGreaterThan: 3011 if (isFloat) 3012 binOp = spv::OpFOrdGreaterThan; 3013 else if (isUnsigned) 3014 binOp = spv::OpUGreaterThan; 3015 else 3016 binOp = spv::OpSGreaterThan; 3017 break; 3018 case glslang::EOpLessThanEqual: 3019 if (isFloat) 3020 binOp = spv::OpFOrdLessThanEqual; 3021 else if (isUnsigned) 3022 binOp = spv::OpULessThanEqual; 3023 else 3024 binOp = spv::OpSLessThanEqual; 3025 break; 3026 case glslang::EOpGreaterThanEqual: 3027 if (isFloat) 3028 binOp = spv::OpFOrdGreaterThanEqual; 3029 else if (isUnsigned) 3030 binOp = spv::OpUGreaterThanEqual; 3031 else 3032 binOp = spv::OpSGreaterThanEqual; 3033 break; 3034 case glslang::EOpEqual: 3035 case glslang::EOpVectorEqual: 3036 if (isFloat) 3037 binOp = spv::OpFOrdEqual; 3038 else if (isBool) 3039 binOp = spv::OpLogicalEqual; 3040 else 3041 binOp = spv::OpIEqual; 3042 break; 3043 case glslang::EOpNotEqual: 3044 case glslang::EOpVectorNotEqual: 3045 if (isFloat) 3046 binOp = spv::OpFOrdNotEqual; 3047 else if (isBool) 3048 binOp = spv::OpLogicalNotEqual; 3049 else 3050 binOp = spv::OpINotEqual; 3051 break; 3052 default: 3053 break; 3054 } 3055 3056 if (binOp != spv::OpNop) { 3057 spv::Id result = builder.createBinOp(binOp, typeId, left, right); 3058 addDecoration(result, noContraction); 3059 return builder.setPrecision(result, precision); 3060 } 3061 3062 return 0; 3063} 3064 3065// 3066// Translate AST matrix operation to SPV operation, already having SPV-based operands/types. 3067// These can be any of: 3068// 3069// matrix * scalar 3070// scalar * matrix 3071// matrix * matrix linear algebraic 3072// matrix * vector 3073// vector * matrix 3074// matrix * matrix componentwise 3075// matrix op matrix op in {+, -, /} 3076// matrix op scalar op in {+, -, /} 3077// scalar op matrix op in {+, -, /} 3078// 3079spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id left, spv::Id right) 3080{ 3081 bool firstClass = true; 3082 3083 // First, handle first-class matrix operations (* and matrix/scalar) 3084 switch (op) { 3085 case spv::OpFDiv: 3086 if (builder.isMatrix(left) && builder.isScalar(right)) { 3087 // turn matrix / scalar into a multiply... 3088 right = builder.createBinOp(spv::OpFDiv, builder.getTypeId(right), builder.makeFloatConstant(1.0F), right); 3089 op = spv::OpMatrixTimesScalar; 3090 } else 3091 firstClass = false; 3092 break; 3093 case spv::OpMatrixTimesScalar: 3094 if (builder.isMatrix(right)) 3095 std::swap(left, right); 3096 assert(builder.isScalar(right)); 3097 break; 3098 case spv::OpVectorTimesMatrix: 3099 assert(builder.isVector(left)); 3100 assert(builder.isMatrix(right)); 3101 break; 3102 case spv::OpMatrixTimesVector: 3103 assert(builder.isMatrix(left)); 3104 assert(builder.isVector(right)); 3105 break; 3106 case spv::OpMatrixTimesMatrix: 3107 assert(builder.isMatrix(left)); 3108 assert(builder.isMatrix(right)); 3109 break; 3110 default: 3111 firstClass = false; 3112 break; 3113 } 3114 3115 if (firstClass) { 3116 spv::Id result = builder.createBinOp(op, typeId, left, right); 3117 addDecoration(result, noContraction); 3118 return builder.setPrecision(result, precision); 3119 } 3120 3121 // Handle component-wise +, -, *, %, and / for all combinations of type. 3122 // The result type of all of them is the same type as the (a) matrix operand. 3123 // The algorithm is to: 3124 // - break the matrix(es) into vectors 3125 // - smear any scalar to a vector 3126 // - do vector operations 3127 // - make a matrix out the vector results 3128 switch (op) { 3129 case spv::OpFAdd: 3130 case spv::OpFSub: 3131 case spv::OpFDiv: 3132 case spv::OpFMod: 3133 case spv::OpFMul: 3134 { 3135 // one time set up... 3136 bool leftMat = builder.isMatrix(left); 3137 bool rightMat = builder.isMatrix(right); 3138 unsigned int numCols = leftMat ? builder.getNumColumns(left) : builder.getNumColumns(right); 3139 int numRows = leftMat ? builder.getNumRows(left) : builder.getNumRows(right); 3140 spv::Id scalarType = builder.getScalarTypeId(typeId); 3141 spv::Id vecType = builder.makeVectorType(scalarType, numRows); 3142 std::vector<spv::Id> results; 3143 spv::Id smearVec = spv::NoResult; 3144 if (builder.isScalar(left)) 3145 smearVec = builder.smearScalar(precision, left, vecType); 3146 else if (builder.isScalar(right)) 3147 smearVec = builder.smearScalar(precision, right, vecType); 3148 3149 // do each vector op 3150 for (unsigned int c = 0; c < numCols; ++c) { 3151 std::vector<unsigned int> indexes; 3152 indexes.push_back(c); 3153 spv::Id leftVec = leftMat ? builder.createCompositeExtract( left, vecType, indexes) : smearVec; 3154 spv::Id rightVec = rightMat ? builder.createCompositeExtract(right, vecType, indexes) : smearVec; 3155 spv::Id result = builder.createBinOp(op, vecType, leftVec, rightVec); 3156 addDecoration(result, noContraction); 3157 results.push_back(builder.setPrecision(result, precision)); 3158 } 3159 3160 // put the pieces together 3161 return builder.setPrecision(builder.createCompositeConstruct(typeId, results), precision); 3162 } 3163 default: 3164 assert(0); 3165 return spv::NoResult; 3166 } 3167} 3168 3169spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id operand, glslang::TBasicType typeProxy) 3170{ 3171 spv::Op unaryOp = spv::OpNop; 3172 int libCall = -1; 3173 bool isUnsigned = typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64; 3174 bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble; 3175 3176 switch (op) { 3177 case glslang::EOpNegative: 3178 if (isFloat) { 3179 unaryOp = spv::OpFNegate; 3180 if (builder.isMatrixType(typeId)) 3181 return createUnaryMatrixOperation(unaryOp, precision, noContraction, typeId, operand, typeProxy); 3182 } else 3183 unaryOp = spv::OpSNegate; 3184 break; 3185 3186 case glslang::EOpLogicalNot: 3187 case glslang::EOpVectorLogicalNot: 3188 unaryOp = spv::OpLogicalNot; 3189 break; 3190 case glslang::EOpBitwiseNot: 3191 unaryOp = spv::OpNot; 3192 break; 3193 3194 case glslang::EOpDeterminant: 3195 libCall = spv::GLSLstd450Determinant; 3196 break; 3197 case glslang::EOpMatrixInverse: 3198 libCall = spv::GLSLstd450MatrixInverse; 3199 break; 3200 case glslang::EOpTranspose: 3201 unaryOp = spv::OpTranspose; 3202 break; 3203 3204 case glslang::EOpRadians: 3205 libCall = spv::GLSLstd450Radians; 3206 break; 3207 case glslang::EOpDegrees: 3208 libCall = spv::GLSLstd450Degrees; 3209 break; 3210 case glslang::EOpSin: 3211 libCall = spv::GLSLstd450Sin; 3212 break; 3213 case glslang::EOpCos: 3214 libCall = spv::GLSLstd450Cos; 3215 break; 3216 case glslang::EOpTan: 3217 libCall = spv::GLSLstd450Tan; 3218 break; 3219 case glslang::EOpAcos: 3220 libCall = spv::GLSLstd450Acos; 3221 break; 3222 case glslang::EOpAsin: 3223 libCall = spv::GLSLstd450Asin; 3224 break; 3225 case glslang::EOpAtan: 3226 libCall = spv::GLSLstd450Atan; 3227 break; 3228 3229 case glslang::EOpAcosh: 3230 libCall = spv::GLSLstd450Acosh; 3231 break; 3232 case glslang::EOpAsinh: 3233 libCall = spv::GLSLstd450Asinh; 3234 break; 3235 case glslang::EOpAtanh: 3236 libCall = spv::GLSLstd450Atanh; 3237 break; 3238 case glslang::EOpTanh: 3239 libCall = spv::GLSLstd450Tanh; 3240 break; 3241 case glslang::EOpCosh: 3242 libCall = spv::GLSLstd450Cosh; 3243 break; 3244 case glslang::EOpSinh: 3245 libCall = spv::GLSLstd450Sinh; 3246 break; 3247 3248 case glslang::EOpLength: 3249 libCall = spv::GLSLstd450Length; 3250 break; 3251 case glslang::EOpNormalize: 3252 libCall = spv::GLSLstd450Normalize; 3253 break; 3254 3255 case glslang::EOpExp: 3256 libCall = spv::GLSLstd450Exp; 3257 break; 3258 case glslang::EOpLog: 3259 libCall = spv::GLSLstd450Log; 3260 break; 3261 case glslang::EOpExp2: 3262 libCall = spv::GLSLstd450Exp2; 3263 break; 3264 case glslang::EOpLog2: 3265 libCall = spv::GLSLstd450Log2; 3266 break; 3267 case glslang::EOpSqrt: 3268 libCall = spv::GLSLstd450Sqrt; 3269 break; 3270 case glslang::EOpInverseSqrt: 3271 libCall = spv::GLSLstd450InverseSqrt; 3272 break; 3273 3274 case glslang::EOpFloor: 3275 libCall = spv::GLSLstd450Floor; 3276 break; 3277 case glslang::EOpTrunc: 3278 libCall = spv::GLSLstd450Trunc; 3279 break; 3280 case glslang::EOpRound: 3281 libCall = spv::GLSLstd450Round; 3282 break; 3283 case glslang::EOpRoundEven: 3284 libCall = spv::GLSLstd450RoundEven; 3285 break; 3286 case glslang::EOpCeil: 3287 libCall = spv::GLSLstd450Ceil; 3288 break; 3289 case glslang::EOpFract: 3290 libCall = spv::GLSLstd450Fract; 3291 break; 3292 3293 case glslang::EOpIsNan: 3294 unaryOp = spv::OpIsNan; 3295 break; 3296 case glslang::EOpIsInf: 3297 unaryOp = spv::OpIsInf; 3298 break; 3299 case glslang::EOpIsFinite: 3300 unaryOp = spv::OpIsFinite; 3301 break; 3302 3303 case glslang::EOpFloatBitsToInt: 3304 case glslang::EOpFloatBitsToUint: 3305 case glslang::EOpIntBitsToFloat: 3306 case glslang::EOpUintBitsToFloat: 3307 case glslang::EOpDoubleBitsToInt64: 3308 case glslang::EOpDoubleBitsToUint64: 3309 case glslang::EOpInt64BitsToDouble: 3310 case glslang::EOpUint64BitsToDouble: 3311 unaryOp = spv::OpBitcast; 3312 break; 3313 3314 case glslang::EOpPackSnorm2x16: 3315 libCall = spv::GLSLstd450PackSnorm2x16; 3316 break; 3317 case glslang::EOpUnpackSnorm2x16: 3318 libCall = spv::GLSLstd450UnpackSnorm2x16; 3319 break; 3320 case glslang::EOpPackUnorm2x16: 3321 libCall = spv::GLSLstd450PackUnorm2x16; 3322 break; 3323 case glslang::EOpUnpackUnorm2x16: 3324 libCall = spv::GLSLstd450UnpackUnorm2x16; 3325 break; 3326 case glslang::EOpPackHalf2x16: 3327 libCall = spv::GLSLstd450PackHalf2x16; 3328 break; 3329 case glslang::EOpUnpackHalf2x16: 3330 libCall = spv::GLSLstd450UnpackHalf2x16; 3331 break; 3332 case glslang::EOpPackSnorm4x8: 3333 libCall = spv::GLSLstd450PackSnorm4x8; 3334 break; 3335 case glslang::EOpUnpackSnorm4x8: 3336 libCall = spv::GLSLstd450UnpackSnorm4x8; 3337 break; 3338 case glslang::EOpPackUnorm4x8: 3339 libCall = spv::GLSLstd450PackUnorm4x8; 3340 break; 3341 case glslang::EOpUnpackUnorm4x8: 3342 libCall = spv::GLSLstd450UnpackUnorm4x8; 3343 break; 3344 case glslang::EOpPackDouble2x32: 3345 libCall = spv::GLSLstd450PackDouble2x32; 3346 break; 3347 case glslang::EOpUnpackDouble2x32: 3348 libCall = spv::GLSLstd450UnpackDouble2x32; 3349 break; 3350 3351 case glslang::EOpPackInt2x32: 3352 case glslang::EOpUnpackInt2x32: 3353 case glslang::EOpPackUint2x32: 3354 case glslang::EOpUnpackUint2x32: 3355 logger->missingFunctionality("shader int64"); 3356 libCall = spv::GLSLstd450Bad; // TODO: This is a placeholder. 3357 break; 3358 3359 case glslang::EOpDPdx: 3360 unaryOp = spv::OpDPdx; 3361 break; 3362 case glslang::EOpDPdy: 3363 unaryOp = spv::OpDPdy; 3364 break; 3365 case glslang::EOpFwidth: 3366 unaryOp = spv::OpFwidth; 3367 break; 3368 case glslang::EOpDPdxFine: 3369 builder.addCapability(spv::CapabilityDerivativeControl); 3370 unaryOp = spv::OpDPdxFine; 3371 break; 3372 case glslang::EOpDPdyFine: 3373 builder.addCapability(spv::CapabilityDerivativeControl); 3374 unaryOp = spv::OpDPdyFine; 3375 break; 3376 case glslang::EOpFwidthFine: 3377 builder.addCapability(spv::CapabilityDerivativeControl); 3378 unaryOp = spv::OpFwidthFine; 3379 break; 3380 case glslang::EOpDPdxCoarse: 3381 builder.addCapability(spv::CapabilityDerivativeControl); 3382 unaryOp = spv::OpDPdxCoarse; 3383 break; 3384 case glslang::EOpDPdyCoarse: 3385 builder.addCapability(spv::CapabilityDerivativeControl); 3386 unaryOp = spv::OpDPdyCoarse; 3387 break; 3388 case glslang::EOpFwidthCoarse: 3389 builder.addCapability(spv::CapabilityDerivativeControl); 3390 unaryOp = spv::OpFwidthCoarse; 3391 break; 3392 case glslang::EOpInterpolateAtCentroid: 3393 builder.addCapability(spv::CapabilityInterpolationFunction); 3394 libCall = spv::GLSLstd450InterpolateAtCentroid; 3395 break; 3396 case glslang::EOpAny: 3397 unaryOp = spv::OpAny; 3398 break; 3399 case glslang::EOpAll: 3400 unaryOp = spv::OpAll; 3401 break; 3402 3403 case glslang::EOpAbs: 3404 if (isFloat) 3405 libCall = spv::GLSLstd450FAbs; 3406 else 3407 libCall = spv::GLSLstd450SAbs; 3408 break; 3409 case glslang::EOpSign: 3410 if (isFloat) 3411 libCall = spv::GLSLstd450FSign; 3412 else 3413 libCall = spv::GLSLstd450SSign; 3414 break; 3415 3416 case glslang::EOpAtomicCounterIncrement: 3417 case glslang::EOpAtomicCounterDecrement: 3418 case glslang::EOpAtomicCounter: 3419 { 3420 // Handle all of the atomics in one place, in createAtomicOperation() 3421 std::vector<spv::Id> operands; 3422 operands.push_back(operand); 3423 return createAtomicOperation(op, precision, typeId, operands, typeProxy); 3424 } 3425 3426 case glslang::EOpBitFieldReverse: 3427 unaryOp = spv::OpBitReverse; 3428 break; 3429 case glslang::EOpBitCount: 3430 unaryOp = spv::OpBitCount; 3431 break; 3432 case glslang::EOpFindLSB: 3433 libCall = spv::GLSLstd450FindILsb; 3434 break; 3435 case glslang::EOpFindMSB: 3436 if (isUnsigned) 3437 libCall = spv::GLSLstd450FindUMsb; 3438 else 3439 libCall = spv::GLSLstd450FindSMsb; 3440 break; 3441 3442 case glslang::EOpBallot: 3443 case glslang::EOpReadFirstInvocation: 3444 logger->missingFunctionality("shader ballot"); 3445 libCall = spv::GLSLstd450Bad; 3446 break; 3447 3448 case glslang::EOpAnyInvocation: 3449 case glslang::EOpAllInvocations: 3450 case glslang::EOpAllInvocationsEqual: 3451 return createInvocationsOperation(op, typeId, operand); 3452 3453 default: 3454 return 0; 3455 } 3456 3457 spv::Id id; 3458 if (libCall >= 0) { 3459 std::vector<spv::Id> args; 3460 args.push_back(operand); 3461 id = builder.createBuiltinCall(typeId, stdBuiltins, libCall, args); 3462 } else { 3463 id = builder.createUnaryOp(unaryOp, typeId, operand); 3464 } 3465 3466 addDecoration(id, noContraction); 3467 return builder.setPrecision(id, precision); 3468} 3469 3470// Create a unary operation on a matrix 3471spv::Id TGlslangToSpvTraverser::createUnaryMatrixOperation(spv::Op op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id operand, glslang::TBasicType /* typeProxy */) 3472{ 3473 // Handle unary operations vector by vector. 3474 // The result type is the same type as the original type. 3475 // The algorithm is to: 3476 // - break the matrix into vectors 3477 // - apply the operation to each vector 3478 // - make a matrix out the vector results 3479 3480 // get the types sorted out 3481 int numCols = builder.getNumColumns(operand); 3482 int numRows = builder.getNumRows(operand); 3483 spv::Id srcVecType = builder.makeVectorType(builder.getScalarTypeId(builder.getTypeId(operand)), numRows); 3484 spv::Id destVecType = builder.makeVectorType(builder.getScalarTypeId(typeId), numRows); 3485 std::vector<spv::Id> results; 3486 3487 // do each vector op 3488 for (int c = 0; c < numCols; ++c) { 3489 std::vector<unsigned int> indexes; 3490 indexes.push_back(c); 3491 spv::Id srcVec = builder.createCompositeExtract(operand, srcVecType, indexes); 3492 spv::Id destVec = builder.createUnaryOp(op, destVecType, srcVec); 3493 addDecoration(destVec, noContraction); 3494 results.push_back(builder.setPrecision(destVec, precision)); 3495 } 3496 3497 // put the pieces together 3498 return builder.setPrecision(builder.createCompositeConstruct(typeId, results), precision); 3499} 3500 3501spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, spv::Decoration precision, spv::Decoration noContraction, spv::Id destType, spv::Id operand, glslang::TBasicType typeProxy) 3502{ 3503 spv::Op convOp = spv::OpNop; 3504 spv::Id zero = 0; 3505 spv::Id one = 0; 3506 spv::Id type = 0; 3507 3508 int vectorSize = builder.isVectorType(destType) ? builder.getNumTypeComponents(destType) : 0; 3509 3510 switch (op) { 3511 case glslang::EOpConvIntToBool: 3512 case glslang::EOpConvUintToBool: 3513 case glslang::EOpConvInt64ToBool: 3514 case glslang::EOpConvUint64ToBool: 3515 zero = (op == glslang::EOpConvInt64ToBool || 3516 op == glslang::EOpConvUint64ToBool) ? builder.makeUint64Constant(0) : builder.makeUintConstant(0); 3517 zero = makeSmearedConstant(zero, vectorSize); 3518 return builder.createBinOp(spv::OpINotEqual, destType, operand, zero); 3519 3520 case glslang::EOpConvFloatToBool: 3521 zero = builder.makeFloatConstant(0.0F); 3522 zero = makeSmearedConstant(zero, vectorSize); 3523 return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero); 3524 3525 case glslang::EOpConvDoubleToBool: 3526 zero = builder.makeDoubleConstant(0.0); 3527 zero = makeSmearedConstant(zero, vectorSize); 3528 return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero); 3529 3530 case glslang::EOpConvBoolToFloat: 3531 convOp = spv::OpSelect; 3532 zero = builder.makeFloatConstant(0.0); 3533 one = builder.makeFloatConstant(1.0); 3534 break; 3535 case glslang::EOpConvBoolToDouble: 3536 convOp = spv::OpSelect; 3537 zero = builder.makeDoubleConstant(0.0); 3538 one = builder.makeDoubleConstant(1.0); 3539 break; 3540 case glslang::EOpConvBoolToInt: 3541 case glslang::EOpConvBoolToInt64: 3542 zero = (op == glslang::EOpConvBoolToInt64) ? builder.makeInt64Constant(0) : builder.makeIntConstant(0); 3543 one = (op == glslang::EOpConvBoolToInt64) ? builder.makeInt64Constant(1) : builder.makeIntConstant(1); 3544 convOp = spv::OpSelect; 3545 break; 3546 case glslang::EOpConvBoolToUint: 3547 case glslang::EOpConvBoolToUint64: 3548 zero = (op == glslang::EOpConvBoolToUint64) ? builder.makeUint64Constant(0) : builder.makeUintConstant(0); 3549 one = (op == glslang::EOpConvBoolToUint64) ? builder.makeUint64Constant(1) : builder.makeUintConstant(1); 3550 convOp = spv::OpSelect; 3551 break; 3552 3553 case glslang::EOpConvIntToFloat: 3554 case glslang::EOpConvIntToDouble: 3555 case glslang::EOpConvInt64ToFloat: 3556 case glslang::EOpConvInt64ToDouble: 3557 convOp = spv::OpConvertSToF; 3558 break; 3559 3560 case glslang::EOpConvUintToFloat: 3561 case glslang::EOpConvUintToDouble: 3562 case glslang::EOpConvUint64ToFloat: 3563 case glslang::EOpConvUint64ToDouble: 3564 convOp = spv::OpConvertUToF; 3565 break; 3566 3567 case glslang::EOpConvDoubleToFloat: 3568 case glslang::EOpConvFloatToDouble: 3569 convOp = spv::OpFConvert; 3570 if (builder.isMatrixType(destType)) 3571 return createUnaryMatrixOperation(convOp, precision, noContraction, destType, operand, typeProxy); 3572 break; 3573 3574 case glslang::EOpConvFloatToInt: 3575 case glslang::EOpConvDoubleToInt: 3576 case glslang::EOpConvFloatToInt64: 3577 case glslang::EOpConvDoubleToInt64: 3578 convOp = spv::OpConvertFToS; 3579 break; 3580 3581 case glslang::EOpConvUintToInt: 3582 case glslang::EOpConvIntToUint: 3583 case glslang::EOpConvUint64ToInt64: 3584 case glslang::EOpConvInt64ToUint64: 3585 if (builder.isInSpecConstCodeGenMode()) { 3586 // Build zero scalar or vector for OpIAdd. 3587 zero = (op == glslang::EOpConvUintToInt64 || 3588 op == glslang::EOpConvIntToUint64) ? builder.makeUint64Constant(0) : builder.makeUintConstant(0); 3589 zero = makeSmearedConstant(zero, vectorSize); 3590 // Use OpIAdd, instead of OpBitcast to do the conversion when 3591 // generating for OpSpecConstantOp instruction. 3592 return builder.createBinOp(spv::OpIAdd, destType, operand, zero); 3593 } 3594 // For normal run-time conversion instruction, use OpBitcast. 3595 convOp = spv::OpBitcast; 3596 break; 3597 3598 case glslang::EOpConvFloatToUint: 3599 case glslang::EOpConvDoubleToUint: 3600 case glslang::EOpConvFloatToUint64: 3601 case glslang::EOpConvDoubleToUint64: 3602 convOp = spv::OpConvertFToU; 3603 break; 3604 3605 case glslang::EOpConvIntToInt64: 3606 case glslang::EOpConvInt64ToInt: 3607 convOp = spv::OpSConvert; 3608 break; 3609 3610 case glslang::EOpConvUintToUint64: 3611 case glslang::EOpConvUint64ToUint: 3612 convOp = spv::OpUConvert; 3613 break; 3614 3615 case glslang::EOpConvIntToUint64: 3616 case glslang::EOpConvInt64ToUint: 3617 case glslang::EOpConvUint64ToInt: 3618 case glslang::EOpConvUintToInt64: 3619 // OpSConvert/OpUConvert + OpBitCast 3620 switch (op) { 3621 case glslang::EOpConvIntToUint64: 3622 convOp = spv::OpSConvert; 3623 type = builder.makeIntType(64); 3624 break; 3625 case glslang::EOpConvInt64ToUint: 3626 convOp = spv::OpSConvert; 3627 type = builder.makeIntType(32); 3628 break; 3629 case glslang::EOpConvUint64ToInt: 3630 convOp = spv::OpUConvert; 3631 type = builder.makeUintType(32); 3632 break; 3633 case glslang::EOpConvUintToInt64: 3634 convOp = spv::OpUConvert; 3635 type = builder.makeUintType(64); 3636 break; 3637 default: 3638 assert(0); 3639 break; 3640 } 3641 3642 if (vectorSize > 0) 3643 type = builder.makeVectorType(type, vectorSize); 3644 3645 operand = builder.createUnaryOp(convOp, type, operand); 3646 3647 if (builder.isInSpecConstCodeGenMode()) { 3648 // Build zero scalar or vector for OpIAdd. 3649 zero = (op == glslang::EOpConvIntToUint64 || 3650 op == glslang::EOpConvUintToInt64) ? builder.makeUint64Constant(0) : builder.makeUintConstant(0); 3651 zero = makeSmearedConstant(zero, vectorSize); 3652 // Use OpIAdd, instead of OpBitcast to do the conversion when 3653 // generating for OpSpecConstantOp instruction. 3654 return builder.createBinOp(spv::OpIAdd, destType, operand, zero); 3655 } 3656 // For normal run-time conversion instruction, use OpBitcast. 3657 convOp = spv::OpBitcast; 3658 break; 3659 default: 3660 break; 3661 } 3662 3663 spv::Id result = 0; 3664 if (convOp == spv::OpNop) 3665 return result; 3666 3667 if (convOp == spv::OpSelect) { 3668 zero = makeSmearedConstant(zero, vectorSize); 3669 one = makeSmearedConstant(one, vectorSize); 3670 result = builder.createTriOp(convOp, destType, operand, one, zero); 3671 } else 3672 result = builder.createUnaryOp(convOp, destType, operand); 3673 3674 return builder.setPrecision(result, precision); 3675} 3676 3677spv::Id TGlslangToSpvTraverser::makeSmearedConstant(spv::Id constant, int vectorSize) 3678{ 3679 if (vectorSize == 0) 3680 return constant; 3681 3682 spv::Id vectorTypeId = builder.makeVectorType(builder.getTypeId(constant), vectorSize); 3683 std::vector<spv::Id> components; 3684 for (int c = 0; c < vectorSize; ++c) 3685 components.push_back(constant); 3686 return builder.makeCompositeConstant(vectorTypeId, components); 3687} 3688 3689// For glslang ops that map to SPV atomic opCodes 3690spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv::Decoration /*precision*/, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy) 3691{ 3692 spv::Op opCode = spv::OpNop; 3693 3694 switch (op) { 3695 case glslang::EOpAtomicAdd: 3696 case glslang::EOpImageAtomicAdd: 3697 opCode = spv::OpAtomicIAdd; 3698 break; 3699 case glslang::EOpAtomicMin: 3700 case glslang::EOpImageAtomicMin: 3701 opCode = typeProxy == glslang::EbtUint ? spv::OpAtomicUMin : spv::OpAtomicSMin; 3702 break; 3703 case glslang::EOpAtomicMax: 3704 case glslang::EOpImageAtomicMax: 3705 opCode = typeProxy == glslang::EbtUint ? spv::OpAtomicUMax : spv::OpAtomicSMax; 3706 break; 3707 case glslang::EOpAtomicAnd: 3708 case glslang::EOpImageAtomicAnd: 3709 opCode = spv::OpAtomicAnd; 3710 break; 3711 case glslang::EOpAtomicOr: 3712 case glslang::EOpImageAtomicOr: 3713 opCode = spv::OpAtomicOr; 3714 break; 3715 case glslang::EOpAtomicXor: 3716 case glslang::EOpImageAtomicXor: 3717 opCode = spv::OpAtomicXor; 3718 break; 3719 case glslang::EOpAtomicExchange: 3720 case glslang::EOpImageAtomicExchange: 3721 opCode = spv::OpAtomicExchange; 3722 break; 3723 case glslang::EOpAtomicCompSwap: 3724 case glslang::EOpImageAtomicCompSwap: 3725 opCode = spv::OpAtomicCompareExchange; 3726 break; 3727 case glslang::EOpAtomicCounterIncrement: 3728 opCode = spv::OpAtomicIIncrement; 3729 break; 3730 case glslang::EOpAtomicCounterDecrement: 3731 opCode = spv::OpAtomicIDecrement; 3732 break; 3733 case glslang::EOpAtomicCounter: 3734 opCode = spv::OpAtomicLoad; 3735 break; 3736 default: 3737 assert(0); 3738 break; 3739 } 3740 3741 // Sort out the operands 3742 // - mapping from glslang -> SPV 3743 // - there are extra SPV operands with no glslang source 3744 // - compare-exchange swaps the value and comparator 3745 // - compare-exchange has an extra memory semantics 3746 std::vector<spv::Id> spvAtomicOperands; // hold the spv operands 3747 auto opIt = operands.begin(); // walk the glslang operands 3748 spvAtomicOperands.push_back(*(opIt++)); 3749 spvAtomicOperands.push_back(builder.makeUintConstant(spv::ScopeDevice)); // TBD: what is the correct scope? 3750 spvAtomicOperands.push_back(builder.makeUintConstant(spv::MemorySemanticsMaskNone)); // TBD: what are the correct memory semantics? 3751 if (opCode == spv::OpAtomicCompareExchange) { 3752 // There are 2 memory semantics for compare-exchange. And the operand order of "comparator" and "new value" in GLSL 3753 // differs from that in SPIR-V. Hence, special processing is required. 3754 spvAtomicOperands.push_back(builder.makeUintConstant(spv::MemorySemanticsMaskNone)); 3755 spvAtomicOperands.push_back(*(opIt + 1)); 3756 spvAtomicOperands.push_back(*opIt); 3757 opIt += 2; 3758 } 3759 3760 // Add the rest of the operands, skipping any that were dealt with above. 3761 for (; opIt != operands.end(); ++opIt) 3762 spvAtomicOperands.push_back(*opIt); 3763 3764 return builder.createOp(opCode, typeId, spvAtomicOperands); 3765} 3766 3767// Create group invocation operations. 3768spv::Id TGlslangToSpvTraverser::createInvocationsOperation(glslang::TOperator op, spv::Id typeId, spv::Id operand) 3769{ 3770 builder.addCapability(spv::CapabilityGroups); 3771 3772 std::vector<spv::Id> operands; 3773 operands.push_back(builder.makeUintConstant(spv::ScopeSubgroup)); 3774 operands.push_back(operand); 3775 3776 switch (op) { 3777 case glslang::EOpAnyInvocation: 3778 case glslang::EOpAllInvocations: 3779 return builder.createOp(op == glslang::EOpAnyInvocation ? spv::OpGroupAny : spv::OpGroupAll, typeId, operands); 3780 3781 case glslang::EOpAllInvocationsEqual: 3782 { 3783 spv::Id groupAll = builder.createOp(spv::OpGroupAll, typeId, operands); 3784 spv::Id groupAny = builder.createOp(spv::OpGroupAny, typeId, operands); 3785 3786 return builder.createBinOp(spv::OpLogicalOr, typeId, groupAll, 3787 builder.createUnaryOp(spv::OpLogicalNot, typeId, groupAny)); 3788 } 3789 default: 3790 logger->missingFunctionality("invocation operation"); 3791 return spv::NoResult; 3792 } 3793} 3794 3795spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy) 3796{ 3797 bool isUnsigned = typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64; 3798 bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble; 3799 3800 spv::Op opCode = spv::OpNop; 3801 int libCall = -1; 3802 size_t consumedOperands = operands.size(); 3803 spv::Id typeId0 = 0; 3804 if (consumedOperands > 0) 3805 typeId0 = builder.getTypeId(operands[0]); 3806 spv::Id frexpIntType = 0; 3807 3808 switch (op) { 3809 case glslang::EOpMin: 3810 if (isFloat) 3811 libCall = spv::GLSLstd450FMin; 3812 else if (isUnsigned) 3813 libCall = spv::GLSLstd450UMin; 3814 else 3815 libCall = spv::GLSLstd450SMin; 3816 builder.promoteScalar(precision, operands.front(), operands.back()); 3817 break; 3818 case glslang::EOpModf: 3819 libCall = spv::GLSLstd450Modf; 3820 break; 3821 case glslang::EOpMax: 3822 if (isFloat) 3823 libCall = spv::GLSLstd450FMax; 3824 else if (isUnsigned) 3825 libCall = spv::GLSLstd450UMax; 3826 else 3827 libCall = spv::GLSLstd450SMax; 3828 builder.promoteScalar(precision, operands.front(), operands.back()); 3829 break; 3830 case glslang::EOpPow: 3831 libCall = spv::GLSLstd450Pow; 3832 break; 3833 case glslang::EOpDot: 3834 opCode = spv::OpDot; 3835 break; 3836 case glslang::EOpAtan: 3837 libCall = spv::GLSLstd450Atan2; 3838 break; 3839 3840 case glslang::EOpClamp: 3841 if (isFloat) 3842 libCall = spv::GLSLstd450FClamp; 3843 else if (isUnsigned) 3844 libCall = spv::GLSLstd450UClamp; 3845 else 3846 libCall = spv::GLSLstd450SClamp; 3847 builder.promoteScalar(precision, operands.front(), operands[1]); 3848 builder.promoteScalar(precision, operands.front(), operands[2]); 3849 break; 3850 case glslang::EOpMix: 3851 if (! builder.isBoolType(builder.getScalarTypeId(builder.getTypeId(operands.back())))) { 3852 assert(isFloat); 3853 libCall = spv::GLSLstd450FMix; 3854 } else { 3855 opCode = spv::OpSelect; 3856 std::swap(operands.front(), operands.back()); 3857 } 3858 builder.promoteScalar(precision, operands.front(), operands.back()); 3859 break; 3860 case glslang::EOpStep: 3861 libCall = spv::GLSLstd450Step; 3862 builder.promoteScalar(precision, operands.front(), operands.back()); 3863 break; 3864 case glslang::EOpSmoothStep: 3865 libCall = spv::GLSLstd450SmoothStep; 3866 builder.promoteScalar(precision, operands[0], operands[2]); 3867 builder.promoteScalar(precision, operands[1], operands[2]); 3868 break; 3869 3870 case glslang::EOpDistance: 3871 libCall = spv::GLSLstd450Distance; 3872 break; 3873 case glslang::EOpCross: 3874 libCall = spv::GLSLstd450Cross; 3875 break; 3876 case glslang::EOpFaceForward: 3877 libCall = spv::GLSLstd450FaceForward; 3878 break; 3879 case glslang::EOpReflect: 3880 libCall = spv::GLSLstd450Reflect; 3881 break; 3882 case glslang::EOpRefract: 3883 libCall = spv::GLSLstd450Refract; 3884 break; 3885 case glslang::EOpInterpolateAtSample: 3886 builder.addCapability(spv::CapabilityInterpolationFunction); 3887 libCall = spv::GLSLstd450InterpolateAtSample; 3888 break; 3889 case glslang::EOpInterpolateAtOffset: 3890 builder.addCapability(spv::CapabilityInterpolationFunction); 3891 libCall = spv::GLSLstd450InterpolateAtOffset; 3892 break; 3893 case glslang::EOpAddCarry: 3894 opCode = spv::OpIAddCarry; 3895 typeId = builder.makeStructResultType(typeId0, typeId0); 3896 consumedOperands = 2; 3897 break; 3898 case glslang::EOpSubBorrow: 3899 opCode = spv::OpISubBorrow; 3900 typeId = builder.makeStructResultType(typeId0, typeId0); 3901 consumedOperands = 2; 3902 break; 3903 case glslang::EOpUMulExtended: 3904 opCode = spv::OpUMulExtended; 3905 typeId = builder.makeStructResultType(typeId0, typeId0); 3906 consumedOperands = 2; 3907 break; 3908 case glslang::EOpIMulExtended: 3909 opCode = spv::OpSMulExtended; 3910 typeId = builder.makeStructResultType(typeId0, typeId0); 3911 consumedOperands = 2; 3912 break; 3913 case glslang::EOpBitfieldExtract: 3914 if (isUnsigned) 3915 opCode = spv::OpBitFieldUExtract; 3916 else 3917 opCode = spv::OpBitFieldSExtract; 3918 break; 3919 case glslang::EOpBitfieldInsert: 3920 opCode = spv::OpBitFieldInsert; 3921 break; 3922 3923 case glslang::EOpFma: 3924 libCall = spv::GLSLstd450Fma; 3925 break; 3926 case glslang::EOpFrexp: 3927 libCall = spv::GLSLstd450FrexpStruct; 3928 if (builder.getNumComponents(operands[0]) == 1) 3929 frexpIntType = builder.makeIntegerType(32, true); 3930 else 3931 frexpIntType = builder.makeVectorType(builder.makeIntegerType(32, true), builder.getNumComponents(operands[0])); 3932 typeId = builder.makeStructResultType(typeId0, frexpIntType); 3933 consumedOperands = 1; 3934 break; 3935 case glslang::EOpLdexp: 3936 libCall = spv::GLSLstd450Ldexp; 3937 break; 3938 3939 case glslang::EOpReadInvocation: 3940 logger->missingFunctionality("shader ballot"); 3941 libCall = spv::GLSLstd450Bad; 3942 break; 3943 3944 default: 3945 return 0; 3946 } 3947 3948 spv::Id id = 0; 3949 if (libCall >= 0) { 3950 // Use an extended instruction from the standard library. 3951 // Construct the call arguments, without modifying the original operands vector. 3952 // We might need the remaining arguments, e.g. in the EOpFrexp case. 3953 std::vector<spv::Id> callArguments(operands.begin(), operands.begin() + consumedOperands); 3954 id = builder.createBuiltinCall(typeId, stdBuiltins, libCall, callArguments); 3955 } else { 3956 switch (consumedOperands) { 3957 case 0: 3958 // should all be handled by visitAggregate and createNoArgOperation 3959 assert(0); 3960 return 0; 3961 case 1: 3962 // should all be handled by createUnaryOperation 3963 assert(0); 3964 return 0; 3965 case 2: 3966 id = builder.createBinOp(opCode, typeId, operands[0], operands[1]); 3967 break; 3968 default: 3969 // anything 3 or over doesn't have l-value operands, so all should be consumed 3970 assert(consumedOperands == operands.size()); 3971 id = builder.createOp(opCode, typeId, operands); 3972 break; 3973 } 3974 } 3975 3976 // Decode the return types that were structures 3977 switch (op) { 3978 case glslang::EOpAddCarry: 3979 case glslang::EOpSubBorrow: 3980 builder.createStore(builder.createCompositeExtract(id, typeId0, 1), operands[2]); 3981 id = builder.createCompositeExtract(id, typeId0, 0); 3982 break; 3983 case glslang::EOpUMulExtended: 3984 case glslang::EOpIMulExtended: 3985 builder.createStore(builder.createCompositeExtract(id, typeId0, 0), operands[3]); 3986 builder.createStore(builder.createCompositeExtract(id, typeId0, 1), operands[2]); 3987 break; 3988 case glslang::EOpFrexp: 3989 assert(operands.size() == 2); 3990 builder.createStore(builder.createCompositeExtract(id, frexpIntType, 1), operands[1]); 3991 id = builder.createCompositeExtract(id, typeId0, 0); 3992 break; 3993 default: 3994 break; 3995 } 3996 3997 return builder.setPrecision(id, precision); 3998} 3999 4000// Intrinsics with no arguments, no return value, and no precision. 4001spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op) 4002{ 4003 // TODO: get the barrier operands correct 4004 4005 switch (op) { 4006 case glslang::EOpEmitVertex: 4007 builder.createNoResultOp(spv::OpEmitVertex); 4008 return 0; 4009 case glslang::EOpEndPrimitive: 4010 builder.createNoResultOp(spv::OpEndPrimitive); 4011 return 0; 4012 case glslang::EOpBarrier: 4013 builder.createControlBarrier(spv::ScopeDevice, spv::ScopeDevice, spv::MemorySemanticsMaskNone); 4014 return 0; 4015 case glslang::EOpMemoryBarrier: 4016 builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsAllMemory); 4017 return 0; 4018 case glslang::EOpMemoryBarrierAtomicCounter: 4019 builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsAtomicCounterMemoryMask); 4020 return 0; 4021 case glslang::EOpMemoryBarrierBuffer: 4022 builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsUniformMemoryMask); 4023 return 0; 4024 case glslang::EOpMemoryBarrierImage: 4025 builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsImageMemoryMask); 4026 return 0; 4027 case glslang::EOpMemoryBarrierShared: 4028 builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsWorkgroupMemoryMask); 4029 return 0; 4030 case glslang::EOpGroupMemoryBarrier: 4031 builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsCrossWorkgroupMemoryMask); 4032 return 0; 4033 case glslang::EOpAllMemoryBarrierWithGroupSync: 4034 // Control barrier with non-"None" semantic is also a memory barrier. 4035 builder.createControlBarrier(spv::ScopeDevice, spv::ScopeDevice, spv::MemorySemanticsAllMemory); 4036 return 0; 4037 case glslang::EOpGroupMemoryBarrierWithGroupSync: 4038 // Control barrier with non-"None" semantic is also a memory barrier. 4039 builder.createControlBarrier(spv::ScopeDevice, spv::ScopeDevice, spv::MemorySemanticsCrossWorkgroupMemoryMask); 4040 return 0; 4041 case glslang::EOpWorkgroupMemoryBarrier: 4042 builder.createMemoryBarrier(spv::ScopeWorkgroup, spv::MemorySemanticsWorkgroupMemoryMask); 4043 return 0; 4044 case glslang::EOpWorkgroupMemoryBarrierWithGroupSync: 4045 // Control barrier with non-"None" semantic is also a memory barrier. 4046 builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeWorkgroup, spv::MemorySemanticsWorkgroupMemoryMask); 4047 return 0; 4048 default: 4049 logger->missingFunctionality("unknown operation with no arguments"); 4050 return 0; 4051 } 4052} 4053 4054spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol) 4055{ 4056 auto iter = symbolValues.find(symbol->getId()); 4057 spv::Id id; 4058 if (symbolValues.end() != iter) { 4059 id = iter->second; 4060 return id; 4061 } 4062 4063 // it was not found, create it 4064 id = createSpvVariable(symbol); 4065 symbolValues[symbol->getId()] = id; 4066 4067 if (symbol->getBasicType() != glslang::EbtBlock) { 4068 addDecoration(id, TranslatePrecisionDecoration(symbol->getType())); 4069 addDecoration(id, TranslateInterpolationDecoration(symbol->getType().getQualifier())); 4070 addDecoration(id, TranslateAuxiliaryStorageDecoration(symbol->getType().getQualifier())); 4071 if (symbol->getType().getQualifier().hasSpecConstantId()) 4072 addDecoration(id, spv::DecorationSpecId, symbol->getType().getQualifier().layoutSpecConstantId); 4073 if (symbol->getQualifier().hasIndex()) 4074 builder.addDecoration(id, spv::DecorationIndex, symbol->getQualifier().layoutIndex); 4075 if (symbol->getQualifier().hasComponent()) 4076 builder.addDecoration(id, spv::DecorationComponent, symbol->getQualifier().layoutComponent); 4077 if (glslangIntermediate->getXfbMode()) { 4078 builder.addCapability(spv::CapabilityTransformFeedback); 4079 if (symbol->getQualifier().hasXfbStride()) 4080 builder.addDecoration(id, spv::DecorationXfbStride, symbol->getQualifier().layoutXfbStride); 4081 if (symbol->getQualifier().hasXfbBuffer()) 4082 builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer); 4083 if (symbol->getQualifier().hasXfbOffset()) 4084 builder.addDecoration(id, spv::DecorationOffset, symbol->getQualifier().layoutXfbOffset); 4085 } 4086 // atomic counters use this: 4087 if (symbol->getQualifier().hasOffset()) 4088 builder.addDecoration(id, spv::DecorationOffset, symbol->getQualifier().layoutOffset); 4089 } 4090 4091 if (symbol->getQualifier().hasLocation()) 4092 builder.addDecoration(id, spv::DecorationLocation, symbol->getQualifier().layoutLocation); 4093 addDecoration(id, TranslateInvariantDecoration(symbol->getType().getQualifier())); 4094 if (symbol->getQualifier().hasStream() && glslangIntermediate->isMultiStream()) { 4095 builder.addCapability(spv::CapabilityGeometryStreams); 4096 builder.addDecoration(id, spv::DecorationStream, symbol->getQualifier().layoutStream); 4097 } 4098 if (symbol->getQualifier().hasSet()) 4099 builder.addDecoration(id, spv::DecorationDescriptorSet, symbol->getQualifier().layoutSet); 4100 else if (IsDescriptorResource(symbol->getType())) { 4101 // default to 0 4102 builder.addDecoration(id, spv::DecorationDescriptorSet, 0); 4103 } 4104 if (symbol->getQualifier().hasBinding()) 4105 builder.addDecoration(id, spv::DecorationBinding, symbol->getQualifier().layoutBinding); 4106 if (symbol->getQualifier().hasAttachment()) 4107 builder.addDecoration(id, spv::DecorationInputAttachmentIndex, symbol->getQualifier().layoutAttachment); 4108 if (glslangIntermediate->getXfbMode()) { 4109 builder.addCapability(spv::CapabilityTransformFeedback); 4110 if (symbol->getQualifier().hasXfbStride()) 4111 builder.addDecoration(id, spv::DecorationXfbStride, symbol->getQualifier().layoutXfbStride); 4112 if (symbol->getQualifier().hasXfbBuffer()) 4113 builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer); 4114 } 4115 4116 if (symbol->getType().isImage()) { 4117 std::vector<spv::Decoration> memory; 4118 TranslateMemoryDecoration(symbol->getType().getQualifier(), memory); 4119 for (unsigned int i = 0; i < memory.size(); ++i) 4120 addDecoration(id, memory[i]); 4121 } 4122 4123 // built-in variable decorations 4124 spv::BuiltIn builtIn = TranslateBuiltInDecoration(symbol->getQualifier().builtIn, false); 4125 if (builtIn != spv::BuiltInMax) 4126 addDecoration(id, spv::DecorationBuiltIn, (int)builtIn); 4127 4128 return id; 4129} 4130 4131// If 'dec' is valid, add no-operand decoration to an object 4132void TGlslangToSpvTraverser::addDecoration(spv::Id id, spv::Decoration dec) 4133{ 4134 if (dec != spv::DecorationMax) 4135 builder.addDecoration(id, dec); 4136} 4137 4138// If 'dec' is valid, add a one-operand decoration to an object 4139void TGlslangToSpvTraverser::addDecoration(spv::Id id, spv::Decoration dec, unsigned value) 4140{ 4141 if (dec != spv::DecorationMax) 4142 builder.addDecoration(id, dec, value); 4143} 4144 4145// If 'dec' is valid, add a no-operand decoration to a struct member 4146void TGlslangToSpvTraverser::addMemberDecoration(spv::Id id, int member, spv::Decoration dec) 4147{ 4148 if (dec != spv::DecorationMax) 4149 builder.addMemberDecoration(id, (unsigned)member, dec); 4150} 4151 4152// If 'dec' is valid, add a one-operand decoration to a struct member 4153void TGlslangToSpvTraverser::addMemberDecoration(spv::Id id, int member, spv::Decoration dec, unsigned value) 4154{ 4155 if (dec != spv::DecorationMax) 4156 builder.addMemberDecoration(id, (unsigned)member, dec, value); 4157} 4158 4159// Make a full tree of instructions to build a SPIR-V specialization constant, 4160// or regular constant if possible. 4161// 4162// TBD: this is not yet done, nor verified to be the best design, it does do the leaf symbols though 4163// 4164// Recursively walk the nodes. The nodes form a tree whose leaves are 4165// regular constants, which themselves are trees that createSpvConstant() 4166// recursively walks. So, this function walks the "top" of the tree: 4167// - emit specialization constant-building instructions for specConstant 4168// - when running into a non-spec-constant, switch to createSpvConstant() 4169spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TIntermTyped& node) 4170{ 4171 assert(node.getQualifier().isConstant()); 4172 4173 // Handle front-end constants first (non-specialization constants). 4174 if (! node.getQualifier().specConstant) { 4175 // hand off to the non-spec-constant path 4176 assert(node.getAsConstantUnion() != nullptr || node.getAsSymbolNode() != nullptr); 4177 int nextConst = 0; 4178 return createSpvConstantFromConstUnionArray(node.getType(), node.getAsConstantUnion() ? node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(), 4179 nextConst, false); 4180 } 4181 4182 // We now know we have a specialization constant to build 4183 4184 // gl_WorkGroupSize is a special case until the front-end handles hierarchical specialization constants, 4185 // even then, it's specialization ids are handled by special case syntax in GLSL: layout(local_size_x = ... 4186 if (node.getType().getQualifier().builtIn == glslang::EbvWorkGroupSize) { 4187 std::vector<spv::Id> dimConstId; 4188 for (int dim = 0; dim < 3; ++dim) { 4189 bool specConst = (glslangIntermediate->getLocalSizeSpecId(dim) != glslang::TQualifier::layoutNotSet); 4190 dimConstId.push_back(builder.makeUintConstant(glslangIntermediate->getLocalSize(dim), specConst)); 4191 if (specConst) 4192 addDecoration(dimConstId.back(), spv::DecorationSpecId, glslangIntermediate->getLocalSizeSpecId(dim)); 4193 } 4194 return builder.makeCompositeConstant(builder.makeVectorType(builder.makeUintType(32), 3), dimConstId, true); 4195 } 4196 4197 // An AST node labelled as specialization constant should be a symbol node. 4198 // Its initializer should either be a sub tree with constant nodes, or a constant union array. 4199 if (auto* sn = node.getAsSymbolNode()) { 4200 if (auto* sub_tree = sn->getConstSubtree()) { 4201 // Traverse the constant constructor sub tree like generating normal run-time instructions. 4202 // During the AST traversal, if the node is marked as 'specConstant', SpecConstantOpModeGuard 4203 // will set the builder into spec constant op instruction generating mode. 4204 sub_tree->traverse(this); 4205 return accessChainLoad(sub_tree->getType()); 4206 } else if (auto* const_union_array = &sn->getConstArray()){ 4207 int nextConst = 0; 4208 return createSpvConstantFromConstUnionArray(sn->getType(), *const_union_array, nextConst, true); 4209 } 4210 } 4211 4212 // Neither a front-end constant node, nor a specialization constant node with constant union array or 4213 // constant sub tree as initializer. 4214 logger->missingFunctionality("Neither a front-end constant nor a spec constant."); 4215 exit(1); 4216 return spv::NoResult; 4217} 4218 4219// Use 'consts' as the flattened glslang source of scalar constants to recursively 4220// build the aggregate SPIR-V constant. 4221// 4222// If there are not enough elements present in 'consts', 0 will be substituted; 4223// an empty 'consts' can be used to create a fully zeroed SPIR-V constant. 4224// 4225spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst, bool specConstant) 4226{ 4227 // vector of constants for SPIR-V 4228 std::vector<spv::Id> spvConsts; 4229 4230 // Type is used for struct and array constants 4231 spv::Id typeId = convertGlslangToSpvType(glslangType); 4232 4233 if (glslangType.isArray()) { 4234 glslang::TType elementType(glslangType, 0); 4235 for (int i = 0; i < glslangType.getOuterArraySize(); ++i) 4236 spvConsts.push_back(createSpvConstantFromConstUnionArray(elementType, consts, nextConst, false)); 4237 } else if (glslangType.isMatrix()) { 4238 glslang::TType vectorType(glslangType, 0); 4239 for (int col = 0; col < glslangType.getMatrixCols(); ++col) 4240 spvConsts.push_back(createSpvConstantFromConstUnionArray(vectorType, consts, nextConst, false)); 4241 } else if (glslangType.getStruct()) { 4242 glslang::TVector<glslang::TTypeLoc>::const_iterator iter; 4243 for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter) 4244 spvConsts.push_back(createSpvConstantFromConstUnionArray(*iter->type, consts, nextConst, false)); 4245 } else if (glslangType.getVectorSize() > 1) { 4246 for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) { 4247 bool zero = nextConst >= consts.size(); 4248 switch (glslangType.getBasicType()) { 4249 case glslang::EbtInt: 4250 spvConsts.push_back(builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst())); 4251 break; 4252 case glslang::EbtUint: 4253 spvConsts.push_back(builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst())); 4254 break; 4255 case glslang::EbtInt64: 4256 spvConsts.push_back(builder.makeInt64Constant(zero ? 0 : consts[nextConst].getI64Const())); 4257 break; 4258 case glslang::EbtUint64: 4259 spvConsts.push_back(builder.makeUint64Constant(zero ? 0 : consts[nextConst].getU64Const())); 4260 break; 4261 case glslang::EbtFloat: 4262 spvConsts.push_back(builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst())); 4263 break; 4264 case glslang::EbtDouble: 4265 spvConsts.push_back(builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst())); 4266 break; 4267 case glslang::EbtBool: 4268 spvConsts.push_back(builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst())); 4269 break; 4270 default: 4271 assert(0); 4272 break; 4273 } 4274 ++nextConst; 4275 } 4276 } else { 4277 // we have a non-aggregate (scalar) constant 4278 bool zero = nextConst >= consts.size(); 4279 spv::Id scalar = 0; 4280 switch (glslangType.getBasicType()) { 4281 case glslang::EbtInt: 4282 scalar = builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst(), specConstant); 4283 break; 4284 case glslang::EbtUint: 4285 scalar = builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst(), specConstant); 4286 break; 4287 case glslang::EbtInt64: 4288 scalar = builder.makeInt64Constant(zero ? 0 : consts[nextConst].getI64Const(), specConstant); 4289 break; 4290 case glslang::EbtUint64: 4291 scalar = builder.makeUint64Constant(zero ? 0 : consts[nextConst].getU64Const(), specConstant); 4292 break; 4293 case glslang::EbtFloat: 4294 scalar = builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst(), specConstant); 4295 break; 4296 case glslang::EbtDouble: 4297 scalar = builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst(), specConstant); 4298 break; 4299 case glslang::EbtBool: 4300 scalar = builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst(), specConstant); 4301 break; 4302 default: 4303 assert(0); 4304 break; 4305 } 4306 ++nextConst; 4307 return scalar; 4308 } 4309 4310 return builder.makeCompositeConstant(typeId, spvConsts); 4311} 4312 4313// Return true if the node is a constant or symbol whose reading has no 4314// non-trivial observable cost or effect. 4315bool TGlslangToSpvTraverser::isTrivialLeaf(const glslang::TIntermTyped* node) 4316{ 4317 // don't know what this is 4318 if (node == nullptr) 4319 return false; 4320 4321 // a constant is safe 4322 if (node->getAsConstantUnion() != nullptr) 4323 return true; 4324 4325 // not a symbol means non-trivial 4326 if (node->getAsSymbolNode() == nullptr) 4327 return false; 4328 4329 // a symbol, depends on what's being read 4330 switch (node->getType().getQualifier().storage) { 4331 case glslang::EvqTemporary: 4332 case glslang::EvqGlobal: 4333 case glslang::EvqIn: 4334 case glslang::EvqInOut: 4335 case glslang::EvqConst: 4336 case glslang::EvqConstReadOnly: 4337 case glslang::EvqUniform: 4338 return true; 4339 default: 4340 return false; 4341 } 4342} 4343 4344// A node is trivial if it is a single operation with no side effects. 4345// Error on the side of saying non-trivial. 4346// Return true if trivial. 4347bool TGlslangToSpvTraverser::isTrivial(const glslang::TIntermTyped* node) 4348{ 4349 if (node == nullptr) 4350 return false; 4351 4352 // symbols and constants are trivial 4353 if (isTrivialLeaf(node)) 4354 return true; 4355 4356 // otherwise, it needs to be a simple operation or one or two leaf nodes 4357 4358 // not a simple operation 4359 const glslang::TIntermBinary* binaryNode = node->getAsBinaryNode(); 4360 const glslang::TIntermUnary* unaryNode = node->getAsUnaryNode(); 4361 if (binaryNode == nullptr && unaryNode == nullptr) 4362 return false; 4363 4364 // not on leaf nodes 4365 if (binaryNode && (! isTrivialLeaf(binaryNode->getLeft()) || ! isTrivialLeaf(binaryNode->getRight()))) 4366 return false; 4367 4368 if (unaryNode && ! isTrivialLeaf(unaryNode->getOperand())) { 4369 return false; 4370 } 4371 4372 switch (node->getAsOperator()->getOp()) { 4373 case glslang::EOpLogicalNot: 4374 case glslang::EOpConvIntToBool: 4375 case glslang::EOpConvUintToBool: 4376 case glslang::EOpConvFloatToBool: 4377 case glslang::EOpConvDoubleToBool: 4378 case glslang::EOpEqual: 4379 case glslang::EOpNotEqual: 4380 case glslang::EOpLessThan: 4381 case glslang::EOpGreaterThan: 4382 case glslang::EOpLessThanEqual: 4383 case glslang::EOpGreaterThanEqual: 4384 case glslang::EOpIndexDirect: 4385 case glslang::EOpIndexDirectStruct: 4386 case glslang::EOpLogicalXor: 4387 case glslang::EOpAny: 4388 case glslang::EOpAll: 4389 return true; 4390 default: 4391 return false; 4392 } 4393} 4394 4395// Emit short-circuiting code, where 'right' is never evaluated unless 4396// the left side is true (for &&) or false (for ||). 4397spv::Id TGlslangToSpvTraverser::createShortCircuit(glslang::TOperator op, glslang::TIntermTyped& left, glslang::TIntermTyped& right) 4398{ 4399 spv::Id boolTypeId = builder.makeBoolType(); 4400 4401 // emit left operand 4402 builder.clearAccessChain(); 4403 left.traverse(this); 4404 spv::Id leftId = accessChainLoad(left.getType()); 4405 4406 // Operands to accumulate OpPhi operands 4407 std::vector<spv::Id> phiOperands; 4408 // accumulate left operand's phi information 4409 phiOperands.push_back(leftId); 4410 phiOperands.push_back(builder.getBuildPoint()->getId()); 4411 4412 // Make the two kinds of operation symmetric with a "!" 4413 // || => emit "if (! left) result = right" 4414 // && => emit "if ( left) result = right" 4415 // 4416 // TODO: this runtime "not" for || could be avoided by adding functionality 4417 // to 'builder' to have an "else" without an "then" 4418 if (op == glslang::EOpLogicalOr) 4419 leftId = builder.createUnaryOp(spv::OpLogicalNot, boolTypeId, leftId); 4420 4421 // make an "if" based on the left value 4422 spv::Builder::If ifBuilder(leftId, builder); 4423 4424 // emit right operand as the "then" part of the "if" 4425 builder.clearAccessChain(); 4426 right.traverse(this); 4427 spv::Id rightId = accessChainLoad(right.getType()); 4428 4429 // accumulate left operand's phi information 4430 phiOperands.push_back(rightId); 4431 phiOperands.push_back(builder.getBuildPoint()->getId()); 4432 4433 // finish the "if" 4434 ifBuilder.makeEndIf(); 4435 4436 // phi together the two results 4437 return builder.createOp(spv::OpPhi, boolTypeId, phiOperands); 4438} 4439 4440}; // end anonymous namespace 4441 4442namespace glslang { 4443 4444void GetSpirvVersion(std::string& version) 4445{ 4446 const int bufSize = 100; 4447 char buf[bufSize]; 4448 snprintf(buf, bufSize, "0x%08x, Revision %d", spv::Version, spv::Revision); 4449 version = buf; 4450} 4451 4452// Write SPIR-V out to a binary file 4453void OutputSpvBin(const std::vector<unsigned int>& spirv, const char* baseName) 4454{ 4455 std::ofstream out; 4456 out.open(baseName, std::ios::binary | std::ios::out); 4457 for (int i = 0; i < (int)spirv.size(); ++i) { 4458 unsigned int word = spirv[i]; 4459 out.write((const char*)&word, 4); 4460 } 4461 out.close(); 4462} 4463 4464// Write SPIR-V out to a text file with 32-bit hexadecimal words 4465void OutputSpvHex(const std::vector<unsigned int>& spirv, const char* baseName) 4466{ 4467 std::ofstream out; 4468 out.open(baseName, std::ios::binary | std::ios::out); 4469 out << "\t// " GLSLANG_REVISION " " GLSLANG_DATE << std::endl; 4470 const int WORDS_PER_LINE = 8; 4471 for (int i = 0; i < (int)spirv.size(); i += WORDS_PER_LINE) { 4472 out << "\t"; 4473 for (int j = 0; j < WORDS_PER_LINE && i + j < (int)spirv.size(); ++j) { 4474 const unsigned int word = spirv[i + j]; 4475 out << "0x" << std::hex << std::setw(8) << std::setfill('0') << word; 4476 if (i + j + 1 < (int)spirv.size()) { 4477 out << ","; 4478 } 4479 } 4480 out << std::endl; 4481 } 4482 out.close(); 4483} 4484 4485// 4486// Set up the glslang traversal 4487// 4488void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv) 4489{ 4490 spv::SpvBuildLogger logger; 4491 GlslangToSpv(intermediate, spirv, &logger); 4492} 4493 4494void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv, spv::SpvBuildLogger* logger) 4495{ 4496 TIntermNode* root = intermediate.getTreeRoot(); 4497 4498 if (root == 0) 4499 return; 4500 4501 glslang::GetThreadPoolAllocator().push(); 4502 4503 TGlslangToSpvTraverser it(&intermediate, logger); 4504 4505 root->traverse(&it); 4506 4507 it.dumpSpv(spirv); 4508 4509 glslang::GetThreadPoolAllocator().pop(); 4510} 4511 4512}; // end namespace glslang 4513