yum-mirror/glslang
git clone https://git.yummers.dev/yum-mirror/glslang
43c384bf
main
1// 2// Copyright (C) 2014-2016 LunarG, Inc. 3// Copyright (C) 2015-2020 Google, Inc. 4// Copyright (C) 2017, 2022-2025 Arm Limited. 5// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. 6// 7// All rights reserved. 8// 9// Redistribution and use in source and binary forms, with or without 10// modification, are permitted provided that the following conditions 11// are met: 12// 13// Redistributions of source code must retain the above copyright 14// notice, this list of conditions and the following disclaimer. 15// 16// Redistributions in binary form must reproduce the above 17// copyright notice, this list of conditions and the following 18// disclaimer in the documentation and/or other materials provided 19// with the distribution. 20// 21// Neither the name of 3Dlabs Inc. Ltd. nor the names of its 22// contributors may be used to endorse or promote products derived 23// from this software without specific prior written permission. 24// 25// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 28// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 29// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 30// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 31// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 33// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 35// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36// POSSIBILITY OF SUCH DAMAGE. 37 38// 39// Visit the nodes in the glslang intermediate tree representation to 40// translate them to SPIR-V. 41// 42 43#include "spirv.hpp11" 44#include "GlslangToSpv.h" 45#include "SpvBuilder.h" 46#include "SpvTools.h" 47#include "spvUtil.h" 48 49namespace spv { 50#include "GLSL.std.450.h" 51#include "GLSL.ext.KHR.h" 52#include "GLSL.ext.EXT.h" 53#include "GLSL.ext.AMD.h" 54#include "GLSL.ext.NV.h" 55#include "GLSL.ext.ARM.h" 56#include "GLSL.ext.QCOM.h" 57#include "NonSemanticDebugPrintf.h" 58} 59 60// Glslang includes 61#include "../glslang/MachineIndependent/localintermediate.h" 62#include "../glslang/MachineIndependent/SymbolTable.h" 63#include "../glslang/Include/Common.h" 64 65// Build-time generated includes 66#include "glslang/build_info.h" 67 68#include <fstream> 69#include <iomanip> 70#include <list> 71#include <map> 72#include <optional> 73#include <stack> 74#include <string> 75#include <vector> 76 77namespace { 78 79namespace { 80class SpecConstantOpModeGuard { 81public : 82SpecConstantOpModeGuard (spv::Builder * builder ) 83 :builder_ (builder ) { 84previous_flag_ = builder -> isInSpecConstCodeGenMode (); 85 } 86 ~SpecConstantOpModeGuard () { 87previous_flag_ ?builder_ -> setToSpecConstCodeGenMode () 88 :builder_ -> setToNormalCodeGenMode (); 89 } 90void turnOnSpecConstantOpMode () { 91builder_ -> setToSpecConstCodeGenMode (); 92 } 93 94private : 95 spv::Builder * builder_ ; 96bool previous_flag_ ; 97}; 98 99struct OpDecorations { 100public : 101OpDecorations (spv::Decoration precision , spv::Decoration noContraction , spv::Decoration nonUniform ) : 102precision (precision ) 103 , 104noContraction (noContraction ), 105nonUniform (nonUniform ) 106 { } 107 108 spv::Decoration precision ; 109 110void addNoContraction (spv::Builder & builder , spv::Id t ) {builder .addDecoration (t ,noContraction ); } 111void addNonUniform (spv::Builder & builder , spv::Id t ) {builder .addDecoration (t ,nonUniform ); } 112protected : 113 spv::Decoration noContraction ; 114 spv::Decoration nonUniform ; 115}; 116 117void addDerivativeGroupExecutionMode (spv::Builder & builder ,const glslang::TIntermediate & intermediate , 118 spv::Function * shaderEntry ) 119{ 120if (intermediate .getLayoutDerivativeModeNone ()== glslang::LayoutDerivativeGroupQuads ) { 121if (intermediate .getLayoutDerivativeExtension ()== glslang::EdgKHR ) { 122builder .addCapability (spv::Capability ::ComputeDerivativeGroupQuadsKHR ); 123builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::DerivativeGroupQuadsKHR ); 124builder .addExtension (spv::E_SPV_KHR_compute_shader_derivatives ); 125 }else { 126builder .addCapability (spv::Capability ::ComputeDerivativeGroupQuadsNV ); 127builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::DerivativeGroupQuadsNV ); 128builder .addExtension (spv::E_SPV_NV_compute_shader_derivatives ); 129 } 130 }else if (intermediate .getLayoutDerivativeModeNone ()== glslang::LayoutDerivativeGroupLinear ) { 131if (intermediate .getLayoutDerivativeExtension ()== glslang::EdgKHR ) { 132builder .addCapability (spv::Capability ::ComputeDerivativeGroupLinearKHR ); 133builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::DerivativeGroupLinearKHR ); 134builder .addExtension (spv::E_SPV_KHR_compute_shader_derivatives ); 135 }else { 136builder .addCapability (spv::Capability ::ComputeDerivativeGroupLinearNV ); 137builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::DerivativeGroupLinearNV ); 138builder .addExtension (spv::E_SPV_NV_compute_shader_derivatives ); 139 } 140 } 141} 142 143}// namespace 144 145class TGlslangToSpvTraverser ; 146 147class DescHeapLayoutEmitter { 148public : 149explicit DescHeapLayoutEmitter (TGlslangToSpvTraverser & traverser ); 150 151bool isDescriptorPayload (const glslang::TType & type )const ; 152bool containsDescriptorPayload (const glslang::TType & type )const ; 153 154 spv::Id getOrCreateValueSize (const glslang::TType & type ); 155 spv::Id getOrCreateValueAlignment (const glslang::TType & type ); 156 157// Runtime arrays return spv::NoResult for total array size. 158 spv::Id getOrCreateArraySize (const glslang::TType & arrayType ); 159 spv::Id getOrCreateArrayAlignment (const glslang::TType & arrayType ); 160 std::vector < spv::Id > getOrCreateArrayStrides (const glslang::TType & arrayType ); 161 162// Returns OffsetIdEXT operands relative to the struct start. 163 std::vector < spv::Id > getOrCreateStructMemberOffsets (const glslang::TType & structType ); 164 165private : 166// compute* does not write TType* caches; it is safe for temporary array element types. 167 spv::Id computeValueSize (const glslang::TType & type ); 168 spv::Id computeValueAlignment (const glslang::TType & type ); 169 spv::Id getOrCreateStructSize (const glslang::TType & structType ); 170 spv::Id getOrCreateStructAlignment (const glslang::TType & structType ); 171 172 spv::Id makeUint (unsigned value ); 173 spv::Id makeSpecOp (spv::Op op ,const std::vector < spv::Id >& operands ); 174 spv::Id getMemberSize (const glslang::TType & memberType ); 175 spv::Id getMemberAlignment (const glslang::TType & memberType ); 176 177void getInnermostArrayElementType (const glslang::TType & arrayType , glslang::TType & elementType )const ; 178 179TGlslangToSpvTraverser & traverser ; 180 181// TType* caches are only for stable AST/member/symbol types. 182 std::unordered_map < const glslang::TType * , spv::Id > valueSizeCache ; 183 std::unordered_map < const glslang::TType * , spv::Id > valueAlignmentCache ; 184 std::unordered_map < const glslang::TType * , spv::Id > arraySizeCache ; 185 std::unordered_map < const glslang::TType * , spv::Id > arrayAlignmentCache ; 186 std::unordered_map < const glslang::TType * , std::vector < spv::Id >> arrayStridesCache ; 187 std::unordered_map < const glslang::TTypeList * , spv::Id > structSizeCache ; 188 std::unordered_map < const glslang::TTypeList * , spv::Id > structAlignmentCache ; 189 std::unordered_map < const glslang::TTypeList * , std::vector < spv::Id >> structMemberOffsetsCache ; 190}; 191 192// 193// The main holder of information for translating glslang to SPIR-V. 194// 195// Derives from the AST walking base class. 196// 197class TGlslangToSpvTraverser :public glslang::TIntermTraverser { 198public : 199TGlslangToSpvTraverser (unsigned int spvVersion ,const glslang::TIntermediate * , spv::SpvBuildLogger * logger , 200 glslang::SpvOptions & options ); 201virtual ~TGlslangToSpvTraverser () { } 202 203bool visitAggregate (glslang::TVisit , glslang::TIntermAggregate * )override ; 204bool visitBinary (glslang::TVisit , glslang::TIntermBinary * )override ; 205void visitConstantUnion (glslang::TIntermConstantUnion * )override ; 206bool visitSelection (glslang::TVisit , glslang::TIntermSelection * )override ; 207bool visitSwitch (glslang::TVisit , glslang::TIntermSwitch * )override ; 208void visitSymbol (glslang::TIntermSymbol * symbol )override ; 209bool visitUnary (glslang::TVisit , glslang::TIntermUnary * )override ; 210bool visitLoop (glslang::TVisit , glslang::TIntermLoop * )override ; 211bool visitBranch (glslang::TVisit visit , glslang::TIntermBranch * )override ; 212bool visitVariableDecl (glslang::TVisit , glslang::TIntermVariableDecl * )override ; 213 214void finishSpv (bool compileOnly ); 215void dumpSpv (std::vector < unsigned int >& out ); 216 217protected : 218friend class DescHeapLayoutEmitter ; 219 220TGlslangToSpvTraverser (TGlslangToSpvTraverser & ); 221TGlslangToSpvTraverser & operator= (TGlslangToSpvTraverser & ); 222 223 spv::Decoration TranslateInterpolationDecoration (const glslang::TQualifier & qualifier ); 224 spv::Decoration TranslateAuxiliaryStorageDecoration (const glslang::TQualifier & qualifier ); 225 spv::Decoration TranslateNonUniformDecoration (const glslang::TQualifier & qualifier ); 226 spv::Decoration TranslateNonUniformDecoration (const spv::Builder ::AccessChain ::CoherentFlags & coherentFlags ); 227 spv::Builder ::AccessChain ::CoherentFlags TranslateCoherent (const glslang::TType & type ); 228 spv::MemoryAccessMask TranslateMemoryAccess (const spv::Builder ::AccessChain ::CoherentFlags & coherentFlags ); 229 spv::ImageOperandsMask TranslateImageOperands (const spv::Builder ::AccessChain ::CoherentFlags & coherentFlags ); 230 spv::Scope TranslateMemoryScope (const spv::Builder ::AccessChain ::CoherentFlags & coherentFlags ); 231 spv::BuiltIn TranslateBuiltInDecoration (glslang::TBuiltInVariable ,bool memberDeclaration ); 232 spv::ImageFormat TranslateImageFormat (const glslang::TType & type ); 233 spv::SelectionControlMask TranslateSelectionControl (const glslang::TIntermSelection & )const ; 234 spv::SelectionControlMask TranslateSwitchControl (const glslang::TIntermSwitch & )const ; 235 spv::LoopControlMask TranslateLoopControl (const glslang::TIntermLoop & , std::vector < unsigned int >& operands )const ; 236 spv::FunctionControlMask TranslateFunctionControl (unsigned int )const ; 237 spv::StorageClass TranslateStorageClass (const glslang::TType & ); 238void TranslateLiterals (const glslang::TVector < const glslang::TIntermConstantUnion *>& , std::vector < unsigned >& )const ; 239void addIndirectionIndexCapabilities (const glslang::TType & baseType ,const glslang::TType & indexType ); 240 spv::Id createSpvVariable (const glslang::TIntermSymbol * , spv::Id forcedType ); 241 spv::Id getSampledType (const glslang::TSampler & ); 242 spv::Id getInvertedSwizzleType (const glslang::TIntermTyped & ); 243 spv::Id createInvertedSwizzle (spv::Decoration precision ,const glslang::TIntermTyped & , spv::Id parentResult ); 244void convertSwizzle (const glslang::TIntermAggregate & , std::vector < unsigned >& swizzle ); 245 spv::Id convertGlslangToSpvType (const glslang::TType & type ,bool forwardReferenceOnly = false); 246 spv::Id convertGlslangToSpvType (const glslang::TType & type , glslang::TLayoutPacking ,const glslang::TQualifier & , 247bool lastBufferBlockMember ,bool forwardReferenceOnly = false); 248void applySpirvDecorate (const glslang::TType & type , spv::Id id , std::optional < int > member ); 249bool filterMember (const glslang::TType & member ); 250 spv::Id convertGlslangStructToSpvType (const glslang::TType & ,const glslang::TTypeList * glslangStruct , 251 glslang::TLayoutPacking ,const glslang::TQualifier & ); 252 spv::LinkageType convertGlslangLinkageToSpv (glslang::TLinkType glslangLinkType ); 253bool isDescHeapDescriptorType (const glslang::TType & type )const ; 254bool containsDescHeapDescriptorType (const glslang::TType & type )const ; 255 spv::Id makeDescHeapImageArrayWrapperType (const glslang::TIntermSymbol & symbol , spv::Id arrayType ); 256 257void decorateStructType (const glslang::TType & ,const glslang::TTypeList * glslangStruct , glslang::TLayoutPacking , 258const glslang::TQualifier & , spv::Id ,const std::vector < spv::Id >& spvMembers ); 259 spv::Id makeArraySizeId (const glslang::TArraySizes & ,int dim ,bool allowZero = false,bool boolType = false); 260 spv::Id makeHeapOffsetId (const glslang::TType & type ); 261 spv::Id accessChainLoad (const glslang::TType & type ); 262void accessChainStore (const glslang::TType & type , spv::Id rvalue ); 263void multiTypeStore (const glslang::TType & , spv::Id rValue ); 264 spv::Id convertLoadedBoolInUniformToUint (const glslang::TType & type , spv::Id nominalTypeId , spv::Id loadedId ); 265 glslang::TLayoutPacking getExplicitLayout (const glslang::TType & type )const ; 266int getArrayStride (const glslang::TType & arrayType , glslang::TLayoutPacking , glslang::TLayoutMatrix ); 267int getMatrixStride (const glslang::TType & matrixType , glslang::TLayoutPacking , glslang::TLayoutMatrix ); 268void updateMemberOffset (const glslang::TType & structType ,const glslang::TType & memberType ,int & currentOffset , 269int & nextOffset , glslang::TLayoutPacking , glslang::TLayoutMatrix ); 270void declareUseOfStructMember (const glslang::TTypeList & members ,int glslangMember ); 271 272bool isShaderEntryPoint (const glslang::TIntermAggregate * node ); 273bool writableParam (glslang::TStorageQualifier )const ; 274bool originalParam (glslang::TStorageQualifier ,const glslang::TType & ,bool implicitThisParam ); 275void makeFunctions (const glslang::TIntermSequence & ); 276void makeGlobalInitializers (const glslang::TIntermSequence & ); 277void collectRayTracingLinkerObjects (); 278void visitFunctions (const glslang::TIntermSequence & ); 279void translateArguments (const glslang::TIntermAggregate & node , std::vector < spv::Id >& arguments , 280 spv::Builder ::AccessChain ::CoherentFlags & lvalueCoherentFlags ); 281void translateArguments (glslang::TIntermUnary & node , std::vector < spv::Id >& arguments ); 282 spv::Id createImageTextureFunctionCall (glslang::TIntermOperator * node ); 283 spv::Id handleUserFunctionCall (const glslang::TIntermAggregate * ); 284 285 spv::Id createBinaryOperation (glslang::TOperator op ,OpDecorations & , spv::Id typeId , spv::Id left , spv::Id right , 286 glslang::TBasicType typeProxy ,bool reduceComparison = true); 287 spv::Id createBinaryMatrixOperation (spv::Op ,OpDecorations & , spv::Id typeId , spv::Id left , spv::Id right ); 288 spv::Id createUnaryOperation (glslang::TOperator op ,OpDecorations & , spv::Id typeId , spv::Id operand , 289 glslang::TBasicType typeProxy , 290const spv::Builder ::AccessChain ::CoherentFlags & lvalueCoherentFlags , 291const glslang::TType & opType ); 292 spv::Id createUnaryMatrixOperation (spv::Op op ,OpDecorations & , spv::Id typeId , spv::Id operand , 293 glslang::TBasicType typeProxy ); 294 spv::Id createConversion (glslang::TOperator op ,OpDecorations & , spv::Id destTypeId , spv::Id operand , 295 glslang::TBasicType resultBasicType , glslang::TBasicType operandBasicType , 296bool sameCoopMatUse = true); 297 spv::Id createCoopMatConversion (spv::Id destType , spv::Id operand , 298 glslang::TBasicType resultBasicType , glslang::TBasicType operandBasicType , 299bool sameUse ,bool transpose ); 300 301 spv::Id createIntWidthConversion (spv::Id operand ,int vectorSize , spv::Id destType , 302 glslang::TBasicType resultBasicType , glslang::TBasicType operandBasicType ); 303bool specConstUConvertNeedsWorkaround (); 304 spv::Id createSpecConstUConvert (spv::Id typeId , spv::Id operand ,int vectorSize ,int operandWidth , 305int resultWidth ); 306 spv::Id makeSmearedConstant (spv::Id constant ,int vectorSize ); 307 spv::Id createAtomicOperation (glslang::TOperator op , spv::Decoration precision , spv::Id typeId , 308 std::vector < spv::Id >& operands , glslang::TBasicType typeProxy , 309const spv::Builder ::AccessChain ::CoherentFlags & lvalueCoherentFlags , 310const glslang::TType & opType ); 311 spv::Id createInvocationsOperation (glslang::TOperator op , spv::Id typeId , std::vector < spv::Id >& operands , 312 glslang::TBasicType typeProxy ); 313 spv::Id CreateInvocationsVectorOperation (spv::Op op , spv::GroupOperation groupOperation , 314 spv::Id typeId , std::vector < spv::Id >& operands ); 315 spv::Id createSubgroupOperation (glslang::TOperator op , spv::Id typeId , std::vector < spv::Id >& operands , 316 glslang::TBasicType typeProxy ); 317 spv::Id createMiscOperation (glslang::TOperator op , spv::Decoration precision , spv::Id typeId , 318 std::vector < spv::Id >& operands , glslang::TBasicType typeProxy ); 319 spv::Id createNoArgOperation (glslang::TOperator op , spv::Decoration precision , spv::Id typeId ); 320 spv::Id getSymbolId (const glslang::TIntermSymbol * node ); 321void addMeshNVDecoration (spv::Id id ,int member ,const glslang::TQualifier & qualifier ); 322bool hasQCOMImageProceessingDecoration (spv::Id id , spv::Decoration decor ); 323void addImageProcessingQCOMDecoration (spv::Id id , spv::Decoration decor ); 324void addImageProcessing2QCOMDecoration (spv::Id id ,bool isForGather ); 325 spv::Id createSpvConstant (const glslang::TIntermTyped & ); 326 spv::Id createSpvConstantFromConstUnionArray (const glslang::TType & type ,const glslang::TConstUnionArray & , 327int & nextConst ,bool specConstant ); 328bool isTrivialLeaf (const glslang::TIntermTyped * node ); 329bool isTrivial (const glslang::TIntermTyped * node ); 330 spv::Id createShortCircuit (glslang::TOperator , glslang::TIntermTyped & left , glslang::TIntermTyped & right ); 331 spv::Id getExtBuiltins (const char * name ); 332 std::pair < spv::Id , spv::Id > getForcedType (glslang::TBuiltInVariable builtIn ,const glslang::TType & ); 333 spv::Id translateForcedType (spv::Id object ,const glslang::TType & type ); 334 spv::Id createCompositeConstruct (spv::Id typeId , std::vector < spv::Id > constituents ); 335void recordDescHeapAccessChainInfo (glslang::TIntermBinary * node ); 336void createAbortEXT (const glslang::TIntermSequence & glslangOperands ); 337void enableCoopMatConversions (); 338 339 glslang::SpvOptions & options ; 340 spv::Function * shaderEntry ; 341 spv::Function * currentFunction ; 342 spv::Instruction * entryPoint ; 343int sequenceDepth ; 344 345// GL_EXT_opacity_micromap_ray_query_mode: the spec constant emitted for gl_EnableOpacityMicromapEXT, 346// if it was materialized during traversal; spv::NoResult otherwise. finishSpv() references it (or 347// synthesizes one) for the OpacityMicromapIdKHR execution mode. 348 spv::Id opacityMicromapEnableConstId ; 349 350 spv::SpvBuildLogger * logger ; 351 352// There is a 1:1 mapping between a spv builder and a module; this is thread safe 353 spv::Builder builder ; 354bool inEntryPoint ; 355bool entryPointTerminated ; 356bool linkageOnly ;// true when visiting the set of objects in the AST present only for 357// establishing interface, whether or not they were statically used 358 std::set < spv::Id > iOSet ;// all input/output variables from either static use or declaration of interface 359const glslang::TIntermediate * glslangIntermediate ; 360bool nanMinMaxClamp ;// true if use NMin/NMax/NClamp instead of FMin/FMax/FClamp 361 spv::Id stdBuiltins ; 362 spv::Id nonSemanticDebugPrintf ; 363 std::unordered_map < std::string , spv::Id > extBuiltinMap ; 364 365 std::unordered_map < long long , spv::Id > symbolValues ; 366 std::unordered_map < uint32_t , spv::Id > builtInVariableIds ; 367 std::unordered_set < long long > rValueParameters ;// set of formal function parameters passed as rValues, 368// rather than a pointer 369 std::unordered_map < std::string , spv::Function *> functionMap ; 370 std::unordered_map < const glslang::TTypeList * , spv::Id > structMap [glslang::ElpCount ][glslang::ElmCount ]; 371// for mapping glslang block indices to spv indices (e.g., due to hidden members), 372// keyed by the block's member list so distinct block types never share a slot: 373 std::unordered_map < const glslang::TTypeList * , std::vector < int >> memberRemapper ; 374 std::stack < bool > breakForLoop ;// false means break for switch 375 std::unordered_map < std::string ,const glslang::TIntermSymbol *> counterOriginator ; 376// Map pointee types for EbtReference to their forward pointers 377 std::map < const glslang::TType * , spv::Id > forwardPointers ; 378// Type forcing, for when SPIR-V wants a different type than the AST, 379// requiring local translation to and from SPIR-V type on every access. 380// Maps <builtin-variable-id -> AST-required-type-id> 381 std::unordered_map < spv::Id , spv::Id > forceType ; 382// Used by Task shader while generating opearnds for OpEmitMeshTasksEXT 383 spv::Id taskPayloadID ; 384// Used later for generating OpTraceKHR/OpExecuteCallableKHR/OpHitObjectRecordHit*/OpHitObjectGetShaderBindingTableData 385 std::unordered_map < unsigned int , glslang::TIntermSymbol *> locationToSymbol [4 ]; 386 std::unordered_map < spv::Id , std::vector < spv::Decoration > > idToQCOMDecorations ; 387 388// Descriptor heap root types used as OpUntypedAccessChainKHR base type operands. 389 std::unordered_map < long long , spv::Id > heapDescHeapBaseType ; 390// Descriptor heap block payload types. Opaque descriptor types are already deduplicated by SpvBuilder. 391 std::unordered_map < const glslang::TTypeList * , spv::Id > heapDescHeapBlockDescriptorTypes ; 392 393DescHeapLayoutEmitter descHeapLayout ; 394 395}; 396 397// 398// Helper functions for translating glslang representations to SPIR-V enumerants. 399// 400 401// Translate glslang profile to SPIR-V source language. 402spv::SourceLanguage TranslateSourceLanguage (glslang::EShSource source ,EProfile profile ) 403{ 404switch (source ) { 405case glslang::EShSourceGlsl : 406switch (profile ) { 407case ENoProfile : 408case ECoreProfile : 409case ECompatibilityProfile : 410return spv::SourceLanguage ::GLSL ; 411case EEsProfile : 412return spv::SourceLanguage ::ESSL ; 413default : 414return spv::SourceLanguage ::Unknown ; 415 } 416case glslang::EShSourceHlsl : 417return spv::SourceLanguage ::HLSL ; 418default : 419return spv::SourceLanguage ::Unknown ; 420 } 421} 422 423// Translate glslang language (stage) to SPIR-V execution model. 424spv::ExecutionModel TranslateExecutionModel (EShLanguage stage ,bool isMeshShaderEXT = false) 425{ 426switch (stage ) { 427case EShLangVertex :return spv::ExecutionModel ::Vertex ; 428case EShLangFragment :return spv::ExecutionModel ::Fragment ; 429case EShLangCompute :return spv::ExecutionModel ::GLCompute ; 430case EShLangTessControl :return spv::ExecutionModel ::TessellationControl ; 431case EShLangTessEvaluation :return spv::ExecutionModel ::TessellationEvaluation ; 432case EShLangGeometry :return spv::ExecutionModel ::Geometry ; 433case EShLangRayGen :return spv::ExecutionModel ::RayGenerationKHR ; 434case EShLangIntersect :return spv::ExecutionModel ::IntersectionKHR ; 435case EShLangAnyHit :return spv::ExecutionModel ::AnyHitKHR ; 436case EShLangClosestHit :return spv::ExecutionModel ::ClosestHitKHR ; 437case EShLangMiss :return spv::ExecutionModel ::MissKHR ; 438case EShLangCallable :return spv::ExecutionModel ::CallableKHR ; 439case EShLangTask :return (isMeshShaderEXT )? spv::ExecutionModel ::TaskEXT : spv::ExecutionModel ::TaskNV ; 440case EShLangMesh :return (isMeshShaderEXT )? spv::ExecutionModel ::MeshEXT : spv::ExecutionModel ::MeshNV ; 441default : 442assert (0 ); 443return spv::ExecutionModel ::Fragment ; 444 } 445} 446 447// Translate glslang sampler type to SPIR-V dimensionality. 448spv::Dim TranslateDimensionality (const glslang::TSampler & sampler ) 449{ 450switch (sampler .dim ) { 451case glslang::Esd1D :return spv::Dim ::Dim1D ; 452case glslang::Esd2D :return spv::Dim ::Dim2D ; 453case glslang::Esd3D :return spv::Dim ::Dim3D ; 454case glslang::EsdCube :return spv::Dim ::Cube ; 455case glslang::EsdRect :return spv::Dim ::Rect ; 456case glslang::EsdBuffer :return spv::Dim ::Buffer ; 457case glslang::EsdSubpass :return spv::Dim ::SubpassData ; 458case glslang::EsdAttachmentEXT :return spv::Dim ::TileImageDataEXT ; 459default : 460assert (0 ); 461return spv::Dim ::Dim2D ; 462 } 463} 464 465// Translate glslang precision to SPIR-V precision decorations. 466spv::Decoration TranslatePrecisionDecoration (glslang::TPrecisionQualifier glslangPrecision ) 467{ 468switch (glslangPrecision ) { 469case glslang::EpqLow :return spv::Decoration ::RelaxedPrecision ; 470case glslang::EpqMedium :return spv::Decoration ::RelaxedPrecision ; 471default : 472return spv::NoPrecision ; 473 } 474} 475 476// Translate glslang type to SPIR-V precision decorations. 477spv::Decoration TranslatePrecisionDecoration (const glslang::TType & type ) 478{ 479return TranslatePrecisionDecoration (type .getQualifier ().precision ); 480} 481 482// Translate glslang type to SPIR-V block decorations. 483spv::Decoration TranslateBlockDecoration (const glslang::TStorageQualifier storage ,bool useStorageBuffer ) 484{ 485switch (storage ) { 486case glslang::EvqUniform :return spv::Decoration ::Block ; 487case glslang::EvqBuffer :return useStorageBuffer ? spv::Decoration ::Block : spv::Decoration ::BufferBlock ; 488case glslang::EvqVaryingIn :return spv::Decoration ::Block ; 489case glslang::EvqVaryingOut :return spv::Decoration ::Block ; 490case glslang::EvqShared :return spv::Decoration ::Block ; 491case glslang::EvqPayload :return spv::Decoration ::Block ; 492case glslang::EvqPayloadIn :return spv::Decoration ::Block ; 493case glslang::EvqHitAttr :return spv::Decoration ::Block ; 494case glslang::EvqCallableData :return spv::Decoration ::Block ; 495case glslang::EvqCallableDataIn :return spv::Decoration ::Block ; 496case glslang::EvqHitObjectAttrNV :return spv::Decoration ::Block ; 497case glslang::EvqHitObjectAttrEXT :return spv::Decoration ::Block ; 498case glslang::EvqResourceHeap :return spv::Decoration ::Block ; 499case glslang::EvqSamplerHeap :return spv::Decoration ::Block ; 500default : 501assert (0 ); 502break ; 503 } 504 505return spv::Decoration ::Max ; 506} 507 508// Translate glslang type to SPIR-V memory decorations. 509void TranslateMemoryDecoration (const glslang::TQualifier & qualifier , std::vector < spv::Decoration >& memory , 510bool useVulkanMemoryModel ) 511{ 512if (!useVulkanMemoryModel ) { 513if (qualifier .isVolatile ()) { 514memory .push_back (spv::Decoration ::Volatile ); 515memory .push_back (spv::Decoration ::Coherent ); 516 }else if (qualifier .isCoherent ()) { 517memory .push_back (spv::Decoration ::Coherent ); 518 } 519 } 520if (qualifier .isRestrict ()) 521memory .push_back (spv::Decoration ::Restrict ); 522if (qualifier .isReadOnly ()) 523memory .push_back (spv::Decoration ::NonWritable ); 524if (qualifier .isWriteOnly ()) 525memory .push_back (spv::Decoration ::NonReadable ); 526} 527 528// Translate glslang type to SPIR-V layout decorations. 529spv::Decoration TranslateLayoutDecoration (const glslang::TType & type , glslang::TLayoutMatrix matrixLayout ) 530{ 531if (type .isMatrix ()) { 532switch (matrixLayout ) { 533case glslang::ElmRowMajor : 534return spv::Decoration ::RowMajor ; 535case glslang::ElmColumnMajor : 536return spv::Decoration ::ColMajor ; 537default : 538// opaque layouts don't need a majorness 539return spv::Decoration ::Max ; 540 } 541 }else { 542switch (type .getBasicType ()) { 543default : 544return spv::Decoration ::Max ; 545break ; 546case glslang::EbtBlock : 547switch (type .getQualifier ().storage ) { 548case glslang::EvqShared : 549case glslang::EvqUniform : 550case glslang::EvqBuffer : 551switch (type .getQualifier ().layoutPacking ) { 552case glslang::ElpShared :return spv::Decoration ::GLSLShared ; 553case glslang::ElpPacked :return spv::Decoration ::GLSLPacked ; 554default : 555return spv::Decoration ::Max ; 556 } 557case glslang::EvqVaryingIn : 558case glslang::EvqVaryingOut : 559if (type .getQualifier ().isTaskMemory ()) { 560switch (type .getQualifier ().layoutPacking ) { 561case glslang::ElpShared :return spv::Decoration ::GLSLShared ; 562case glslang::ElpPacked :return spv::Decoration ::GLSLPacked ; 563default :break ; 564 } 565 }else { 566assert (type .getQualifier ().layoutPacking == glslang::ElpNone ); 567 } 568return spv::Decoration ::Max ; 569case glslang::EvqPayload : 570case glslang::EvqPayloadIn : 571case glslang::EvqHitAttr : 572case glslang::EvqCallableData : 573case glslang::EvqCallableDataIn : 574case glslang::EvqHitObjectAttrNV : 575case glslang::EvqHitObjectAttrEXT : 576case glslang::EvqResourceHeap : 577case glslang::EvqSamplerHeap : 578return spv::Decoration ::Max ; 579default : 580assert (0 ); 581return spv::Decoration ::Max ; 582 } 583 } 584 } 585} 586 587// Translate glslang type to SPIR-V interpolation decorations. 588// Returns spv::Decoration::Max when no decoration 589// should be applied. 590spv::Decoration TGlslangToSpvTraverser ::TranslateInterpolationDecoration (const glslang::TQualifier & qualifier ) 591{ 592if (qualifier .smooth ) 593// Smooth decoration doesn't exist in SPIR-V 1.0 594return spv::Decoration ::Max ; 595else if (qualifier .isNonPerspective ()) 596return spv::Decoration ::NoPerspective ; 597else if (qualifier .flat ) 598return spv::Decoration ::Flat ; 599else if (qualifier .isExplicitInterpolation ()) { 600builder .addExtension (spv::E_SPV_AMD_shader_explicit_vertex_parameter ); 601return spv::Decoration ::ExplicitInterpAMD ; 602 } 603else 604return spv::Decoration ::Max ; 605} 606 607// Translate glslang type to SPIR-V auxiliary storage decorations. 608// Returns spv::Decoration::Max when no decoration 609// should be applied. 610spv::Decoration TGlslangToSpvTraverser ::TranslateAuxiliaryStorageDecoration (const glslang::TQualifier & qualifier ) 611{ 612if (qualifier .centroid ) 613return spv::Decoration ::Centroid ; 614else if (qualifier .patch ) 615return spv::Decoration ::Patch ; 616else if (qualifier .sample ) { 617builder .addCapability (spv::Capability ::SampleRateShading ); 618return spv::Decoration ::Sample ; 619 } 620 621return spv::Decoration ::Max ; 622} 623 624// If glslang type is invariant, return SPIR-V invariant decoration. 625spv::Decoration TranslateInvariantDecoration (const glslang::TQualifier & qualifier ) 626{ 627if (qualifier .invariant ) 628return spv::Decoration ::Invariant ; 629else 630return spv::Decoration ::Max ; 631} 632 633// If glslang type is noContraction, return SPIR-V NoContraction decoration. 634spv::Decoration TranslateNoContractionDecoration (const glslang::TQualifier & qualifier ) 635{ 636if (qualifier .isNoContraction ()) 637return spv::Decoration ::NoContraction ; 638else 639return spv::Decoration ::Max ; 640} 641 642// If glslang type is nonUniform, return SPIR-V NonUniform decoration. 643spv::Decoration TGlslangToSpvTraverser ::TranslateNonUniformDecoration (const glslang::TQualifier & qualifier ) 644{ 645if (qualifier .isNonUniform ()) { 646builder .addIncorporatedExtension ("SPV_EXT_descriptor_indexing" , spv::Spv_1_5 ); 647builder .addCapability (spv::Capability ::ShaderNonUniformEXT ); 648 649auto & extensions = glslangIntermediate -> getRequestedExtensions (); 650if (extensions .find ("GL_EXT_descriptor_heap" )!= extensions .end ()) { 651builder .addExtension ("SPV_EXT_descriptor_heap" ); 652builder .addCapability (spv::Capability ::DescriptorHeapEXT ); 653 } 654else { 655return spv::Decoration ::NonUniformEXT ; 656 } 657 } 658 659return spv::Decoration ::Max ; 660} 661 662// If lvalue flags contains nonUniform, return SPIR-V NonUniform decoration. 663spv::Decoration TGlslangToSpvTraverser ::TranslateNonUniformDecoration ( 664const spv::Builder ::AccessChain ::CoherentFlags & coherentFlags ) 665{ 666if (coherentFlags .isNonUniform ()) { 667builder .addIncorporatedExtension ("SPV_EXT_descriptor_indexing" , spv::Spv_1_5 ); 668builder .addCapability (spv::Capability ::ShaderNonUniformEXT ); 669 670auto & extensions = glslangIntermediate -> getRequestedExtensions (); 671if (extensions .find ("GL_EXT_descriptor_heap" )!= extensions .end ()) { 672builder .addExtension ("SPV_EXT_descriptor_heap" ); 673builder .addCapability (spv::Capability ::DescriptorHeapEXT ); 674 } 675else { 676return spv::Decoration ::NonUniformEXT ; 677 } 678 } 679 680return spv::Decoration ::Max ; 681} 682 683spv::MemoryAccessMask TGlslangToSpvTraverser ::TranslateMemoryAccess ( 684const spv::Builder ::AccessChain ::CoherentFlags & coherentFlags ) 685{ 686 spv::MemoryAccessMask mask = spv::MemoryAccessMask ::MaskNone ; 687 688if (!glslangIntermediate -> usingVulkanMemoryModel ()|| coherentFlags .isImage ) 689return mask ; 690 691if (coherentFlags .isVolatile ()|| coherentFlags .anyCoherent ()) { 692mask = mask | spv::MemoryAccessMask ::MakePointerAvailableKHR | 693 spv::MemoryAccessMask ::MakePointerVisibleKHR ; 694 } 695 696if (coherentFlags .nonprivate ) { 697mask = mask | spv::MemoryAccessMask ::NonPrivatePointerKHR ; 698 } 699if (coherentFlags .volatil ) { 700mask = mask | spv::MemoryAccessMask ::Volatile ; 701 } 702if (coherentFlags .nontemporal ) { 703mask = mask | spv::MemoryAccessMask ::Nontemporal ; 704 } 705if (mask != spv::MemoryAccessMask ::MaskNone ) { 706builder .addCapability (spv::Capability ::VulkanMemoryModelKHR ); 707 } 708 709return mask ; 710} 711 712spv::ImageOperandsMask TGlslangToSpvTraverser ::TranslateImageOperands ( 713const spv::Builder ::AccessChain ::CoherentFlags & coherentFlags ) 714{ 715 spv::ImageOperandsMask mask = spv::ImageOperandsMask ::MaskNone ; 716 717if (!glslangIntermediate -> usingVulkanMemoryModel ()) 718return mask ; 719 720if (coherentFlags .volatil || 721coherentFlags .anyCoherent ()) { 722mask = mask | spv::ImageOperandsMask ::MakeTexelAvailableKHR | 723 spv::ImageOperandsMask ::MakeTexelVisibleKHR ; 724 } 725if (coherentFlags .nonprivate ) { 726mask = mask | spv::ImageOperandsMask ::NonPrivateTexelKHR ; 727 } 728if (coherentFlags .volatil ) { 729mask = mask | spv::ImageOperandsMask ::VolatileTexelKHR ; 730 } 731if (coherentFlags .nontemporal && builder .getSpvVersion () >= spv::Spv_1_6 ) { 732mask = mask | spv::ImageOperandsMask ::Nontemporal ; 733 } 734if (mask != spv::ImageOperandsMask ::MaskNone ) { 735builder .addCapability (spv::Capability ::VulkanMemoryModelKHR ); 736 } 737 738return mask ; 739} 740 741spv::Builder ::AccessChain ::CoherentFlags TGlslangToSpvTraverser ::TranslateCoherent (const glslang::TType & type ) 742{ 743 spv::Builder ::AccessChain ::CoherentFlags flags = {}; 744flags .coherent = type .getQualifier ().coherent ; 745flags .devicecoherent = type .getQualifier ().devicecoherent ; 746flags .queuefamilycoherent = type .getQualifier ().queuefamilycoherent ; 747// shared variables are implicitly workgroupcoherent in GLSL. 748flags .workgroupcoherent = type .getQualifier ().workgroupcoherent || 749type .getQualifier ().storage == glslang::EvqShared ; 750flags .subgroupcoherent = type .getQualifier ().subgroupcoherent ; 751flags .shadercallcoherent = type .getQualifier ().shadercallcoherent ; 752flags .volatil = type .getQualifier ().volatil ; 753flags .nontemporal = type .getQualifier ().nontemporal ; 754// *coherent variables are implicitly nonprivate in GLSL 755flags .nonprivate = type .getQualifier ().nonprivate || 756flags .anyCoherent ()|| 757flags .volatil ; 758flags .isImage = type .getBasicType ()== glslang::EbtSampler ; 759flags .nonUniform = type .getQualifier ().nonUniform ; 760return flags ; 761} 762 763spv::Scope TGlslangToSpvTraverser ::TranslateMemoryScope ( 764const spv::Builder ::AccessChain ::CoherentFlags & coherentFlags ) 765{ 766 spv::Scope scope = spv::Scope ::Max ; 767 768if (coherentFlags .volatil || coherentFlags .coherent ) { 769// coherent defaults to Device scope in the old model, QueueFamilyKHR scope in the new model 770scope = glslangIntermediate -> usingVulkanMemoryModel () ? spv::Scope ::QueueFamilyKHR : spv::Scope ::Device ; 771 }else if (coherentFlags .devicecoherent ) { 772scope = spv::Scope ::Device ; 773 }else if (coherentFlags .queuefamilycoherent ) { 774scope = spv::Scope ::QueueFamilyKHR ; 775 }else if (coherentFlags .workgroupcoherent ) { 776scope = spv::Scope ::Workgroup ; 777 }else if (coherentFlags .subgroupcoherent ) { 778scope = spv::Scope ::Subgroup ; 779 }else if (coherentFlags .shadercallcoherent ) { 780scope = spv::Scope ::ShaderCallKHR ; 781 } 782if (glslangIntermediate -> usingVulkanMemoryModel ()&& scope == spv::Scope ::Device ) { 783builder .addCapability (spv::Capability ::VulkanMemoryModelDeviceScopeKHR ); 784 } 785 786return scope ; 787} 788 789// Translate a glslang built-in variable to a SPIR-V built in decoration. Also generate 790// associated capabilities when required. For some built-in variables, a capability 791// is generated only when using the variable in an executable instruction, but not when 792// just declaring a struct member variable with it. This is true for PointSize, 793// ClipDistance, and CullDistance. 794spv::BuiltIn TGlslangToSpvTraverser ::TranslateBuiltInDecoration (glslang::TBuiltInVariable builtIn , 795bool memberDeclaration ) 796{ 797switch (builtIn ) { 798case glslang::EbvPointSize : 799// Defer adding the capability until the built-in is actually used. 800if (!memberDeclaration ) { 801switch (glslangIntermediate -> getStage ()) { 802case EShLangGeometry : 803builder .addCapability (spv::Capability ::GeometryPointSize ); 804break ; 805case EShLangTessControl : 806case EShLangTessEvaluation : 807builder .addCapability (spv::Capability ::TessellationPointSize ); 808break ; 809default : 810break ; 811 } 812 } 813return spv::BuiltIn ::PointSize ; 814 815case glslang::EbvPosition :return spv::BuiltIn ::Position ; 816case glslang::EbvVertexId :return spv::BuiltIn ::VertexId ; 817case glslang::EbvInstanceId :return spv::BuiltIn ::InstanceId ; 818case glslang::EbvVertexIndex :return spv::BuiltIn ::VertexIndex ; 819case glslang::EbvInstanceIndex :return spv::BuiltIn ::InstanceIndex ; 820 821case glslang::EbvFragCoord :return spv::BuiltIn ::FragCoord ; 822case glslang::EbvPointCoord :return spv::BuiltIn ::PointCoord ; 823case glslang::EbvFace :return spv::BuiltIn ::FrontFacing ; 824case glslang::EbvFragDepth :return spv::BuiltIn ::FragDepth ; 825 826case glslang::EbvNumWorkGroups :return spv::BuiltIn ::NumWorkgroups ; 827case glslang::EbvWorkGroupSize :return spv::BuiltIn ::WorkgroupSize ; 828case glslang::EbvWorkGroupId :return spv::BuiltIn ::WorkgroupId ; 829case glslang::EbvLocalInvocationId :return spv::BuiltIn ::LocalInvocationId ; 830case glslang::EbvLocalInvocationIndex :return spv::BuiltIn ::LocalInvocationIndex ; 831case glslang::EbvGlobalInvocationId :return spv::BuiltIn ::GlobalInvocationId ; 832 833// These *Distance capabilities logically belong here, but if the member is declared and 834// then never used, consumers of SPIR-V prefer the capability not be declared. 835// They are now generated when used, rather than here when declared. 836// Potentially, the specification should be more clear what the minimum 837// use needed is to trigger the capability. 838// 839case glslang::EbvClipDistance : 840if (!memberDeclaration ) 841builder .addCapability (spv::Capability ::ClipDistance ); 842return spv::BuiltIn ::ClipDistance ; 843 844case glslang::EbvCullDistance : 845if (!memberDeclaration ) 846builder .addCapability (spv::Capability ::CullDistance ); 847return spv::BuiltIn ::CullDistance ; 848 849case glslang::EbvViewportIndex : 850if (glslangIntermediate -> getStage ()== EShLangGeometry || 851glslangIntermediate -> getStage ()== EShLangFragment ) { 852builder .addCapability (spv::Capability ::MultiViewport ); 853 } 854if (glslangIntermediate -> getStage ()== EShLangVertex || 855glslangIntermediate -> getStage ()== EShLangTessControl || 856glslangIntermediate -> getStage ()== EShLangTessEvaluation ) { 857 858if (builder .getSpvVersion ()< spv::Spv_1_5 ) { 859builder .addIncorporatedExtension (spv::E_SPV_EXT_shader_viewport_index_layer , spv::Spv_1_5 ); 860builder .addCapability (spv::Capability ::ShaderViewportIndexLayerEXT ); 861 } 862else 863builder .addCapability (spv::Capability ::ShaderViewportIndex ); 864 } 865return spv::BuiltIn ::ViewportIndex ; 866 867case glslang::EbvSampleId : 868builder .addCapability (spv::Capability ::SampleRateShading ); 869return spv::BuiltIn ::SampleId ; 870 871case glslang::EbvSamplePosition : 872builder .addCapability (spv::Capability ::SampleRateShading ); 873return spv::BuiltIn ::SamplePosition ; 874 875case glslang::EbvSampleMask : 876return spv::BuiltIn ::SampleMask ; 877 878case glslang::EbvLayer : 879if (glslangIntermediate -> getStage ()== EShLangMesh ) { 880return spv::BuiltIn ::Layer ; 881 } 882if (glslangIntermediate -> getStage ()== EShLangGeometry || 883glslangIntermediate -> getStage ()== EShLangFragment ) { 884builder .addCapability (spv::Capability ::Geometry ); 885 } 886if (glslangIntermediate -> getStage ()== EShLangVertex || 887glslangIntermediate -> getStage ()== EShLangTessControl || 888glslangIntermediate -> getStage ()== EShLangTessEvaluation ) { 889 890if (builder .getSpvVersion ()< spv::Spv_1_5 ) { 891builder .addIncorporatedExtension (spv::E_SPV_EXT_shader_viewport_index_layer , spv::Spv_1_5 ); 892builder .addCapability (spv::Capability ::ShaderViewportIndexLayerEXT ); 893 }else 894builder .addCapability (spv::Capability ::ShaderLayer ); 895 } 896return spv::BuiltIn ::Layer ; 897 898case glslang::EbvBaseVertex : 899builder .addIncorporatedExtension (spv::E_SPV_KHR_shader_draw_parameters , spv::Spv_1_3 ); 900builder .addCapability (spv::Capability ::DrawParameters ); 901return spv::BuiltIn ::BaseVertex ; 902 903case glslang::EbvBaseInstance : 904builder .addIncorporatedExtension (spv::E_SPV_KHR_shader_draw_parameters , spv::Spv_1_3 ); 905builder .addCapability (spv::Capability ::DrawParameters ); 906return spv::BuiltIn ::BaseInstance ; 907 908case glslang::EbvDrawId : 909builder .addIncorporatedExtension (spv::E_SPV_KHR_shader_draw_parameters , spv::Spv_1_3 ); 910builder .addCapability (spv::Capability ::DrawParameters ); 911return spv::BuiltIn ::DrawIndex ; 912 913case glslang::EbvPrimitiveId : 914if (glslangIntermediate -> getStage ()== EShLangFragment ) 915builder .addCapability (spv::Capability ::Geometry ); 916return spv::BuiltIn ::PrimitiveId ; 917 918case glslang::EbvFragStencilRef : 919builder .addExtension (spv::E_SPV_EXT_shader_stencil_export ); 920builder .addCapability (spv::Capability ::StencilExportEXT ); 921return spv::BuiltIn ::FragStencilRefEXT ; 922 923case glslang::EbvShadingRateKHR : 924builder .addExtension (spv::E_SPV_KHR_fragment_shading_rate ); 925builder .addCapability (spv::Capability ::FragmentShadingRateKHR ); 926return spv::BuiltIn ::ShadingRateKHR ; 927 928case glslang::EbvPrimitiveShadingRateKHR : 929builder .addExtension (spv::E_SPV_KHR_fragment_shading_rate ); 930builder .addCapability (spv::Capability ::FragmentShadingRateKHR ); 931return spv::BuiltIn ::PrimitiveShadingRateKHR ; 932 933case glslang::EbvInvocationId :return spv::BuiltIn ::InvocationId ; 934case glslang::EbvTessLevelInner :return spv::BuiltIn ::TessLevelInner ; 935case glslang::EbvTessLevelOuter :return spv::BuiltIn ::TessLevelOuter ; 936case glslang::EbvTessCoord :return spv::BuiltIn ::TessCoord ; 937case glslang::EbvPatchVertices :return spv::BuiltIn ::PatchVertices ; 938case glslang::EbvHelperInvocation :return spv::BuiltIn ::HelperInvocation ; 939 940case glslang::EbvSubGroupSize : 941builder .addExtension (spv::E_SPV_KHR_shader_ballot ); 942builder .addCapability (spv::Capability ::SubgroupBallotKHR ); 943return spv::BuiltIn ::SubgroupSize ; 944 945case glslang::EbvSubGroupInvocation : 946builder .addExtension (spv::E_SPV_KHR_shader_ballot ); 947builder .addCapability (spv::Capability ::SubgroupBallotKHR ); 948return spv::BuiltIn ::SubgroupLocalInvocationId ; 949 950case glslang::EbvSubGroupEqMask : 951builder .addExtension (spv::E_SPV_KHR_shader_ballot ); 952builder .addCapability (spv::Capability ::SubgroupBallotKHR ); 953return spv::BuiltIn ::SubgroupEqMask ; 954 955case glslang::EbvSubGroupGeMask : 956builder .addExtension (spv::E_SPV_KHR_shader_ballot ); 957builder .addCapability (spv::Capability ::SubgroupBallotKHR ); 958return spv::BuiltIn ::SubgroupGeMask ; 959 960case glslang::EbvSubGroupGtMask : 961builder .addExtension (spv::E_SPV_KHR_shader_ballot ); 962builder .addCapability (spv::Capability ::SubgroupBallotKHR ); 963return spv::BuiltIn ::SubgroupGtMask ; 964 965case glslang::EbvSubGroupLeMask : 966builder .addExtension (spv::E_SPV_KHR_shader_ballot ); 967builder .addCapability (spv::Capability ::SubgroupBallotKHR ); 968return spv::BuiltIn ::SubgroupLeMask ; 969 970case glslang::EbvSubGroupLtMask : 971builder .addExtension (spv::E_SPV_KHR_shader_ballot ); 972builder .addCapability (spv::Capability ::SubgroupBallotKHR ); 973return spv::BuiltIn ::SubgroupLtMask ; 974 975case glslang::EbvNumSubgroups : 976builder .addCapability (spv::Capability ::GroupNonUniform ); 977return spv::BuiltIn ::NumSubgroups ; 978 979case glslang::EbvSubgroupID : 980builder .addCapability (spv::Capability ::GroupNonUniform ); 981return spv::BuiltIn ::SubgroupId ; 982 983case glslang::EbvSubgroupSize2 : 984builder .addCapability (spv::Capability ::GroupNonUniform ); 985return spv::BuiltIn ::SubgroupSize ; 986 987case glslang::EbvSubgroupInvocation2 : 988builder .addCapability (spv::Capability ::GroupNonUniform ); 989return spv::BuiltIn ::SubgroupLocalInvocationId ; 990 991case glslang::EbvSubgroupEqMask2 : 992builder .addCapability (spv::Capability ::GroupNonUniform ); 993builder .addCapability (spv::Capability ::GroupNonUniformBallot ); 994return spv::BuiltIn ::SubgroupEqMask ; 995 996case glslang::EbvSubgroupGeMask2 : 997builder .addCapability (spv::Capability ::GroupNonUniform ); 998builder .addCapability (spv::Capability ::GroupNonUniformBallot ); 999return spv::BuiltIn ::SubgroupGeMask ; 1000 1001case glslang::EbvSubgroupGtMask2 : 1002builder .addCapability (spv::Capability ::GroupNonUniform ); 1003builder .addCapability (spv::Capability ::GroupNonUniformBallot ); 1004return spv::BuiltIn ::SubgroupGtMask ; 1005 1006case glslang::EbvSubgroupLeMask2 : 1007builder .addCapability (spv::Capability ::GroupNonUniform ); 1008builder .addCapability (spv::Capability ::GroupNonUniformBallot ); 1009return spv::BuiltIn ::SubgroupLeMask ; 1010 1011case glslang::EbvSubgroupLtMask2 : 1012builder .addCapability (spv::Capability ::GroupNonUniform ); 1013builder .addCapability (spv::Capability ::GroupNonUniformBallot ); 1014return spv::BuiltIn ::SubgroupLtMask ; 1015 1016case glslang::EbvBaryCoordNoPersp : 1017builder .addExtension (spv::E_SPV_AMD_shader_explicit_vertex_parameter ); 1018return spv::BuiltIn ::BaryCoordNoPerspAMD ; 1019 1020case glslang::EbvBaryCoordNoPerspCentroid : 1021builder .addExtension (spv::E_SPV_AMD_shader_explicit_vertex_parameter ); 1022return spv::BuiltIn ::BaryCoordNoPerspCentroidAMD ; 1023 1024case glslang::EbvBaryCoordNoPerspSample : 1025builder .addExtension (spv::E_SPV_AMD_shader_explicit_vertex_parameter ); 1026return spv::BuiltIn ::BaryCoordNoPerspSampleAMD ; 1027 1028case glslang::EbvBaryCoordSmooth : 1029builder .addExtension (spv::E_SPV_AMD_shader_explicit_vertex_parameter ); 1030return spv::BuiltIn ::BaryCoordSmoothAMD ; 1031 1032case glslang::EbvBaryCoordSmoothCentroid : 1033builder .addExtension (spv::E_SPV_AMD_shader_explicit_vertex_parameter ); 1034return spv::BuiltIn ::BaryCoordSmoothCentroidAMD ; 1035 1036case glslang::EbvBaryCoordSmoothSample : 1037builder .addExtension (spv::E_SPV_AMD_shader_explicit_vertex_parameter ); 1038return spv::BuiltIn ::BaryCoordSmoothSampleAMD ; 1039 1040case glslang::EbvBaryCoordPullModel : 1041builder .addExtension (spv::E_SPV_AMD_shader_explicit_vertex_parameter ); 1042return spv::BuiltIn ::BaryCoordPullModelAMD ; 1043 1044case glslang::EbvDeviceIndex : 1045builder .addIncorporatedExtension (spv::E_SPV_KHR_device_group , spv::Spv_1_3 ); 1046builder .addCapability (spv::Capability ::DeviceGroup ); 1047return spv::BuiltIn ::DeviceIndex ; 1048 1049case glslang::EbvViewIndex : 1050builder .addIncorporatedExtension (spv::E_SPV_KHR_multiview , spv::Spv_1_3 ); 1051builder .addCapability (spv::Capability ::MultiView ); 1052return spv::BuiltIn ::ViewIndex ; 1053 1054case glslang::EbvFragSizeEXT : 1055builder .addExtension (spv::E_SPV_EXT_fragment_invocation_density ); 1056builder .addCapability (spv::Capability ::FragmentDensityEXT ); 1057return spv::BuiltIn ::FragSizeEXT ; 1058 1059case glslang::EbvFragInvocationCountEXT : 1060builder .addExtension (spv::E_SPV_EXT_fragment_invocation_density ); 1061builder .addCapability (spv::Capability ::FragmentDensityEXT ); 1062return spv::BuiltIn ::FragInvocationCountEXT ; 1063 1064case glslang::EbvViewportMaskNV : 1065if (!memberDeclaration ) { 1066builder .addExtension (spv::E_SPV_NV_viewport_array2 ); 1067builder .addCapability (spv::Capability ::ShaderViewportMaskNV ); 1068 } 1069return spv::BuiltIn ::ViewportMaskNV ; 1070case glslang::EbvSecondaryPositionNV : 1071if (!memberDeclaration ) { 1072builder .addExtension (spv::E_SPV_NV_stereo_view_rendering ); 1073builder .addCapability (spv::Capability ::ShaderStereoViewNV ); 1074 } 1075return spv::BuiltIn ::SecondaryPositionNV ; 1076case glslang::EbvSecondaryViewportMaskNV : 1077if (!memberDeclaration ) { 1078builder .addExtension (spv::E_SPV_NV_stereo_view_rendering ); 1079builder .addCapability (spv::Capability ::ShaderStereoViewNV ); 1080 } 1081return spv::BuiltIn ::SecondaryViewportMaskNV ; 1082case glslang::EbvPositionPerViewNV : 1083if (!memberDeclaration ) { 1084builder .addExtension (spv::E_SPV_NVX_multiview_per_view_attributes ); 1085builder .addCapability (spv::Capability ::PerViewAttributesNV ); 1086 } 1087return spv::BuiltIn ::PositionPerViewNV ; 1088case glslang::EbvViewportMaskPerViewNV : 1089if (!memberDeclaration ) { 1090builder .addExtension (spv::E_SPV_NVX_multiview_per_view_attributes ); 1091builder .addCapability (spv::Capability ::PerViewAttributesNV ); 1092 } 1093return spv::BuiltIn ::ViewportMaskPerViewNV ; 1094case glslang::EbvFragFullyCoveredNV : 1095builder .addExtension (spv::E_SPV_EXT_fragment_fully_covered ); 1096builder .addCapability (spv::Capability ::FragmentFullyCoveredEXT ); 1097return spv::BuiltIn ::FullyCoveredEXT ; 1098case glslang::EbvFragmentSizeNV : 1099builder .addExtension (spv::E_SPV_NV_shading_rate ); 1100builder .addCapability (spv::Capability ::ShadingRateNV ); 1101return spv::BuiltIn ::FragmentSizeNV ; 1102case glslang::EbvInvocationsPerPixelNV : 1103builder .addExtension (spv::E_SPV_NV_shading_rate ); 1104builder .addCapability (spv::Capability ::ShadingRateNV ); 1105return spv::BuiltIn ::InvocationsPerPixelNV ; 1106 1107// ray tracing 1108case glslang::EbvLaunchId : 1109return spv::BuiltIn ::LaunchIdKHR ; 1110case glslang::EbvLaunchSize : 1111return spv::BuiltIn ::LaunchSizeKHR ; 1112case glslang::EbvWorldRayOrigin : 1113return spv::BuiltIn ::WorldRayOriginKHR ; 1114case glslang::EbvWorldRayDirection : 1115return spv::BuiltIn ::WorldRayDirectionKHR ; 1116case glslang::EbvObjectRayOrigin : 1117return spv::BuiltIn ::ObjectRayOriginKHR ; 1118case glslang::EbvObjectRayDirection : 1119return spv::BuiltIn ::ObjectRayDirectionKHR ; 1120case glslang::EbvRayTmin : 1121return spv::BuiltIn ::RayTminKHR ; 1122case glslang::EbvRayTmax : 1123return spv::BuiltIn ::RayTmaxKHR ; 1124case glslang::EbvCullMask : 1125return spv::BuiltIn ::CullMaskKHR ; 1126case glslang::EbvPositionFetch : 1127return spv::BuiltIn ::HitTriangleVertexPositionsKHR ; 1128case glslang::EbvInstanceCustomIndex : 1129return spv::BuiltIn ::InstanceCustomIndexKHR ; 1130case glslang::EbvHitKind : 1131return spv::BuiltIn ::HitKindKHR ; 1132case glslang::EbvObjectToWorld : 1133case glslang::EbvObjectToWorld3x4 : 1134return spv::BuiltIn ::ObjectToWorldKHR ; 1135case glslang::EbvWorldToObject : 1136case glslang::EbvWorldToObject3x4 : 1137return spv::BuiltIn ::WorldToObjectKHR ; 1138case glslang::EbvIncomingRayFlags : 1139return spv::BuiltIn ::IncomingRayFlagsKHR ; 1140case glslang::EbvGeometryIndex : 1141return spv::BuiltIn ::RayGeometryIndexKHR ; 1142case glslang::EbvCurrentRayTimeNV : 1143builder .addExtension (spv::E_SPV_NV_ray_tracing_motion_blur ); 1144builder .addCapability (spv::Capability ::RayTracingMotionBlurNV ); 1145return spv::BuiltIn ::CurrentRayTimeNV ; 1146case glslang::EbvMicroTrianglePositionNV : 1147builder .addCapability (spv::Capability ::RayTracingDisplacementMicromapNV ); 1148builder .addExtension ("SPV_NV_displacement_micromap" ); 1149return spv::BuiltIn ::HitMicroTriangleVertexPositionsNV ; 1150case glslang::EbvMicroTriangleBaryNV : 1151builder .addCapability (spv::Capability ::RayTracingDisplacementMicromapNV ); 1152builder .addExtension ("SPV_NV_displacement_micromap" ); 1153return spv::BuiltIn ::HitMicroTriangleVertexBarycentricsNV ; 1154case glslang::EbvHitKindFrontFacingMicroTriangleNV : 1155builder .addCapability (spv::Capability ::RayTracingDisplacementMicromapNV ); 1156builder .addExtension ("SPV_NV_displacement_micromap" ); 1157return spv::BuiltIn ::HitKindFrontFacingMicroTriangleNV ; 1158case glslang::EbvHitKindBackFacingMicroTriangleNV : 1159builder .addCapability (spv::Capability ::RayTracingDisplacementMicromapNV ); 1160builder .addExtension ("SPV_NV_displacement_micromap" ); 1161return spv::BuiltIn ::HitKindBackFacingMicroTriangleNV ; 1162case glslang::EbvClusterIDNV : 1163builder .addCapability (spv::Capability ::RayTracingClusterAccelerationStructureNV ); 1164builder .addExtension ("SPV_NV_cluster_acceleration_structure" ); 1165return spv::BuiltIn ::ClusterIDNV ; 1166case glslang::EbvHitIsSphereNV : 1167builder .addCapability (spv::Capability ::RayTracingSpheresGeometryNV ); 1168builder .addExtension ("SPV_NV_linear_swept_spheres" ); 1169return spv::BuiltIn ::HitIsSphereNV ; 1170case glslang::EbvHitIsLSSNV : 1171builder .addCapability (spv::Capability ::RayTracingLinearSweptSpheresGeometryNV ); 1172builder .addExtension ("SPV_NV_linear_swept_spheres" ); 1173return spv::BuiltIn ::HitIsLSSNV ; 1174case glslang::EbvHitSpherePositionNV : 1175builder .addCapability (spv::Capability ::RayTracingSpheresGeometryNV ); 1176builder .addExtension ("SPV_NV_linear_swept_spheres" ); 1177return spv::BuiltIn ::HitSpherePositionNV ; 1178case glslang::EbvHitSphereRadiusNV : 1179builder .addCapability (spv::Capability ::RayTracingSpheresGeometryNV ); 1180builder .addExtension ("SPV_NV_linear_swept_spheres" ); 1181return spv::BuiltIn ::HitSphereRadiusNV ; 1182case glslang::EbvHitLSSPositionsNV : 1183builder .addCapability (spv::Capability ::RayTracingLinearSweptSpheresGeometryNV ); 1184builder .addExtension ("SPV_NV_linear_swept_spheres" ); 1185return spv::BuiltIn ::HitLSSPositionsNV ; 1186case glslang::EbvHitLSSRadiiNV : 1187builder .addCapability (spv::Capability ::RayTracingLinearSweptSpheresGeometryNV ); 1188builder .addExtension ("SPV_NV_linear_swept_spheres" ); 1189return spv::BuiltIn ::HitLSSRadiiNV ; 1190 1191// barycentrics 1192case glslang::EbvBaryCoordNV : 1193builder .addExtension (spv::E_SPV_NV_fragment_shader_barycentric ); 1194builder .addCapability (spv::Capability ::FragmentBarycentricNV ); 1195return spv::BuiltIn ::BaryCoordNV ; 1196case glslang::EbvBaryCoordNoPerspNV : 1197builder .addExtension (spv::E_SPV_NV_fragment_shader_barycentric ); 1198builder .addCapability (spv::Capability ::FragmentBarycentricNV ); 1199return spv::BuiltIn ::BaryCoordNoPerspNV ; 1200 1201case glslang::EbvBaryCoordEXT : 1202builder .addExtension (spv::E_SPV_KHR_fragment_shader_barycentric ); 1203builder .addCapability (spv::Capability ::FragmentBarycentricKHR ); 1204return spv::BuiltIn ::BaryCoordKHR ; 1205case glslang::EbvBaryCoordNoPerspEXT : 1206builder .addExtension (spv::E_SPV_KHR_fragment_shader_barycentric ); 1207builder .addCapability (spv::Capability ::FragmentBarycentricKHR ); 1208return spv::BuiltIn ::BaryCoordNoPerspKHR ; 1209 1210// mesh shaders 1211case glslang::EbvTaskCountNV : 1212return spv::BuiltIn ::TaskCountNV ; 1213case glslang::EbvPrimitiveCountNV : 1214return spv::BuiltIn ::PrimitiveCountNV ; 1215case glslang::EbvPrimitiveIndicesNV : 1216return spv::BuiltIn ::PrimitiveIndicesNV ; 1217case glslang::EbvClipDistancePerViewNV : 1218return spv::BuiltIn ::ClipDistancePerViewNV ; 1219case glslang::EbvCullDistancePerViewNV : 1220return spv::BuiltIn ::CullDistancePerViewNV ; 1221case glslang::EbvLayerPerViewNV : 1222return spv::BuiltIn ::LayerPerViewNV ; 1223case glslang::EbvMeshViewCountNV : 1224return spv::BuiltIn ::MeshViewCountNV ; 1225case glslang::EbvMeshViewIndicesNV : 1226return spv::BuiltIn ::MeshViewIndicesNV ; 1227 1228// SPV_EXT_mesh_shader 1229case glslang::EbvPrimitivePointIndicesEXT : 1230return spv::BuiltIn ::PrimitivePointIndicesEXT ; 1231case glslang::EbvPrimitiveLineIndicesEXT : 1232return spv::BuiltIn ::PrimitiveLineIndicesEXT ; 1233case glslang::EbvPrimitiveTriangleIndicesEXT : 1234return spv::BuiltIn ::PrimitiveTriangleIndicesEXT ; 1235case glslang::EbvCullPrimitiveEXT : 1236return spv::BuiltIn ::CullPrimitiveEXT ; 1237 1238// sm builtins 1239case glslang::EbvWarpsPerSM : 1240builder .addExtension (spv::E_SPV_NV_shader_sm_builtins ); 1241builder .addCapability (spv::Capability ::ShaderSMBuiltinsNV ); 1242return spv::BuiltIn ::WarpsPerSMNV ; 1243case glslang::EbvSMCount : 1244builder .addExtension (spv::E_SPV_NV_shader_sm_builtins ); 1245builder .addCapability (spv::Capability ::ShaderSMBuiltinsNV ); 1246return spv::BuiltIn ::SMCountNV ; 1247case glslang::EbvWarpID : 1248builder .addExtension (spv::E_SPV_NV_shader_sm_builtins ); 1249builder .addCapability (spv::Capability ::ShaderSMBuiltinsNV ); 1250return spv::BuiltIn ::WarpIDNV ; 1251case glslang::EbvSMID : 1252builder .addExtension (spv::E_SPV_NV_shader_sm_builtins ); 1253builder .addCapability (spv::Capability ::ShaderSMBuiltinsNV ); 1254return spv::BuiltIn ::SMIDNV ; 1255 1256// ARM builtins 1257case glslang::EbvCoreCountARM : 1258builder .addExtension (spv::E_SPV_ARM_core_builtins ); 1259builder .addCapability (spv::Capability ::CoreBuiltinsARM ); 1260return spv::BuiltIn ::CoreCountARM ; 1261case glslang::EbvCoreIDARM : 1262builder .addExtension (spv::E_SPV_ARM_core_builtins ); 1263builder .addCapability (spv::Capability ::CoreBuiltinsARM ); 1264return spv::BuiltIn ::CoreIDARM ; 1265case glslang::EbvCoreMaxIDARM : 1266builder .addExtension (spv::E_SPV_ARM_core_builtins ); 1267builder .addCapability (spv::Capability ::CoreBuiltinsARM ); 1268return spv::BuiltIn ::CoreMaxIDARM ; 1269case glslang::EbvWarpIDARM : 1270builder .addExtension (spv::E_SPV_ARM_core_builtins ); 1271builder .addCapability (spv::Capability ::CoreBuiltinsARM ); 1272return spv::BuiltIn ::WarpIDARM ; 1273case glslang::EbvWarpMaxIDARM : 1274builder .addExtension (spv::E_SPV_ARM_core_builtins ); 1275builder .addCapability (spv::Capability ::CoreBuiltinsARM ); 1276return spv::BuiltIn ::WarpMaxIDARM ; 1277 1278// QCOM builtins 1279case glslang::EbvTileOffsetQCOM : 1280builder .addExtension (spv::E_SPV_QCOM_tile_shading ); 1281return spv::BuiltIn ::TileOffsetQCOM ; 1282case glslang::EbvTileDimensionQCOM : 1283builder .addExtension (spv::E_SPV_QCOM_tile_shading ); 1284return spv::BuiltIn ::TileDimensionQCOM ; 1285case glslang::EbvTileApronSizeQCOM : 1286builder .addExtension (spv::E_SPV_QCOM_tile_shading ); 1287return spv::BuiltIn ::TileApronSizeQCOM ; 1288 1289// SPV_EXT_descriptor_heap 1290case glslang::EbvSamplerHeapEXT : 1291builder .addExtension (spv::E_SPV_EXT_descriptor_heap ); 1292builder .addExtension (spv::E_SPV_KHR_untyped_pointers ); 1293builder .addCapability (spv::Capability ::DescriptorHeapEXT ); 1294builder .addCapability (spv::Capability ::UntypedPointersKHR ); 1295// Add SamplerHeapEXT Symbol for spv level. 1296if (builtInVariableIds .find (uint32_t (spv::BuiltIn ::SamplerHeapEXT ))== builtInVariableIds .end ()) { 1297 spv::Id samplerHeapEXT = 1298builder .createUntypedVariable (spv::NoPrecision , spv::StorageClass ::UniformConstant ,"sampler_heap" ); 1299if (glslangIntermediate -> getSpv ().spv >= glslang::EShTargetSpv_1_4 ) 1300entryPoint -> addIdOperand (samplerHeapEXT ); 1301builder .addDecoration (samplerHeapEXT , spv::Decoration ::BuiltIn , (int )spv::BuiltIn ::SamplerHeapEXT ); 1302builtInVariableIds .insert ({uint32_t (spv::BuiltIn ::SamplerHeapEXT ),samplerHeapEXT }); 1303 } 1304return spv::BuiltIn ::SamplerHeapEXT ; 1305case glslang::EbvResourceHeapEXT : 1306builder .addExtension (spv::E_SPV_EXT_descriptor_heap ); 1307builder .addExtension (spv::E_SPV_KHR_untyped_pointers ); 1308builder .addCapability (spv::Capability ::DescriptorHeapEXT ); 1309builder .addCapability (spv::Capability ::UntypedPointersKHR ); 1310// Add ResourceHeapEXT Symbol for spv level. 1311if (builtInVariableIds .find (uint32_t (spv::BuiltIn ::ResourceHeapEXT ))== builtInVariableIds .end ()) { 1312 spv::Id resourceHeapEXT = 1313builder .createUntypedVariable (spv::NoPrecision , spv::StorageClass ::UniformConstant ,"resource_heap" ); 1314if (glslangIntermediate -> getSpv ().spv >= glslang::EShTargetSpv_1_4 ) 1315entryPoint -> addIdOperand (resourceHeapEXT ); 1316builder .addDecoration (resourceHeapEXT , spv::Decoration ::BuiltIn , (int )spv::BuiltIn ::ResourceHeapEXT ); 1317builtInVariableIds .insert ({uint32_t (spv::BuiltIn ::ResourceHeapEXT ),resourceHeapEXT }); 1318 } 1319return spv::BuiltIn ::ResourceHeapEXT ; 1320 1321default : 1322return spv::BuiltIn ::Max ; 1323 } 1324} 1325 1326// Translate glslang image layout format to SPIR-V image format. 1327spv::ImageFormat TGlslangToSpvTraverser ::TranslateImageFormat (const glslang::TType & type ) 1328{ 1329assert (type .getBasicType ()== glslang::EbtSampler ); 1330 1331// Check for capabilities 1332switch (type .getQualifier ().getFormat ()) { 1333case glslang::ElfRg32f : 1334case glslang::ElfRg16f : 1335case glslang::ElfR11fG11fB10f : 1336case glslang::ElfR16f : 1337case glslang::ElfRgba16 : 1338case glslang::ElfRgb10A2 : 1339case glslang::ElfRg16 : 1340case glslang::ElfRg8 : 1341case glslang::ElfR16 : 1342case glslang::ElfR8 : 1343case glslang::ElfRgba16Snorm : 1344case glslang::ElfRg16Snorm : 1345case glslang::ElfRg8Snorm : 1346case glslang::ElfR16Snorm : 1347case glslang::ElfR8Snorm : 1348 1349case glslang::ElfRg32i : 1350case glslang::ElfRg16i : 1351case glslang::ElfRg8i : 1352case glslang::ElfR16i : 1353case glslang::ElfR8i : 1354 1355case glslang::ElfRgb10a2ui : 1356case glslang::ElfRg32ui : 1357case glslang::ElfRg16ui : 1358case glslang::ElfRg8ui : 1359case glslang::ElfR16ui : 1360case glslang::ElfR8ui : 1361builder .addCapability (spv::Capability ::StorageImageExtendedFormats ); 1362break ; 1363 1364case glslang::ElfR64ui : 1365case glslang::ElfR64i : 1366builder .addExtension (spv::E_SPV_EXT_shader_image_int64 ); 1367builder .addCapability (spv::Capability ::Int64ImageEXT ); 1368break ; 1369default : 1370break ; 1371 } 1372 1373// do the translation 1374switch (type .getQualifier ().getFormat ()) { 1375case glslang::ElfNone :return spv::ImageFormat ::Unknown ; 1376case glslang::ElfRgba32f :return spv::ImageFormat ::Rgba32f ; 1377case glslang::ElfRgba16f :return spv::ImageFormat ::Rgba16f ; 1378case glslang::ElfR32f :return spv::ImageFormat ::R32f ; 1379case glslang::ElfRgba8 :return spv::ImageFormat ::Rgba8 ; 1380case glslang::ElfRgba8Snorm :return spv::ImageFormat ::Rgba8Snorm ; 1381case glslang::ElfRg32f :return spv::ImageFormat ::Rg32f ; 1382case glslang::ElfRg16f :return spv::ImageFormat ::Rg16f ; 1383case glslang::ElfR11fG11fB10f :return spv::ImageFormat ::R11fG11fB10f ; 1384case glslang::ElfR16f :return spv::ImageFormat ::R16f ; 1385case glslang::ElfRgba16 :return spv::ImageFormat ::Rgba16 ; 1386case glslang::ElfRgb10A2 :return spv::ImageFormat ::Rgb10A2 ; 1387case glslang::ElfRg16 :return spv::ImageFormat ::Rg16 ; 1388case glslang::ElfRg8 :return spv::ImageFormat ::Rg8 ; 1389case glslang::ElfR16 :return spv::ImageFormat ::R16 ; 1390case glslang::ElfR8 :return spv::ImageFormat ::R8 ; 1391case glslang::ElfRgba16Snorm :return spv::ImageFormat ::Rgba16Snorm ; 1392case glslang::ElfRg16Snorm :return spv::ImageFormat ::Rg16Snorm ; 1393case glslang::ElfRg8Snorm :return spv::ImageFormat ::Rg8Snorm ; 1394case glslang::ElfR16Snorm :return spv::ImageFormat ::R16Snorm ; 1395case glslang::ElfR8Snorm :return spv::ImageFormat ::R8Snorm ; 1396case glslang::ElfRgba32i :return spv::ImageFormat ::Rgba32i ; 1397case glslang::ElfRgba16i :return spv::ImageFormat ::Rgba16i ; 1398case glslang::ElfRgba8i :return spv::ImageFormat ::Rgba8i ; 1399case glslang::ElfR32i :return spv::ImageFormat ::R32i ; 1400case glslang::ElfRg32i :return spv::ImageFormat ::Rg32i ; 1401case glslang::ElfRg16i :return spv::ImageFormat ::Rg16i ; 1402case glslang::ElfRg8i :return spv::ImageFormat ::Rg8i ; 1403case glslang::ElfR16i :return spv::ImageFormat ::R16i ; 1404case glslang::ElfR8i :return spv::ImageFormat ::R8i ; 1405case glslang::ElfRgba32ui :return spv::ImageFormat ::Rgba32ui ; 1406case glslang::ElfRgba16ui :return spv::ImageFormat ::Rgba16ui ; 1407case glslang::ElfRgba8ui :return spv::ImageFormat ::Rgba8ui ; 1408case glslang::ElfR32ui :return spv::ImageFormat ::R32ui ; 1409case glslang::ElfRg32ui :return spv::ImageFormat ::Rg32ui ; 1410case glslang::ElfRg16ui :return spv::ImageFormat ::Rg16ui ; 1411case glslang::ElfRgb10a2ui :return spv::ImageFormat ::Rgb10a2ui ; 1412case glslang::ElfRg8ui :return spv::ImageFormat ::Rg8ui ; 1413case glslang::ElfR16ui :return spv::ImageFormat ::R16ui ; 1414case glslang::ElfR8ui :return spv::ImageFormat ::R8ui ; 1415case glslang::ElfR64ui :return spv::ImageFormat ::R64ui ; 1416case glslang::ElfR64i :return spv::ImageFormat ::R64i ; 1417default :return spv::ImageFormat ::Max ; 1418 } 1419} 1420 1421spv::SelectionControlMask TGlslangToSpvTraverser ::TranslateSelectionControl ( 1422const glslang::TIntermSelection & selectionNode )const 1423{ 1424if (selectionNode .getFlatten ()) 1425return spv::SelectionControlMask ::Flatten ; 1426if (selectionNode .getDontFlatten ()) 1427return spv::SelectionControlMask ::DontFlatten ; 1428return spv::SelectionControlMask ::MaskNone ; 1429} 1430 1431spv::SelectionControlMask TGlslangToSpvTraverser ::TranslateSwitchControl (const glslang::TIntermSwitch & switchNode ) 1432const 1433{ 1434if (switchNode .getFlatten ()) 1435return spv::SelectionControlMask ::Flatten ; 1436if (switchNode .getDontFlatten ()) 1437return spv::SelectionControlMask ::DontFlatten ; 1438return spv::SelectionControlMask ::MaskNone ; 1439} 1440 1441spv::FunctionControlMask TGlslangToSpvTraverser ::TranslateFunctionControl (unsigned int functionControl )const 1442{ 1443 spv::FunctionControlMask control = spv::FunctionControlMask ::MaskNone ; 1444 1445if (functionControl & glslang::EfcInline ) 1446control = control | spv::FunctionControlMask ::Inline ; 1447if (functionControl & glslang::EfcDontInline ) 1448control = control | spv::FunctionControlMask ::DontInline ; 1449 1450return control ; 1451} 1452 1453// return a non-0 dependency if the dependency argument must be set 1454spv::LoopControlMask TGlslangToSpvTraverser ::TranslateLoopControl (const glslang::TIntermLoop & loopNode , 1455 std::vector < unsigned int >& operands )const 1456{ 1457 spv::LoopControlMask control = spv::LoopControlMask ::MaskNone ; 1458 1459if (loopNode .getDontUnroll ()) 1460control = control | spv::LoopControlMask ::DontUnroll ; 1461if (loopNode .getUnroll ()) 1462control = control | spv::LoopControlMask ::Unroll ; 1463if (unsigned (loopNode .getLoopDependency ())== glslang::TIntermLoop ::dependencyInfinite ) 1464control = control | spv::LoopControlMask ::DependencyInfinite ; 1465else if (loopNode .getLoopDependency ()> 0 ) { 1466control = control | spv::LoopControlMask ::DependencyLength ; 1467operands .push_back ((unsigned int )loopNode .getLoopDependency ()); 1468 } 1469if (glslangIntermediate -> getSpv ().spv >= glslang::EShTargetSpv_1_4 ) { 1470if (loopNode .getMinIterations ()> 0 ) { 1471control = control | spv::LoopControlMask ::MinIterations ; 1472operands .push_back (loopNode .getMinIterations ()); 1473 } 1474if (loopNode .getMaxIterations ()< glslang::TIntermLoop ::iterationsInfinite ) { 1475control = control | spv::LoopControlMask ::MaxIterations ; 1476operands .push_back (loopNode .getMaxIterations ()); 1477 } 1478if (loopNode .getIterationMultiple ()> 1 ) { 1479control = control | spv::LoopControlMask ::IterationMultiple ; 1480operands .push_back (loopNode .getIterationMultiple ()); 1481 } 1482if (loopNode .getPeelCount ()> 0 ) { 1483control = control | spv::LoopControlMask ::PeelCount ; 1484operands .push_back (loopNode .getPeelCount ()); 1485 } 1486if (loopNode .getPartialCount ()> 0 ) { 1487control = control | spv::LoopControlMask ::PartialCount ; 1488operands .push_back (loopNode .getPartialCount ()); 1489 } 1490 } 1491if (loopNode .getMultipleWaitQueuesQCOM ()!= loopNode .noMultipleQaitQueues ) { 1492control = control | spv::LoopControlMask ::MultipleWaitQueuesQCOM ; 1493operands .push_back (loopNode .getMultipleWaitQueuesQCOM ()); 1494 } 1495 1496return control ; 1497} 1498 1499// Translate glslang type to SPIR-V storage class. 1500spv::StorageClass TGlslangToSpvTraverser ::TranslateStorageClass (const glslang::TType & type ) 1501{ 1502if (type .getBasicType ()== glslang::EbtRayQuery || type .getBasicType ()== glslang::EbtHitObjectNV 1503|| type .getBasicType ()== glslang::EbtHitObjectEXT ) 1504return spv::StorageClass ::Private ; 1505if (type .getQualifier ().isSpirvByReference ()) { 1506if (type .getQualifier ().isParamInput ()|| type .getQualifier ().isParamOutput ()) 1507return spv::StorageClass ::Function ; 1508 } 1509if (type .getQualifier ().isPipeInput ()) 1510return spv::StorageClass ::Input ; 1511if (type .getQualifier ().isPipeOutput ()) 1512return spv::StorageClass ::Output ; 1513if (type .getQualifier ().storage == glslang::EvqTileImageEXT || type .isAttachmentEXT ()) { 1514builder .addExtension (spv::E_SPV_EXT_shader_tile_image ); 1515builder .addCapability (spv::Capability ::TileImageColorReadAccessEXT ); 1516return spv::StorageClass ::TileImageEXT ; 1517 } 1518 1519if (type .getQualifier ().isTileAttachmentQCOM ()) { 1520builder .addExtension (spv::E_SPV_QCOM_tile_shading ); 1521builder .addCapability (spv::Capability ::TileShadingQCOM ); 1522return spv::StorageClass ::TileAttachmentQCOM ; 1523 } 1524 1525if (glslangIntermediate -> getSource ()!= glslang::EShSourceHlsl || 1526type .getQualifier ().storage == glslang::EvqUniform ) { 1527if (type .isAtomic ()) 1528return spv::StorageClass ::AtomicCounter ; 1529if (type .containsOpaque ()&& !glslangIntermediate -> getBindlessMode ()) { 1530if (type .getQualifier ().storage == glslang::EvqResourceHeap || 1531type .getQualifier ().storage == glslang::EvqSamplerHeap ) 1532return spv::StorageClass ::Uniform ; 1533else 1534return spv::StorageClass ::UniformConstant ; 1535 } 1536 } 1537 1538if (type .getQualifier ().isUniformOrBuffer ()&& 1539type .getQualifier ().isShaderRecord ()) { 1540return spv::StorageClass ::ShaderRecordBufferKHR ; 1541 } 1542 1543if (glslangIntermediate -> usingStorageBuffer ()&& type .getQualifier ().storage == glslang::EvqBuffer ) { 1544builder .addIncorporatedExtension (spv::E_SPV_KHR_storage_buffer_storage_class , spv::Spv_1_3 ); 1545return spv::StorageClass ::StorageBuffer ; 1546 } 1547 1548if (type .getQualifier ().isUniformOrBuffer ()) { 1549if (type .getQualifier ().isPushConstant ()) 1550return spv::StorageClass ::PushConstant ; 1551if (type .getBasicType ()== glslang::EbtBlock || 1552type .getQualifier ().layoutDescriptorHeap || 1553type .getQualifier ().isBufferType ()) 1554return spv::StorageClass ::Uniform ; 1555return spv::StorageClass ::UniformConstant ; 1556 } 1557 1558if (type .getQualifier ().storage == glslang::EvqShared && type .getBasicType ()== glslang::EbtBlock ) { 1559builder .addExtension (spv::E_SPV_KHR_workgroup_memory_explicit_layout ); 1560builder .addCapability (spv::Capability ::WorkgroupMemoryExplicitLayoutKHR ); 1561return spv::StorageClass ::Workgroup ; 1562 } 1563 1564switch (type .getQualifier ().storage ) { 1565case glslang::EvqGlobal :return spv::StorageClass ::Private ; 1566case glslang::EvqConstReadOnly :return spv::StorageClass ::Function ; 1567case glslang::EvqTemporary :return spv::StorageClass ::Function ; 1568case glslang::EvqShared :return spv::StorageClass ::Workgroup ; 1569case glslang::EvqPayload :return spv::StorageClass ::RayPayloadKHR ; 1570case glslang::EvqPayloadIn :return spv::StorageClass ::IncomingRayPayloadKHR ; 1571case glslang::EvqHitAttr :return spv::StorageClass ::HitAttributeKHR ; 1572case glslang::EvqCallableData :return spv::StorageClass ::CallableDataKHR ; 1573case glslang::EvqCallableDataIn :return spv::StorageClass ::IncomingCallableDataKHR ; 1574case glslang::EvqtaskPayloadSharedEXT :return spv::StorageClass ::TaskPayloadWorkgroupEXT ; 1575case glslang::EvqHitObjectAttrNV :return spv::StorageClass ::HitObjectAttributeNV ; 1576case glslang::EvqHitObjectAttrEXT :return spv::StorageClass ::HitObjectAttributeEXT ; 1577case glslang::EvqSpirvStorageClass :return static_cast < spv::StorageClass > (type .getQualifier ().spirvStorageClass ); 1578default : 1579assert (0 ); 1580break ; 1581 } 1582 1583return spv::StorageClass ::Function ; 1584} 1585 1586// Translate glslang constants to SPIR-V literals 1587void TGlslangToSpvTraverser ::TranslateLiterals (const glslang::TVector < const glslang::TIntermConstantUnion *>& constants , 1588 std::vector < unsigned >& literals )const 1589{ 1590for (auto constant :constants ) { 1591if (constant -> getBasicType ()== glslang::EbtFloat ) { 1592float floatValue = static_cast < float > (constant -> getConstArray ()[0 ].getDConst ()); 1593unsigned literal ; 1594 static_assert(sizeof (literal )== sizeof (floatValue ),"sizeof(unsigned) != sizeof(float)" ); 1595memcpy (& literal ,& floatValue ,sizeof (literal )); 1596literals .push_back (literal ); 1597 }else if (constant -> getBasicType ()== glslang::EbtInt ) { 1598unsigned literal = constant -> getConstArray ()[0 ].getIConst (); 1599literals .push_back (literal ); 1600 }else if (constant -> getBasicType ()== glslang::EbtUint ) { 1601unsigned literal = constant -> getConstArray ()[0 ].getUConst (); 1602literals .push_back (literal ); 1603 }else if (constant -> getBasicType ()== glslang::EbtBool ) { 1604unsigned literal = constant -> getConstArray ()[0 ].getBConst (); 1605literals .push_back (literal ); 1606 }else if (constant -> getBasicType ()== glslang::EbtString ) { 1607auto str = constant -> getConstArray ()[0 ].getSConst ()-> c_str (); 1608unsigned literal = 0 ; 1609char * literalPtr = reinterpret_cast < char *> (& literal ); 1610unsigned charCount = 0 ; 1611char ch = 0 ; 1612do { 1613ch = * (str ++ ); 1614* (literalPtr ++ )= ch ; 1615++ charCount ; 1616if (charCount == 4 ) { 1617literals .push_back (literal ); 1618literalPtr = reinterpret_cast < char *> (& literal ); 1619charCount = 0 ; 1620 } 1621 }while (ch != 0 ); 1622 1623// Partial literal is padded with 0 1624if (charCount > 0 ) { 1625for (;charCount < 4 ;++ charCount ) 1626* (literalPtr ++ )= 0 ; 1627literals .push_back (literal ); 1628 } 1629 }else 1630assert (0 );// Unexpected type 1631 } 1632} 1633 1634// Add capabilities pertaining to how an array is indexed. 1635void TGlslangToSpvTraverser ::addIndirectionIndexCapabilities (const glslang::TType & baseType , 1636const glslang::TType & indexType ) 1637{ 1638if (indexType .getQualifier ().isNonUniform ()) { 1639 1640// deal with an asserted non-uniform index 1641// SPV_EXT_descriptor_indexing already added in TranslateNonUniformDecoration 1642if (baseType .getBasicType ()== glslang::EbtSampler ) { 1643if (baseType .getQualifier ().hasAttachment ()) 1644builder .addCapability (spv::Capability ::InputAttachmentArrayNonUniformIndexingEXT ); 1645else if (baseType .isImage ()&& baseType .getSampler ().isBuffer ()) 1646builder .addCapability (spv::Capability ::StorageTexelBufferArrayNonUniformIndexingEXT ); 1647else if (baseType .isTexture ()&& baseType .getSampler ().isBuffer ()) 1648builder .addCapability (spv::Capability ::UniformTexelBufferArrayNonUniformIndexingEXT ); 1649else if (baseType .isImage ()) 1650builder .addCapability (spv::Capability ::StorageImageArrayNonUniformIndexingEXT ); 1651else if (baseType .isTexture ()) 1652builder .addCapability (spv::Capability ::SampledImageArrayNonUniformIndexingEXT ); 1653 }else if (baseType .getBasicType ()== glslang::EbtBlock ) { 1654if (baseType .getQualifier ().storage == glslang::EvqBuffer ) 1655builder .addCapability (spv::Capability ::StorageBufferArrayNonUniformIndexingEXT ); 1656else if (baseType .getQualifier ().storage == glslang::EvqUniform ) 1657builder .addCapability (spv::Capability ::UniformBufferArrayNonUniformIndexingEXT ); 1658 } 1659 }else { 1660// assume a dynamically uniform index 1661if (baseType .getBasicType ()== glslang::EbtSampler ) { 1662if (baseType .getQualifier ().hasAttachment ()) { 1663builder .addIncorporatedExtension ("SPV_EXT_descriptor_indexing" , spv::Spv_1_5 ); 1664builder .addCapability (spv::Capability ::InputAttachmentArrayDynamicIndexingEXT ); 1665 }else if (baseType .isImage ()&& baseType .getSampler ().isBuffer ()) { 1666builder .addIncorporatedExtension ("SPV_EXT_descriptor_indexing" , spv::Spv_1_5 ); 1667builder .addCapability (spv::Capability ::StorageTexelBufferArrayDynamicIndexingEXT ); 1668 }else if (baseType .isTexture ()&& baseType .getSampler ().isBuffer ()) { 1669builder .addIncorporatedExtension ("SPV_EXT_descriptor_indexing" , spv::Spv_1_5 ); 1670builder .addCapability (spv::Capability ::UniformTexelBufferArrayDynamicIndexingEXT ); 1671 } 1672 } 1673 } 1674} 1675 1676// Return whether or not the given type is something that should be tied to a 1677// descriptor set. 1678bool IsDescriptorResource (const glslang::TType & type ) 1679{ 1680// uniform and buffer blocks are included, unless it is a push_constant 1681if (type .getBasicType ()== glslang::EbtBlock ) 1682return type .getQualifier ().isUniformOrBuffer ()&& 1683 !type .getQualifier ().isShaderRecord ()&& 1684 !type .getQualifier ().isPushConstant (); 1685 1686// non block... 1687// basically samplerXXX/subpass/sampler/texture are all included 1688// if they are the global-scope-class, not the function parameter 1689// (or local, if they ever exist) class. 1690if (type .getBasicType ()== glslang::EbtSampler || 1691type .getBasicType ()== glslang::EbtAccStruct ) 1692return type .getQualifier ().isUniformOrBuffer (); 1693 1694// Tensors are tied to a descriptor. 1695if (type .isTensorARM ()) 1696return true; 1697 1698// None of the above. 1699return false; 1700} 1701 1702void InheritQualifiers (glslang::TQualifier & child ,const glslang::TQualifier & parent ) 1703{ 1704if (child .layoutMatrix == glslang::ElmNone ) 1705child .layoutMatrix = parent .layoutMatrix ; 1706 1707if (parent .invariant ) 1708child .invariant = true; 1709if (parent .flat ) 1710child .flat = true; 1711if (parent .centroid ) 1712child .centroid = true; 1713if (parent .nopersp ) 1714child .nopersp = true; 1715if (parent .explicitInterp ) 1716child .explicitInterp = true; 1717if (parent .perPrimitiveNV ) 1718child .perPrimitiveNV = true; 1719if (parent .perViewNV ) 1720child .perViewNV = true; 1721if (parent .perTaskNV ) 1722child .perTaskNV = true; 1723if (parent .storage == glslang::EvqtaskPayloadSharedEXT ) 1724child .storage = glslang::EvqtaskPayloadSharedEXT ; 1725if (parent .patch ) 1726child .patch = true; 1727if (parent .sample ) 1728child .sample = true; 1729if (parent .coherent ) 1730child .coherent = true; 1731if (parent .devicecoherent ) 1732child .devicecoherent = true; 1733if (parent .queuefamilycoherent ) 1734child .queuefamilycoherent = true; 1735if (parent .workgroupcoherent ) 1736child .workgroupcoherent = true; 1737if (parent .subgroupcoherent ) 1738child .subgroupcoherent = true; 1739if (parent .shadercallcoherent ) 1740child .shadercallcoherent = true; 1741if (parent .nonprivate ) 1742child .nonprivate = true; 1743if (parent .volatil ) 1744child .volatil = true; 1745if (parent .nontemporal ) 1746child .nontemporal = true; 1747if (parent .restrict ) 1748child .restrict = true; 1749if (parent .readonly ) 1750child .readonly = true; 1751if (parent .writeonly ) 1752child .writeonly = true; 1753if (parent .nonUniform ) 1754child .nonUniform = true; 1755} 1756 1757bool HasNonLayoutQualifiers (const glslang::TType & type ,const glslang::TQualifier & qualifier ) 1758{ 1759// This should list qualifiers that simultaneous satisfy: 1760// - struct members might inherit from a struct declaration 1761// (note that non-block structs don't explicitly inherit, 1762// only implicitly, meaning no decoration involved) 1763// - affect decorations on the struct members 1764// (note smooth does not, and expecting something like volatile 1765// to effect the whole object) 1766// - are not part of the offset/st430/etc or row/column-major layout 1767return qualifier .invariant || (qualifier .hasLocation ()&& type .getBasicType ()== glslang::EbtBlock ); 1768} 1769 1770// 1771// Implement the TGlslangToSpvTraverser class. 1772// 1773 1774TGlslangToSpvTraverser ::TGlslangToSpvTraverser (unsigned int spvVersion , 1775const glslang::TIntermediate * glslangIntermediate , 1776 spv::SpvBuildLogger * buildLogger , glslang::SpvOptions & options ) : 1777TIntermTraverser (true, false, true), 1778options (options ), 1779shaderEntry (nullptr ),currentFunction (nullptr ), 1780sequenceDepth (0 ), 1781opacityMicromapEnableConstId (spv::NoResult ), 1782logger (buildLogger ), 1783builder (spvVersion , (glslang::GetKhronosToolId () <<16 ) | glslang::GetSpirvGeneratorVersion (),logger ), 1784inEntryPoint (false),entryPointTerminated (false),linkageOnly (false), 1785glslangIntermediate (glslangIntermediate ), 1786nanMinMaxClamp (glslangIntermediate -> getNanMinMaxClamp ()), 1787nonSemanticDebugPrintf (0 ), 1788taskPayloadID (0 ), 1789descHeapLayout (* this ) 1790{ 1791bool isMeshShaderExt = (glslangIntermediate -> getRequestedExtensions ().find (glslang::E_GL_EXT_mesh_shader )!= 1792glslangIntermediate -> getRequestedExtensions ().end ()); 1793 spv::ExecutionModel executionModel = TranslateExecutionModel (glslangIntermediate -> getStage (),isMeshShaderExt ); 1794 1795builder .clearAccessChain (); 1796builder .setSource (TranslateSourceLanguage (glslangIntermediate -> getSource (),glslangIntermediate -> getProfile ()), 1797glslangIntermediate -> getVersion ()); 1798 1799if (options .emitNonSemanticShaderDebugSource ) 1800this -> options .emitNonSemanticShaderDebugInfo = true; 1801if (options .emitNonSemanticShaderDebugInfo ) 1802this -> options .generateDebugInfo = true; 1803 1804if (this -> options .generateDebugInfo ) { 1805if (this -> options .emitNonSemanticShaderDebugInfo ) { 1806builder .setEmitNonSemanticShaderDebugInfo (this -> options .emitNonSemanticShaderDebugSource ); 1807 } 1808else { 1809builder .setEmitSpirvDebugInfo (); 1810 } 1811builder .setDebugMainSourceFile (glslangIntermediate -> getSourceFile ()); 1812 1813// Set the source shader's text 1814 std::string text ; 1815 1816// If for SPV version 1.0, include 1817// a preamble in comments stating the OpModuleProcessed instructions. 1818// Otherwise, emit those as actual instructions. 1819// 1820// ...Except when using ShaderDebugInfo we DON'T want these as it will mess up the line 1821// number, instead the user has opt'ed in for ShaderDebugInfo instead, so they will want 1822// to parse those instead 1823// https://github.com/KhronosGroup/glslang/issues/3863 1824const bool add_comments = 1825glslangIntermediate -> getSpv ().spv < glslang::EShTargetSpv_1_1 && !options .emitNonSemanticShaderDebugSource ; 1826 1827const std::vector < std::string >& processes = glslangIntermediate -> getProcesses (); 1828for (int p = 0 ;p < (int )processes .size ();++ p ) { 1829if (add_comments ) { 1830text .append ("// OpModuleProcessed " ); 1831text .append (processes [p ]); 1832text .append ("\n" ); 1833 }else if (glslangIntermediate -> getSpv ().spv >= glslang::EShTargetSpv_1_1 ) { 1834// OpModuleProcessed added in SPIR-V 1.1 1835builder .addModuleProcessed (processes [p ]); 1836 } 1837 } 1838if (add_comments && (int )processes .size ()> 0 ) 1839text .append ("#line 1\n" ); 1840text .append (glslangIntermediate -> getSourceText ()); 1841builder .setSourceText (text ); 1842// Pass name and text for all included files 1843const std::map < std::string , std::string >& include_txt = glslangIntermediate -> getIncludeText (); 1844for (auto iItr = include_txt .begin ();iItr != include_txt .end ();++ iItr ) 1845builder .addInclude (iItr -> first ,iItr -> second ); 1846 }else if (this -> options .emitSourceFileName ) { 1847builder .setEmitSourceFileName (glslangIntermediate -> getSourceFile ()); 1848 } 1849 1850builder .setUseReplicatedComposites (glslangIntermediate -> usingReplicatedComposites ()); 1851 1852stdBuiltins = builder .import ("GLSL.std.450" ); 1853 1854 spv::AddressingModel addressingModel = spv::AddressingModel ::Logical ; 1855 spv::MemoryModel memoryModel = spv::MemoryModel ::GLSL450 ; 1856 1857if (glslangIntermediate -> usingPhysicalStorageBuffer ()) { 1858addressingModel = spv::AddressingModel ::PhysicalStorageBuffer64EXT ; 1859builder .addIncorporatedExtension (spv::E_SPV_KHR_physical_storage_buffer , spv::Spv_1_5 ); 1860builder .addCapability (spv::Capability ::PhysicalStorageBufferAddressesEXT ); 1861 } 1862if (glslangIntermediate -> usingVulkanMemoryModel ()) { 1863memoryModel = spv::MemoryModel ::VulkanKHR ; 1864builder .addCapability (spv::Capability ::VulkanMemoryModelKHR ); 1865builder .addIncorporatedExtension (spv::E_SPV_KHR_vulkan_memory_model , spv::Spv_1_5 ); 1866 } 1867builder .setMemoryModel (addressingModel ,memoryModel ); 1868 1869if (glslangIntermediate -> usingVariablePointers ()) { 1870builder .addCapability (spv::Capability ::VariablePointers ); 1871 } 1872 1873// If not linking, there is no entry point 1874if (!options .compileOnly ) { 1875shaderEntry = builder .makeEntryPoint (glslangIntermediate -> getEntryPointName ().c_str ()); 1876entryPoint = 1877builder .addEntryPoint (executionModel ,shaderEntry ,glslangIntermediate -> getEntryPointName ().c_str ()); 1878 } 1879 1880// Add the source extensions 1881const auto & sourceExtensions = glslangIntermediate -> getRequestedExtensions (); 1882for (auto it = sourceExtensions .begin ();it != sourceExtensions .end ();++ it ) 1883builder .addSourceExtension (it -> c_str ()); 1884 1885// Add the top-level modes for this shader. 1886 1887if (glslangIntermediate -> getXfbMode ()) { 1888builder .addCapability (spv::Capability ::TransformFeedback ); 1889builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::Xfb ); 1890 } 1891 1892if (glslangIntermediate -> getLayoutPrimitiveCulling ()) { 1893builder .addCapability (spv::Capability ::RayTraversalPrimitiveCullingKHR ); 1894 } 1895 1896// gl_RayFlagsForceOpacityMicromap2StateEXT was referenced. The SPIR-V RayFlags 1897// bit ForceOpacityMicromap2StateKHR requires the RayTracingOpacityMicromapEXT 1898// capability. Emit it here so it applies uniformly to ray-tracing-pipeline 1899// stages and any stage running ray queries. 1900if (glslangIntermediate -> getUsesOpacityMicromap2StateFlag ()) { 1901builder .addCapability (spv::Capability ::RayTracingOpacityMicromapEXT ); 1902builder .addExtension ("SPV_EXT_opacity_micromap" ); 1903 } 1904 1905if (glslangIntermediate -> getSubgroupUniformControlFlow ()) { 1906builder .addExtension (spv::E_SPV_KHR_subgroup_uniform_control_flow ); 1907builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::SubgroupUniformControlFlowKHR ); 1908 } 1909if (glslangIntermediate -> getMaximallyReconverges ()) { 1910builder .addExtension (spv::E_SPV_KHR_maximal_reconvergence ); 1911builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::MaximallyReconvergesKHR ); 1912 } 1913 1914if (glslangIntermediate -> getQuadDerivMode ()) 1915 { 1916builder .addCapability (spv::Capability ::QuadControlKHR ); 1917builder .addExtension (spv::E_SPV_KHR_quad_control ); 1918builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::QuadDerivativesKHR ); 1919 } 1920 1921if (glslangIntermediate -> getReqFullQuadsMode ()) 1922 { 1923builder .addCapability (spv::Capability ::QuadControlKHR ); 1924builder .addExtension (spv::E_SPV_KHR_quad_control ); 1925builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::RequireFullQuadsKHR ); 1926 } 1927 1928if (glslangIntermediate -> usingShader64BitIndexing ()) 1929 { 1930builder .addCapability (spv::Capability ::Shader64BitIndexingEXT ); 1931builder .addExtension (spv::E_SPV_EXT_shader_64bit_indexing ); 1932builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::Shader64BitIndexingEXT ); 1933 } 1934 1935 spv::ExecutionMode mode ; 1936switch (glslangIntermediate -> getStage ()) { 1937case EShLangVertex : 1938builder .addCapability (spv::Capability ::Shader ); 1939break ; 1940 1941case EShLangFragment : 1942builder .addCapability (spv::Capability ::Shader ); 1943if (glslangIntermediate -> getPixelCenterInteger ()) 1944builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::PixelCenterInteger ); 1945 1946if (glslangIntermediate -> getOriginUpperLeft ()) 1947builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::OriginUpperLeft ); 1948else 1949builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::OriginLowerLeft ); 1950 1951if (glslangIntermediate -> getEarlyFragmentTests ()) 1952builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::EarlyFragmentTests ); 1953 1954if (glslangIntermediate -> getEarlyAndLateFragmentTestsAMD ()) 1955 { 1956builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::EarlyAndLateFragmentTestsAMD ); 1957builder .addExtension (spv::E_SPV_AMD_shader_early_and_late_fragment_tests ); 1958 } 1959 1960if (glslangIntermediate -> getPostDepthCoverage ()) { 1961builder .addCapability (spv::Capability ::SampleMaskPostDepthCoverage ); 1962builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::PostDepthCoverage ); 1963builder .addExtension (spv::E_SPV_KHR_post_depth_coverage ); 1964 } 1965 1966if (glslangIntermediate -> getNonCoherentColorAttachmentReadEXT ()) { 1967builder .addCapability (spv::Capability ::TileImageColorReadAccessEXT ); 1968builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::NonCoherentColorAttachmentReadEXT ); 1969builder .addExtension (spv::E_SPV_EXT_shader_tile_image ); 1970 } 1971 1972if (glslangIntermediate -> getNonCoherentDepthAttachmentReadEXT ()) { 1973builder .addCapability (spv::Capability ::TileImageDepthReadAccessEXT ); 1974builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::NonCoherentDepthAttachmentReadEXT ); 1975builder .addExtension (spv::E_SPV_EXT_shader_tile_image ); 1976 } 1977 1978if (glslangIntermediate -> getNonCoherentStencilAttachmentReadEXT ()) { 1979builder .addCapability (spv::Capability ::TileImageStencilReadAccessEXT ); 1980builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::NonCoherentStencilAttachmentReadEXT ); 1981builder .addExtension (spv::E_SPV_EXT_shader_tile_image ); 1982 } 1983 1984if (glslangIntermediate -> getNonCoherentTileAttachmentReadQCOM ()) { 1985builder .addCapability (spv::Capability ::TileShadingQCOM ); 1986builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::NonCoherentTileAttachmentReadQCOM ); 1987builder .addExtension (spv::E_SPV_QCOM_tile_shading ); 1988 } 1989 1990if (glslangIntermediate -> isDepthReplacing ()) 1991builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::DepthReplacing ); 1992 1993if (glslangIntermediate -> isStencilReplacing ()) 1994builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::StencilRefReplacingEXT ); 1995 1996switch (glslangIntermediate -> getDepth ()) { 1997case glslang::EldGreater :mode = spv::ExecutionMode ::DepthGreater ;break ; 1998case glslang::EldLess :mode = spv::ExecutionMode ::DepthLess ;break ; 1999case glslang::EldUnchanged :mode = spv::ExecutionMode ::DepthUnchanged ;break ; 2000default :mode = spv::ExecutionMode ::Max ;break ; 2001 } 2002 2003if (mode != spv::ExecutionMode ::Max ) 2004builder .addExecutionMode (shaderEntry ,mode ); 2005 2006switch (glslangIntermediate -> getStencil ()) { 2007case glslang::ElsRefUnchangedFrontAMD :mode = spv::ExecutionMode ::StencilRefUnchangedFrontAMD ;break ; 2008case glslang::ElsRefGreaterFrontAMD :mode = spv::ExecutionMode ::StencilRefGreaterFrontAMD ;break ; 2009case glslang::ElsRefLessFrontAMD :mode = spv::ExecutionMode ::StencilRefLessFrontAMD ;break ; 2010case glslang::ElsRefUnchangedBackAMD :mode = spv::ExecutionMode ::StencilRefUnchangedBackAMD ;break ; 2011case glslang::ElsRefGreaterBackAMD :mode = spv::ExecutionMode ::StencilRefGreaterBackAMD ;break ; 2012case glslang::ElsRefLessBackAMD :mode = spv::ExecutionMode ::StencilRefLessBackAMD ;break ; 2013default :mode = spv::ExecutionMode ::Max ;break ; 2014 } 2015 2016if (mode != spv::ExecutionMode ::Max ) 2017builder .addExecutionMode (shaderEntry , (spv::ExecutionMode )mode ); 2018switch (glslangIntermediate -> getInterlockOrdering ()) { 2019case glslang::EioPixelInterlockOrdered :mode = spv::ExecutionMode ::PixelInterlockOrderedEXT ; 2020break ; 2021case glslang::EioPixelInterlockUnordered :mode = spv::ExecutionMode ::PixelInterlockUnorderedEXT ; 2022break ; 2023case glslang::EioSampleInterlockOrdered :mode = spv::ExecutionMode ::SampleInterlockOrderedEXT ; 2024break ; 2025case glslang::EioSampleInterlockUnordered :mode = spv::ExecutionMode ::SampleInterlockUnorderedEXT ; 2026break ; 2027case glslang::EioShadingRateInterlockOrdered :mode = spv::ExecutionMode ::ShadingRateInterlockOrderedEXT ; 2028break ; 2029case glslang::EioShadingRateInterlockUnordered :mode = spv::ExecutionMode ::ShadingRateInterlockUnorderedEXT ; 2030break ; 2031default :mode = spv::ExecutionMode ::Max ; 2032break ; 2033 } 2034if (mode != spv::ExecutionMode ::Max ) { 2035builder .addExecutionMode (shaderEntry , (spv::ExecutionMode )mode ); 2036if (mode == spv::ExecutionMode ::ShadingRateInterlockOrderedEXT || 2037mode == spv::ExecutionMode ::ShadingRateInterlockUnorderedEXT ) { 2038builder .addCapability (spv::Capability ::FragmentShaderShadingRateInterlockEXT ); 2039 }else if (mode == spv::ExecutionMode ::PixelInterlockOrderedEXT || 2040mode == spv::ExecutionMode ::PixelInterlockUnorderedEXT ) { 2041builder .addCapability (spv::Capability ::FragmentShaderPixelInterlockEXT ); 2042 }else { 2043builder .addCapability (spv::Capability ::FragmentShaderSampleInterlockEXT ); 2044 } 2045builder .addExtension (spv::E_SPV_EXT_fragment_shader_interlock ); 2046 } 2047break ; 2048 2049case EShLangCompute : { 2050builder .addCapability (spv::Capability ::Shader ); 2051bool needSizeId = false; 2052for (int dim = 0 ;dim < 3 ;++ dim ) { 2053if ((glslangIntermediate -> getLocalSizeSpecId (dim )!= glslang::TQualifier ::layoutNotSet )) { 2054needSizeId = true; 2055break ; 2056 } 2057 } 2058if (glslangIntermediate -> getSpv ().spv >= glslang::EShTargetSpv_1_6 && needSizeId ) { 2059 std::vector < spv::Id > dimConstId ; 2060for (int dim = 0 ;dim < 3 ;++ dim ) { 2061bool specConst = (glslangIntermediate -> getLocalSizeSpecId (dim )!= glslang::TQualifier ::layoutNotSet ); 2062dimConstId .push_back (builder .makeUintConstant (glslangIntermediate -> getLocalSize (dim ),specConst )); 2063if (specConst ) { 2064builder .addDecoration (dimConstId .back (), spv::Decoration ::SpecId , 2065glslangIntermediate -> getLocalSizeSpecId (dim )); 2066needSizeId = true; 2067 } 2068 } 2069builder .addExecutionModeId (shaderEntry , spv::ExecutionMode ::LocalSizeId ,dimConstId ); 2070 }else { 2071if (glslangIntermediate -> getTileShadingRateQCOM (0 ) >=1 || glslangIntermediate -> getTileShadingRateQCOM (1 ) >=1 || glslangIntermediate -> getTileShadingRateQCOM (2 ) >=1 ) { 2072auto rate_x = glslangIntermediate -> getTileShadingRateQCOM (0 ); 2073auto rate_y = glslangIntermediate -> getTileShadingRateQCOM (1 ); 2074auto rate_z = glslangIntermediate -> getTileShadingRateQCOM (2 ); 2075rate_x = (rate_x == 0 ?1 :rate_x ); 2076rate_y = (rate_y == 0 ?1 :rate_y ); 2077rate_z = (rate_z == 0 ?1 :rate_z ); 2078builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::TileShadingRateQCOM ,rate_x ,rate_y ,rate_z ); 2079 }else { 2080builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::LocalSize ,glslangIntermediate -> getLocalSize (0 ), 2081glslangIntermediate -> getLocalSize (1 ), 2082glslangIntermediate -> getLocalSize (2 )); 2083 } 2084 } 2085addDerivativeGroupExecutionMode (builder ,* glslangIntermediate ,shaderEntry ); 2086 2087if (glslangIntermediate -> getNonCoherentTileAttachmentReadQCOM ()) { 2088builder .addCapability (spv::Capability ::TileShadingQCOM ); 2089builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::NonCoherentTileAttachmentReadQCOM ); 2090builder .addExtension (spv::E_SPV_QCOM_tile_shading ); 2091 } 2092 2093break ; 2094 } 2095case EShLangTessEvaluation : 2096case EShLangTessControl : 2097builder .addCapability (spv::Capability ::Tessellation ); 2098 2099 glslang::TLayoutGeometry primitive ; 2100 2101if (glslangIntermediate -> getStage ()== EShLangTessControl ) { 2102builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::OutputVertices , 2103glslangIntermediate -> getVertices ()); 2104primitive = glslangIntermediate -> getOutputPrimitive (); 2105 }else { 2106primitive = glslangIntermediate -> getInputPrimitive (); 2107 } 2108 2109switch (primitive ) { 2110case glslang::ElgTriangles :mode = spv::ExecutionMode ::Triangles ;break ; 2111case glslang::ElgQuads :mode = spv::ExecutionMode ::Quads ;break ; 2112case glslang::ElgIsolines :mode = spv::ExecutionMode ::Isolines ;break ; 2113default :mode = spv::ExecutionMode ::Max ;break ; 2114 } 2115if (mode != spv::ExecutionMode ::Max ) 2116builder .addExecutionMode (shaderEntry ,mode ); 2117 2118switch (glslangIntermediate -> getVertexSpacing ()) { 2119case glslang::EvsEqual :mode = spv::ExecutionMode ::SpacingEqual ;break ; 2120case glslang::EvsFractionalEven :mode = spv::ExecutionMode ::SpacingFractionalEven ;break ; 2121case glslang::EvsFractionalOdd :mode = spv::ExecutionMode ::SpacingFractionalOdd ;break ; 2122default :mode = spv::ExecutionMode ::Max ;break ; 2123 } 2124if (mode != spv::ExecutionMode ::Max ) 2125builder .addExecutionMode (shaderEntry ,mode ); 2126 2127switch (glslangIntermediate -> getVertexOrder ()) { 2128case glslang::EvoCw :mode = spv::ExecutionMode ::VertexOrderCw ;break ; 2129case glslang::EvoCcw :mode = spv::ExecutionMode ::VertexOrderCcw ;break ; 2130default :mode = spv::ExecutionMode ::Max ;break ; 2131 } 2132if (mode != spv::ExecutionMode ::Max ) 2133builder .addExecutionMode (shaderEntry ,mode ); 2134 2135if (glslangIntermediate -> getPointMode ()) 2136builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::PointMode ); 2137break ; 2138 2139case EShLangGeometry : 2140builder .addCapability (spv::Capability ::Geometry ); 2141switch (glslangIntermediate -> getInputPrimitive ()) { 2142case glslang::ElgPoints :mode = spv::ExecutionMode ::InputPoints ;break ; 2143case glslang::ElgLines :mode = spv::ExecutionMode ::InputLines ;break ; 2144case glslang::ElgLinesAdjacency :mode = spv::ExecutionMode ::InputLinesAdjacency ;break ; 2145case glslang::ElgTriangles :mode = spv::ExecutionMode ::Triangles ;break ; 2146case glslang::ElgTrianglesAdjacency :mode = spv::ExecutionMode ::InputTrianglesAdjacency ;break ; 2147default :mode = spv::ExecutionMode ::Max ;break ; 2148 } 2149if (mode != spv::ExecutionMode ::Max ) 2150builder .addExecutionMode (shaderEntry ,mode ); 2151 2152builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::Invocations ,glslangIntermediate -> getInvocations ()); 2153 2154switch (glslangIntermediate -> getOutputPrimitive ()) { 2155case glslang::ElgPoints :mode = spv::ExecutionMode ::OutputPoints ;break ; 2156case glslang::ElgLineStrip :mode = spv::ExecutionMode ::OutputLineStrip ;break ; 2157case glslang::ElgTriangleStrip :mode = spv::ExecutionMode ::OutputTriangleStrip ;break ; 2158default :mode = spv::ExecutionMode ::Max ;break ; 2159 } 2160if (mode != spv::ExecutionMode ::Max ) 2161builder .addExecutionMode (shaderEntry ,mode ); 2162builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::OutputVertices ,glslangIntermediate -> getVertices ()); 2163break ; 2164 2165case EShLangRayGen : 2166case EShLangIntersect : 2167case EShLangAnyHit : 2168case EShLangClosestHit : 2169case EShLangMiss : 2170case EShLangCallable : 2171 { 2172auto & extensions = glslangIntermediate -> getRequestedExtensions (); 2173if (extensions .find ("GL_NV_ray_tracing" )== extensions .end ()) { 2174builder .addCapability (spv::Capability ::RayTracingKHR ); 2175builder .addExtension ("SPV_KHR_ray_tracing" ); 2176 } 2177else { 2178builder .addCapability (spv::Capability ::RayTracingNV ); 2179builder .addExtension ("SPV_NV_ray_tracing" ); 2180 } 2181if (glslangIntermediate -> getStage ()!= EShLangRayGen && glslangIntermediate -> getStage ()!= EShLangCallable ) { 2182if (extensions .find ("GL_EXT_ray_cull_mask" )!= extensions .end ()) { 2183builder .addCapability (spv::Capability ::RayCullMaskKHR ); 2184builder .addExtension ("SPV_KHR_ray_cull_mask" ); 2185 } 2186if (extensions .find ("GL_EXT_ray_tracing_position_fetch" )!= extensions .end ()) { 2187builder .addCapability (spv::Capability ::RayTracingPositionFetchKHR ); 2188builder .addExtension ("SPV_KHR_ray_tracing_position_fetch" ); 2189 } 2190 } 2191break ; 2192 } 2193case EShLangTask : 2194case EShLangMesh : 2195if (isMeshShaderExt ) { 2196builder .addCapability (spv::Capability ::MeshShadingEXT ); 2197builder .addExtension (spv::E_SPV_EXT_mesh_shader ); 2198 }else { 2199builder .addCapability (spv::Capability ::MeshShadingNV ); 2200builder .addExtension (spv::E_SPV_NV_mesh_shader ); 2201 } 2202if (glslangIntermediate -> getSpv ().spv >= glslang::EShTargetSpv_1_6 ) { 2203 std::vector < spv::Id > dimConstId ; 2204for (int dim = 0 ;dim < 3 ;++ dim ) { 2205bool specConst = (glslangIntermediate -> getLocalSizeSpecId (dim )!= glslang::TQualifier ::layoutNotSet ); 2206dimConstId .push_back (builder .makeUintConstant (glslangIntermediate -> getLocalSize (dim ),specConst )); 2207if (specConst ) { 2208builder .addDecoration (dimConstId .back (), spv::Decoration ::SpecId , 2209glslangIntermediate -> getLocalSizeSpecId (dim )); 2210 } 2211 } 2212builder .addExecutionModeId (shaderEntry , spv::ExecutionMode ::LocalSizeId ,dimConstId ); 2213 }else { 2214builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::LocalSize ,glslangIntermediate -> getLocalSize (0 ), 2215glslangIntermediate -> getLocalSize (1 ), 2216glslangIntermediate -> getLocalSize (2 )); 2217 } 2218addDerivativeGroupExecutionMode (builder ,* glslangIntermediate ,shaderEntry ); 2219if (glslangIntermediate -> getStage ()== EShLangMesh ) { 2220builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::OutputVertices , 2221glslangIntermediate -> getVertices ()); 2222builder .addExecutionMode (shaderEntry , spv::ExecutionMode ::OutputPrimitivesNV , 2223glslangIntermediate -> getPrimitives ()); 2224 2225switch (glslangIntermediate -> getOutputPrimitive ()) { 2226case glslang::ElgPoints :mode = spv::ExecutionMode ::OutputPoints ;break ; 2227case glslang::ElgLines :mode = spv::ExecutionMode ::OutputLinesNV ;break ; 2228case glslang::ElgTriangles :mode = spv::ExecutionMode ::OutputTrianglesNV ;break ; 2229default :mode = spv::ExecutionMode ::Max ;break ; 2230 } 2231if (mode != spv::ExecutionMode ::Max ) 2232builder .addExecutionMode (shaderEntry , (spv::ExecutionMode )mode ); 2233 } 2234break ; 2235 2236default : 2237break ; 2238 } 2239 2240// 2241// Add SPIR-V requirements (GL_EXT_spirv_intrinsics) 2242// 2243if (glslangIntermediate -> hasSpirvRequirement ()) { 2244const glslang::TSpirvRequirement & spirvRequirement = glslangIntermediate -> getSpirvRequirement (); 2245 2246// Add SPIR-V extension requirement 2247for (auto & extension :spirvRequirement .extensions ) 2248builder .addExtension (extension .c_str ()); 2249 2250// Add SPIR-V capability requirement 2251for (auto capability :spirvRequirement .capabilities ) 2252builder .addCapability (static_cast < spv::Capability > (capability )); 2253 } 2254 2255// 2256// Add SPIR-V execution mode qualifiers (GL_EXT_spirv_intrinsics) 2257// 2258if (glslangIntermediate -> hasSpirvExecutionMode ()) { 2259const glslang::TSpirvExecutionMode spirvExecutionMode = glslangIntermediate -> getSpirvExecutionMode (); 2260 2261// Add spirv_execution_mode 2262for (auto & mode :spirvExecutionMode .modes ) { 2263if (!mode .second .empty ()) { 2264 std::vector < unsigned > literals ; 2265TranslateLiterals (mode .second ,literals ); 2266builder .addExecutionMode (shaderEntry ,static_cast < spv::ExecutionMode > (mode .first ),literals ); 2267 }else 2268builder .addExecutionMode (shaderEntry ,static_cast < spv::ExecutionMode > (mode .first )); 2269 } 2270 2271// Add spirv_execution_mode_id 2272for (auto & modeId :spirvExecutionMode .modeIds ) { 2273 std::vector < spv::Id > operandIds ; 2274assert (!modeId .second .empty ()); 2275for (auto extraOperand :modeId .second ) { 2276if (extraOperand -> getType ().getQualifier ().isSpecConstant ()) 2277operandIds .push_back (getSymbolId (extraOperand -> getAsSymbolNode ())); 2278else 2279operandIds .push_back (createSpvConstant (* extraOperand )); 2280 } 2281builder .addExecutionModeId (shaderEntry ,static_cast < spv::ExecutionMode > (modeId .first ),operandIds ); 2282 } 2283 } 2284} 2285 2286// Finish creating SPV, after the traversal is complete. 2287void TGlslangToSpvTraverser ::finishSpv (bool compileOnly ) 2288{ 2289// If not linking, an entry point is not expected 2290if (!compileOnly ) { 2291// Finish the entry point function 2292if (!entryPointTerminated ) { 2293builder .setBuildPoint (shaderEntry -> getLastBlock ()); 2294builder .leaveFunction (); 2295 } 2296 2297// finish off the entry-point SPV instruction by adding the Input/Output <id> 2298entryPoint -> reserveOperands (iOSet .size ()); 2299for (auto id :iOSet ) 2300entryPoint -> addIdOperand (id ); 2301 2302// GL_EXT_opacity_micromap_ray_query_mode: the OpacityMicromapIdKHR execution mode is emitted 2303// whenever the extension is enabled (enabling the extension is the declaration), referencing the 2304// <id> of gl_EnableOpacityMicromapEXT. The operand constant depends on how the built-in was 2305// (re)declared: a constant_id redeclaration -> OpSpecConstantFalse (decorated with the SpecId); 2306// 'const bool = true' -> OpConstantTrue; otherwise (default or '= false') -> OpConstantFalse. If 2307// the built-in was read in the shader its spec constant is reused (opacityMicromapEnableConstId) 2308// so only one SpecId is emitted. This path targets SPV_KHR_opacity_micromap; the 2309// ForceOpacityMicromap2State ray flag keeps using SPV_EXT_opacity_micromap for compatibility. 2310if (glslangIntermediate -> IsRequestedExtension (glslang::E_GL_EXT_opacity_micromap_ray_query_mode )) { 2311 spv::Id enableId = opacityMicromapEnableConstId ; 2312if (enableId == spv::NoResult ) { 2313int specId = glslangIntermediate -> getEnableOpacityMicromapSpecId (); 2314if (specId != glslang::TQualifier ::layoutNotSet ) { 2315enableId = builder .makeBoolConstant (false, true); 2316builder .addDecoration (enableId , spv::Decoration ::SpecId ,specId ); 2317 }else { 2318enableId = builder .makeBoolConstant (glslangIntermediate -> getEnableOpacityMicromapDefault (), false); 2319 } 2320 } 2321builder .addCapability (spv::Capability ::RayTracingOpacityMicromapExecutionModeKHR ); 2322builder .addExtension (spv::E_SPV_KHR_opacity_micromap ); 2323builder .addExecutionModeId (shaderEntry , spv::ExecutionMode ::OpacityMicromapIdKHR , {enableId }); 2324 } 2325 } 2326 2327// Add capabilities, extensions, remove unneeded decorations, etc., 2328// based on the resulting SPIR-V. 2329// Note: WebGPU code generation must have the opportunity to aggressively 2330// prune unreachable merge blocks and continue targets. 2331builder .postProcess (compileOnly ); 2332} 2333 2334// Write the SPV into 'out'. 2335void TGlslangToSpvTraverser ::dumpSpv (std::vector < unsigned int >& out ) 2336{ 2337builder .dump (out ); 2338} 2339 2340// 2341// Implement the traversal functions. 2342// 2343// Return true from interior nodes to have the external traversal 2344// continue on to children. Return false if children were 2345// already processed. 2346// 2347 2348// 2349// Symbols can turn into 2350// - uniform/input reads 2351// - output writes 2352// - complex lvalue base setups: foo.bar[3].... , where we see foo and start up an access chain 2353// - something simple that degenerates into the last bullet 2354// 2355void TGlslangToSpvTraverser ::visitSymbol (glslang::TIntermSymbol * symbol ) 2356{ 2357// We update the line information even though no code might be generated here 2358// This is helpful to yield correct lines for control flow instructions 2359if (!linkageOnly ) { 2360builder .setDebugSourceLocation (symbol -> getLoc ().line ,symbol -> getLoc ().getFilename ()); 2361 } 2362 2363if (symbol -> getBasicType ()== glslang::EbtFunction ) { 2364return ; 2365 } 2366 2367SpecConstantOpModeGuard spec_constant_op_mode_setter (& builder ); 2368 2369if (symbol -> getType ().getQualifier ().isSpecConstant ()) 2370spec_constant_op_mode_setter .turnOnSpecConstantOpMode (); 2371#ifdef ENABLE_HLSL 2372// Skip symbol handling if it is string-typed 2373if (symbol -> getBasicType ()== glslang::EbtString ) 2374return ; 2375#endif 2376 2377// getSymbolId() will set up all the IO decorations on the first call. 2378// Formal function parameters were mapped during makeFunctions(). 2379 spv::Id id = getSymbolId (symbol ); 2380 2381if (symbol -> getType ().getQualifier ().isTaskPayload ()) 2382taskPayloadID = id ;// cache the taskPayloadID to be used it as operand for OpEmitMeshTasksEXT 2383 2384if (builder .isPointer (id )) { 2385if (!symbol -> getType ().getQualifier ().isParamInput ()&& 2386 !symbol -> getType ().getQualifier ().isParamOutput ()) { 2387// Include all "static use" and "linkage only" interface variables on the OpEntryPoint instruction 2388// Consider adding to the OpEntryPoint interface list. 2389// Only looking at structures if they have at least one member. 2390if (!symbol -> getType ().isStruct ()|| symbol -> getType ().getStruct ()-> size ()> 0 ) { 2391 spv::StorageClass sc = builder .getStorageClass (id ); 2392// Before SPIR-V 1.4, we only want to include Input and Output. 2393// Starting with SPIR-V 1.4, we want all globals. 2394if ((glslangIntermediate -> getSpv ().spv >= glslang::EShTargetSpv_1_4 && builder .isGlobalVariable (id ))|| 2395 (sc == spv::StorageClass ::Input || sc == spv::StorageClass ::Output )) { 2396iOSet .insert (id ); 2397 } 2398 } 2399 } 2400 2401// If the SPIR-V type is required to be different than the AST type 2402// (for ex SubgroupMasks or 3x4 ObjectToWorld/WorldToObject matrices), 2403// translate now from the SPIR-V type to the AST type, for the consuming 2404// operation. 2405// Note this turns it from an l-value to an r-value. 2406// Currently, all symbols needing this are inputs; avoid the map lookup when non-input. 2407if (symbol -> getType ().getQualifier ().storage == glslang::EvqVaryingIn ) 2408id = translateForcedType (id ,symbol -> getType ()); 2409 } 2410 2411// Only process non-linkage-only nodes for generating actual static uses 2412if (!linkageOnly || symbol -> getQualifier ().isSpecConstant ()) { 2413// Prepare to generate code for the access 2414 2415// L-value chains will be computed left to right. We're on the symbol now, 2416// which is the left-most part of the access chain, so now is "clear" time, 2417// followed by setting the base. 2418builder .clearAccessChain (); 2419 2420// For now, we consider all user variables as being in memory, so they are pointers, 2421// except for 2422// A) R-Value arguments to a function, which are an intermediate object. 2423// See comments in handleUserFunctionCall(). 2424// B) Specialization constants (normal constants don't even come in as a variable), 2425// These are also pure R-values. 2426// C) R-Values from type translation, see above call to translateForcedType() 2427 glslang::TQualifier qualifier = symbol -> getQualifier (); 2428if (qualifier .isSpecConstant ()|| rValueParameters .find (symbol -> getId ())!= rValueParameters .end ()|| 2429 (!builder .isPointerType (builder .getTypeId (id ))&& !builder .isUntypedPointer (id ))) 2430builder .setAccessChainRValue (id ); 2431else 2432builder .setAccessChainLValue (id ); 2433 2434if (qualifier .builtIn == glslang::EbvResourceHeapEXT || 2435qualifier .builtIn == glslang::EbvSamplerHeapEXT ) { 2436const glslang::TType & symbolType = symbol -> getType (); 2437// Direct descriptor-heap image arrays have no variable or member to 2438// carry NonReadable/NonWritable, so wrap them in a one-member block. 2439const bool wrapDescHeapImageArray = 2440symbolType .getQualifier ().layoutDescriptorHeap && 2441symbolType .isArray ()&& 2442symbolType .isImage ()&& 2443 (symbolType .getQualifier ().isReadOnly ()|| symbolType .getQualifier ().isWriteOnly ()); 2444 2445if (builder .getAccessChainDescHeapBaseType ()== spv::NoResult ) { 2446const long long symbolId = symbol -> getId (); 2447auto cachedBaseType = heapDescHeapBaseType .find (symbolId ); 2448if (cachedBaseType == heapDescHeapBaseType .end ()) { 2449 spv::Id baseType = convertGlslangToSpvType (symbolType ); 2450if (wrapDescHeapImageArray ) 2451baseType = makeDescHeapImageArrayWrapperType (* symbol ,baseType ); 2452cachedBaseType = heapDescHeapBaseType .emplace (symbolId ,baseType ).first ; 2453 } 2454builder .setAccessChainDescHeapBaseType (cachedBaseType -> second ); 2455 } 2456if (wrapDescHeapImageArray ) 2457builder .accessChainPushDescHeapIndex (builder .makeIntConstant (0 )); 2458 spv::Id heapOffset = makeHeapOffsetId (symbolType ); 2459if (heapOffset != spv::NoResult ) 2460builder .setAccessChainDescHeapBaseOffset (heapOffset ); 2461 } 2462 } 2463 2464#ifdef ENABLE_HLSL 2465// Process linkage-only nodes for any special additional interface work. 2466if (linkageOnly ) { 2467if (glslangIntermediate -> getHlslFunctionality1 ()) { 2468// Map implicit counter buffers to their originating buffers, which should have been 2469// seen by now, given earlier pruning of unused counters, and preservation of order 2470// of declaration. 2471if (symbol -> getType ().getQualifier ().isUniformOrBuffer ()) { 2472if (!glslangIntermediate -> hasCounterBufferName (symbol -> getName ())) { 2473// Save possible originating buffers for counter buffers, keyed by 2474// making the potential counter-buffer name. 2475 std::string keyName = symbol -> getName ().c_str (); 2476keyName = glslangIntermediate -> addCounterBufferName (keyName ); 2477counterOriginator [keyName ]= symbol ; 2478 }else { 2479// Handle a counter buffer, by finding the saved originating buffer. 2480 std::string keyName = symbol -> getName ().c_str (); 2481auto it = counterOriginator .find (keyName ); 2482if (it != counterOriginator .end ()) { 2483id = getSymbolId (it -> second ); 2484if (id != spv::NoResult ) { 2485 spv::Id counterId = getSymbolId (symbol ); 2486if (counterId != spv::NoResult ) { 2487builder .addExtension ("SPV_GOOGLE_hlsl_functionality1" ); 2488builder .addDecorationId (id , spv::Decoration ::HlslCounterBufferGOOGLE ,counterId ); 2489 } 2490 } 2491 } 2492 } 2493 } 2494 } 2495 } 2496#endif 2497} 2498 2499// Create a one-member heap block so image memory qualifiers can be expressed as 2500// legal member decorations instead of decorating an OpLoad result. 2501spv::Id TGlslangToSpvTraverser ::makeDescHeapImageArrayWrapperType (const glslang::TIntermSymbol & symbol , 2502 spv::Id arrayType ) 2503{ 2504const glslang::TQualifier & qualifier = symbol .getType ().getQualifier (); 2505 spv::Id memberOffset = builder .makeUintConstant (0 ); 2506const std::vector < spv::Id > members = {arrayType }; 2507const std::string wrapperName = std::string (symbol .getName ().c_str ())+ "_heap" ; 2508 spv::Id wrapperType = builder .makeStructType (members , {},wrapperName .c_str (), false); 2509 2510builder .addMemberName (wrapperType ,0 ,symbol .getName ().c_str ()); 2511builder .addDecoration (wrapperType , spv::Decoration ::Block ); 2512builder .addMemberDecorationIdEXT (wrapperType ,0 , spv::Decoration ::OffsetIdEXT , {memberOffset }); 2513 2514if (qualifier .isReadOnly ()) 2515builder .addMemberDecoration (wrapperType ,0 , spv::Decoration ::NonWritable ); 2516if (qualifier .isWriteOnly ()) 2517builder .addMemberDecoration (wrapperType ,0 , spv::Decoration ::NonReadable ); 2518 2519return wrapperType ; 2520} 2521 2522// Create new untyped access chain instruction to descriptor heap, based on EXT_descriptor_heap extension. 2523void TGlslangToSpvTraverser ::recordDescHeapAccessChainInfo (glslang::TIntermBinary * node ) 2524{ 2525// Descriptor heap indexing is represented separately from the normal access chain. 2526// Move the just-pushed heap index out of indexChain and into descHeapIndexChain. 2527if (node -> getQualifier ().layoutDescriptorHeap ) { 2528if (builder .hasAccessChainIndex ()) 2529builder .moveAccessChainIndexToDescHeapIndexChain (); 2530 } 2531 2532// Descriptor leaf nodes need the real resource type for later untyped loads. 2533// Block payload types need explicit caching because SpvBuilder intentionally 2534// does not deduplicate general OpTypeStruct declarations. 2535if (node -> getQualifier ().descriptorHeapDescriptorNode ) { 2536 glslang::TType nodeTy ; 2537nodeTy .shallowCopy (node -> getType ()); 2538 2539const bool useLeftDescriptorType = 2540node -> getLeft ()-> getType ().isArray ()&& 2541node -> getLeft ()-> getQualifier ().isUniformOrBuffer (); 2542 2543if (useLeftDescriptorType ) 2544nodeTy .shallowCopy (node -> getLeft ()-> getType ()); 2545 2546if (nodeTy .isArray ()) 2547nodeTy .clearArraySizes (); 2548nodeTy .getQualifier ().layoutDescriptorHeap = false; 2549 2550 spv::Id descType = spv::NoResult ; 2551if (nodeTy .isStruct ()) { 2552const glslang::TTypeList * descStruct = nodeTy .getStruct (); 2553auto cachedDescType = heapDescHeapBlockDescriptorTypes .find (descStruct ); 2554if (cachedDescType == heapDescHeapBlockDescriptorTypes .end ()) 2555cachedDescType = heapDescHeapBlockDescriptorTypes .emplace (descStruct ,convertGlslangToSpvType (nodeTy )).first ; 2556descType = cachedDescType -> second ; 2557 }else { 2558descType = convertGlslangToSpvType (nodeTy ); 2559 } 2560 2561 spv::StorageClass storageClass = TranslateStorageClass (nodeTy ); 2562if (nodeTy .getBasicType ()== glslang::EbtAccStruct ) 2563storageClass = spv::StorageClass ::UniformConstant ; 2564 2565builder .setAccessChainDescHeapDescriptorType (descType ,storageClass ,nodeTy .getQualifier ().isReadOnly (), 2566nodeTy .getQualifier ().isWriteOnly ()); 2567 } 2568} 2569 2570bool TGlslangToSpvTraverser ::visitBinary (glslang::TVisit /* visit */ , glslang::TIntermBinary * node ) 2571{ 2572builder .setDebugSourceLocation (node -> getLoc ().line ,node -> getLoc ().getFilename ()); 2573 2574SpecConstantOpModeGuard spec_constant_op_mode_setter (& builder ); 2575if (node -> getType ().getQualifier ().isSpecConstant ()) 2576spec_constant_op_mode_setter .turnOnSpecConstantOpMode (); 2577 2578// First, handle special cases 2579switch (node -> getOp ()) { 2580case glslang::EOpAssign : 2581case glslang::EOpAddAssign : 2582case glslang::EOpSubAssign : 2583case glslang::EOpMulAssign : 2584case glslang::EOpVectorTimesMatrixAssign : 2585case glslang::EOpVectorTimesScalarAssign : 2586case glslang::EOpMatrixTimesScalarAssign : 2587case glslang::EOpMatrixTimesMatrixAssign : 2588case glslang::EOpDivAssign : 2589case glslang::EOpModAssign : 2590case glslang::EOpAndAssign : 2591case glslang::EOpInclusiveOrAssign : 2592case glslang::EOpExclusiveOrAssign : 2593case glslang::EOpLeftShiftAssign : 2594case glslang::EOpRightShiftAssign : 2595// A bin-op assign "a += b" means the same thing as "a = a + b" 2596// where a is evaluated before b. For a simple assignment, GLSL 2597// says to evaluate the left before the right. So, always, left 2598// node then right node. 2599 { 2600// get the left l-value, save it away 2601builder .clearAccessChain (); 2602node -> getLeft ()-> traverse (this ); 2603 spv::Builder ::AccessChain lValue = builder .getAccessChain (); 2604 2605// evaluate the right 2606builder .clearAccessChain (); 2607node -> getRight ()-> traverse (this ); 2608 spv::Id rValue = accessChainLoad (node -> getRight ()-> getType ()); 2609 2610// reset line number for assignment 2611builder .setDebugSourceLocation (node -> getLoc ().line ,node -> getLoc ().getFilename ()); 2612 2613if (node -> getOp ()!= glslang::EOpAssign ) { 2614// the left is also an r-value 2615builder .setAccessChain (lValue ); 2616 spv::Id leftRValue = accessChainLoad (node -> getLeft ()-> getType ()); 2617 2618// do the operation 2619 spv::Builder ::AccessChain ::CoherentFlags coherentFlags = TranslateCoherent (node -> getLeft ()-> getType ()); 2620coherentFlags |=TranslateCoherent (node -> getRight ()-> getType ()); 2621OpDecorations decorations = {TranslatePrecisionDecoration (node -> getOperationPrecision ()), 2622TranslateNoContractionDecoration (node -> getType ().getQualifier ()), 2623TranslateNonUniformDecoration (coherentFlags ) }; 2624rValue = createBinaryOperation (node -> getOp (),decorations , 2625convertGlslangToSpvType (node -> getType ()),leftRValue ,rValue , 2626node -> getType ().getBasicType ()); 2627 2628// these all need their counterparts in createBinaryOperation() 2629assert (rValue != spv::NoResult ); 2630 } 2631 2632// store the result 2633builder .setAccessChain (lValue ); 2634multiTypeStore (node -> getLeft ()-> getType (),rValue ); 2635 2636// assignments are expressions having an rValue after they are evaluated... 2637builder .clearAccessChain (); 2638builder .setAccessChainRValue (rValue ); 2639 } 2640return false; 2641case glslang::EOpIndexDirect : 2642case glslang::EOpIndexDirectStruct : 2643 { 2644// Structure, array, matrix, or vector indirection with statically known index. 2645// Get the left part of the access chain. 2646node -> getLeft ()-> traverse (this ); 2647 2648// Add the next element in the chain 2649 2650const int glslangIndex = node -> getRight ()-> getAsConstantUnion ()-> getConstArray ()[0 ].getIConst (); 2651if (!node -> getLeft ()-> getType ().isArray ()&& 2652node -> getLeft ()-> getType ().isVector ()&& 2653node -> getOp ()== glslang::EOpIndexDirect ) { 2654// Swizzle is uniform so propagate uniform into access chain 2655 spv::Builder ::AccessChain ::CoherentFlags coherentFlags = TranslateCoherent (node -> getLeft ()-> getType ()); 2656coherentFlags .nonUniform = 0 ; 2657// This is essentially a hard-coded vector swizzle of size 1, 2658// so short circuit the access-chain stuff with a swizzle. 2659 std::vector < unsigned > swizzle ; 2660swizzle .push_back (glslangIndex ); 2661int dummySize ; 2662builder .accessChainPushSwizzle (swizzle ,convertGlslangToSpvType (node -> getLeft ()-> getType ()), 2663coherentFlags , 2664glslangIntermediate -> getBaseAlignmentScalar ( 2665node -> getLeft ()-> getType (),dummySize )); 2666 }else { 2667 2668// Load through a block reference is performed with a dot operator that 2669// is mapped to EOpIndexDirectStruct. When we get to the actual reference, 2670// do a load and reset the access chain. 2671if (node -> getLeft ()-> isReference ()&& 2672 !node -> getLeft ()-> getType ().isArray ()&& 2673node -> getOp ()== glslang::EOpIndexDirectStruct ) 2674 { 2675 spv::Id left = accessChainLoad (node -> getLeft ()-> getType ()); 2676builder .clearAccessChain (); 2677builder .setAccessChainLValue (left ); 2678 } 2679 2680int spvIndex = glslangIndex ; 2681if (node -> getLeft ()-> getBasicType ()== glslang::EbtBlock && 2682node -> getOp ()== glslang::EOpIndexDirectStruct ) 2683 { 2684// This may be, e.g., an anonymous block-member selection, which generally need 2685// index remapping due to hidden members in anonymous blocks. 2686const glslang::TTypeList * glslangMembers = node -> getLeft ()-> getType ().getStruct (); 2687if (memberRemapper .find (glslangMembers )!= memberRemapper .end ()) { 2688 std::vector < int >& remapper = memberRemapper [glslangMembers ]; 2689assert (remapper .size ()> 0 ); 2690spvIndex = remapper [glslangIndex ]; 2691 } 2692 } 2693 2694// Struct reference propagates uniform lvalue 2695 spv::Builder ::AccessChain ::CoherentFlags coherentFlags = 2696TranslateCoherent (node -> getLeft ()-> getType ()); 2697coherentFlags .nonUniform = 0 ; 2698 2699// normal case for indexing array or structure or block 2700if ((node -> getRight ()-> getType ().getBasicType ()== glslang::EbtUint && glslangIntermediate -> usingPromoteUint32Indices ())|| 2701node -> getRight ()-> getType ().contains64BitInt ()) { 2702int64_t idx = node -> getRight ()-> getType ().contains64BitInt () ? 2703node -> getRight ()-> getAsConstantUnion ()-> getConstArray ()[0 ].getI64Const () : 2704node -> getRight ()-> getAsConstantUnion ()-> getConstArray ()[0 ].getUConst (); 2705builder .accessChainPush (builder .makeInt64Constant (idx ), 2706coherentFlags , 2707node -> getLeft ()-> getType ().getBufferReferenceAlignment ()); 2708 2709 }else { 2710builder .accessChainPush (builder .makeIntConstant (spvIndex ), 2711coherentFlags , 2712node -> getLeft ()-> getType ().getBufferReferenceAlignment ()); 2713 } 2714// Add capabilities here for accessing PointSize and clip/cull distance. 2715// We have deferred generation of associated capabilities until now. 2716if (node -> getLeft ()-> getType ().isStruct ()&& !node -> getLeft ()-> getType ().isArray ()) 2717declareUseOfStructMember (* (node -> getLeft ()-> getType ().getStruct ()),glslangIndex ); 2718 2719// EXT_descriptor_heap 2720// Record untyped descriptor heap access info. 2721if (node -> getQualifier ().layoutDescriptorHeap ) { 2722recordDescHeapAccessChainInfo (node ); 2723 } 2724 } 2725 } 2726return false; 2727case glslang::EOpIndexIndirect : 2728 { 2729// Array, matrix, or vector indirection with variable index. 2730// Will use native SPIR-V access-chain for and array indirection; 2731// matrices are arrays of vectors, so will also work for a matrix. 2732// Will use the access chain's 'component' for variable index into a vector. 2733 2734// This adapter is building access chains left to right. 2735// Set up the access chain to the left. 2736node -> getLeft ()-> traverse (this ); 2737 2738// save it so that computing the right side doesn't trash it 2739 spv::Builder ::AccessChain partial = builder .getAccessChain (); 2740 2741// compute the next index in the chain 2742builder .clearAccessChain (); 2743node -> getRight ()-> traverse (this ); 2744 spv::Id index = accessChainLoad (node -> getRight ()-> getType ()); 2745 2746// Zero-extend smaller unsigned integer types for array indexing. 2747// SPIR-V OpAccessChain treats indices as signed, so we need to zero-extend 2748// unsigned types to preserve their values (signed types are fine as-is). 2749 spv::Id indexType = builder .getTypeId (index ); 2750if (builder .isUintType (indexType )&& builder .getScalarTypeWidth (indexType )< 32 ) { 2751// Zero-extend unsigned types to preserve their values 2752 spv::Id uintType = builder .makeUintType (32 ); 2753index = builder .createUnaryOp (spv::Op ::OpUConvert ,uintType ,index ); 2754 } 2755 2756addIndirectionIndexCapabilities (node -> getLeft ()-> getType (),node -> getRight ()-> getType ()); 2757 2758// restore the saved access chain 2759builder .setAccessChain (partial ); 2760 2761// Only if index is nonUniform should we propagate nonUniform into access chain 2762 spv::Builder ::AccessChain ::CoherentFlags index_flags = TranslateCoherent (node -> getRight ()-> getType ()); 2763 spv::Builder ::AccessChain ::CoherentFlags coherent_flags = TranslateCoherent (node -> getLeft ()-> getType ()); 2764coherent_flags .nonUniform = index_flags .nonUniform ; 2765 2766if (!node -> getLeft ()-> getType ().isArray ()&& node -> getLeft ()-> getType ().isVector ()) { 2767int dummySize ; 2768builder .accessChainPushComponent ( 2769index ,convertGlslangToSpvType (node -> getLeft ()-> getType ()),coherent_flags , 2770glslangIntermediate -> getBaseAlignmentScalar (node -> getLeft ()-> getType (), 2771dummySize )); 2772 }else { 2773if (glslangIntermediate -> usingPromoteUint32Indices ()&& 2774node -> getRight ()-> getType ().getBasicType ()== glslang::EbtUint ) { 2775index = createIntWidthConversion (index ,0 ,builder .makeIntegerType (64 , true), glslang::EbtInt64 ,node -> getRight ()-> getType ().getBasicType ()); 2776 } 2777 2778builder .accessChainPush (index ,coherent_flags , 2779node -> getLeft ()-> getType ().getBufferReferenceAlignment ()); 2780 } 2781 2782// EXT_descriptor_heap 2783// Record untyped descriptor heap access info. 2784if (node -> getQualifier ().layoutDescriptorHeap ) { 2785recordDescHeapAccessChainInfo (node ); 2786 } 2787 } 2788return false; 2789case glslang::EOpVectorSwizzle : 2790 { 2791node -> getLeft ()-> traverse (this ); 2792 std::vector < unsigned > swizzle ; 2793convertSwizzle (* node -> getRight ()-> getAsAggregate (),swizzle ); 2794int dummySize ; 2795builder .accessChainPushSwizzle (swizzle ,convertGlslangToSpvType (node -> getLeft ()-> getType ()), 2796TranslateCoherent (node -> getLeft ()-> getType ()), 2797glslangIntermediate -> getBaseAlignmentScalar (node -> getLeft ()-> getType (), 2798dummySize )); 2799 } 2800return false; 2801case glslang::EOpMatrixSwizzle : 2802logger -> missingFunctionality ("matrix swizzle" ); 2803return true; 2804case glslang::EOpLogicalOr : 2805case glslang::EOpLogicalAnd : 2806 { 2807 2808// These may require short circuiting, but can sometimes be done as straight 2809// binary operations. The right operand must be short circuited if it has 2810// side effects, and should probably be if it is complex. 2811if (node -> getType ().getQualifier ().isSpecConstant ()|| isTrivial (node -> getRight ()-> getAsTyped ())) 2812break ;// handle below as a normal binary operation 2813// otherwise, we need to do dynamic short circuiting on the right operand 2814 spv::Id result = createShortCircuit (node -> getOp (),* node -> getLeft ()-> getAsTyped (), 2815* node -> getRight ()-> getAsTyped ()); 2816builder .clearAccessChain (); 2817builder .setAccessChainRValue (result ); 2818 } 2819return false; 2820default : 2821break ; 2822 } 2823 2824// Assume generic binary op... 2825 2826// get right operand 2827builder .clearAccessChain (); 2828node -> getLeft ()-> traverse (this ); 2829 spv::Id left = accessChainLoad (node -> getLeft ()-> getType ()); 2830 2831// get left operand 2832builder .clearAccessChain (); 2833node -> getRight ()-> traverse (this ); 2834 spv::Id right = accessChainLoad (node -> getRight ()-> getType ()); 2835 2836// get result 2837OpDecorations decorations = {TranslatePrecisionDecoration (node -> getOperationPrecision ()), 2838TranslateNoContractionDecoration (node -> getType ().getQualifier ()), 2839TranslateNonUniformDecoration (node -> getType ().getQualifier ()) }; 2840 spv::Id result = createBinaryOperation (node -> getOp (),decorations , 2841convertGlslangToSpvType (node -> getType ()),left ,right , 2842node -> getLeft ()-> getType ().getBasicType ()); 2843 2844builder .clearAccessChain (); 2845if (!result ) { 2846logger -> missingFunctionality ("unknown glslang binary operation" ); 2847return true;// pick up a child as the place-holder result 2848 }else { 2849builder .setAccessChainRValue (result ); 2850return false; 2851 } 2852} 2853 2854spv::Id TGlslangToSpvTraverser ::convertLoadedBoolInUniformToUint (const glslang::TType & type , 2855 spv::Id nominalTypeId , 2856 spv::Id loadedId ) 2857{ 2858if (builder .isScalarType (nominalTypeId )) { 2859// Conversion for bool 2860 spv::Id boolType = builder .makeBoolType (); 2861if (nominalTypeId != boolType ) 2862return builder .createBinOp (spv::Op ::OpINotEqual ,boolType ,loadedId ,builder .makeUintConstant (0 )); 2863 }else if (builder .isVectorType (nominalTypeId )) { 2864// Conversion for bvec 2865int vecSize = builder .getNumTypeComponents (nominalTypeId ); 2866 spv::Id bvecType = builder .makeVectorType (builder .makeBoolType (),vecSize ); 2867if (nominalTypeId != bvecType ) 2868loadedId = builder .createBinOp (spv::Op ::OpINotEqual ,bvecType ,loadedId , 2869makeSmearedConstant (builder .makeUintConstant (0 ),vecSize )); 2870 }else if (builder .isArrayType (nominalTypeId )) { 2871// Conversion for bool array 2872 spv::Id boolArrayTypeId = convertGlslangToSpvType (type ); 2873if (nominalTypeId != boolArrayTypeId ) 2874 { 2875// Use OpCopyLogical from SPIR-V 1.4 if available. 2876if (glslangIntermediate -> getSpv ().spv >= glslang::EShTargetSpv_1_4 ) 2877return builder .createUnaryOp (spv::Op ::OpCopyLogical ,boolArrayTypeId ,loadedId ); 2878 2879 glslang::TType glslangElementType (type ,0 ); 2880 spv::Id elementNominalTypeId = builder .getContainedTypeId (nominalTypeId ); 2881 std::vector < spv::Id > constituents ; 2882for (int index = 0 ;index < type .getOuterArraySize ();++ index ) { 2883// get the element 2884 spv::Id elementValue = builder .createCompositeExtract (loadedId ,elementNominalTypeId ,index ); 2885 2886// recursively convert it 2887 spv::Id elementConvertedValue = convertLoadedBoolInUniformToUint (glslangElementType ,elementNominalTypeId ,elementValue ); 2888constituents .push_back (elementConvertedValue ); 2889 } 2890return builder .createCompositeConstruct (boolArrayTypeId ,constituents ); 2891 } 2892 } 2893 2894return loadedId ; 2895} 2896 2897// Figure out what, if any, type changes are needed when accessing a specific built-in. 2898// Returns <the type SPIR-V requires for declarion, the type to translate to on use>. 2899// Also see comment for 'forceType', regarding tracking SPIR-V-required types. 2900std::pair < spv::Id , spv::Id > TGlslangToSpvTraverser ::getForcedType (glslang::TBuiltInVariable glslangBuiltIn , 2901const glslang::TType & glslangType ) 2902{ 2903switch (glslangBuiltIn ) 2904 { 2905case glslang::EbvSubGroupEqMask : 2906case glslang::EbvSubGroupGeMask : 2907case glslang::EbvSubGroupGtMask : 2908case glslang::EbvSubGroupLeMask : 2909case glslang::EbvSubGroupLtMask : { 2910// these require changing a 64-bit scaler -> a vector of 32-bit components 2911if (glslangType .isVector ()) 2912break ; 2913 spv::Id ivec4_type = builder .makeVectorType (builder .makeUintType (32 ),4 ); 2914 spv::Id uint64_type = builder .makeUintType (64 ); 2915 std::pair < spv::Id , spv::Id > ret (ivec4_type ,uint64_type ); 2916return ret ; 2917 } 2918// There are no SPIR-V builtins defined for these and map onto original non-transposed 2919// builtins. During visitBinary we insert a transpose 2920case glslang::EbvWorldToObject3x4 : 2921case glslang::EbvObjectToWorld3x4 : { 2922 spv::Id mat43 = builder .makeMatrixType (builder .makeFloatType (32 ),4 ,3 ); 2923 spv::Id mat34 = builder .makeMatrixType (builder .makeFloatType (32 ),3 ,4 ); 2924 std::pair < spv::Id , spv::Id > ret (mat43 ,mat34 ); 2925return ret ; 2926 } 2927default : 2928break ; 2929 } 2930 2931 std::pair < spv::Id , spv::Id > ret (spv::NoType , spv::NoType ); 2932return ret ; 2933} 2934 2935// For an object previously identified (see getForcedType() and forceType) 2936// as needing type translations, do the translation needed for a load, turning 2937// an L-value into in R-value. 2938spv::Id TGlslangToSpvTraverser ::translateForcedType (spv::Id object ,const glslang::TType & type ) 2939{ 2940const auto forceIt = forceType .find (object ); 2941if (forceIt == forceType .end ()) 2942return object ; 2943 2944 spv::Id desiredTypeId = forceIt -> second ; 2945 spv::Id objectTypeId = builder .getTypeId (object ); 2946assert (builder .isPointerType (objectTypeId )); 2947objectTypeId = builder .getContainedTypeId (objectTypeId ); 2948 2949// The load performed below needs to preserve the same Volatile/Coherent memory access 2950// that TGlslangToSpvTraverser::accessChainLoad() would apply 2951 spv::Builder ::AccessChain ::CoherentFlags coherentFlags = TranslateCoherent (type ); 2952 spv::MemoryAccessMask accessMask = 2953 spv::MemoryAccessMask (TranslateMemoryAccess (coherentFlags )& ~spv::MemoryAccessMask ::MakePointerAvailableKHR ); 2954 spv::Scope memoryScope = TranslateMemoryScope (coherentFlags ); 2955 2956if (builder .isVectorType (objectTypeId )&& 2957builder .getScalarTypeWidth (builder .getContainedTypeId (objectTypeId ))== 32 ) { 2958if (builder .getScalarTypeWidth (desiredTypeId )== 64 ) { 2959// handle 32-bit v.xy* -> 64-bit 2960builder .clearAccessChain (); 2961builder .setAccessChainLValue (object ); 2962object = builder .accessChainLoad (spv::NoPrecision , spv::Decoration ::Max , spv::Decoration ::Max ,objectTypeId , 2963accessMask ,memoryScope ); 2964 std::vector < spv::Id > components ; 2965components .push_back (builder .createCompositeExtract (object ,builder .getContainedTypeId (objectTypeId ),0 )); 2966components .push_back (builder .createCompositeExtract (object ,builder .getContainedTypeId (objectTypeId ),1 )); 2967 2968 spv::Id vecType = builder .makeVectorType (builder .getContainedTypeId (objectTypeId ),2 ); 2969return builder .createUnaryOp (spv::Op ::OpBitcast ,desiredTypeId , 2970builder .createCompositeConstruct (vecType ,components )); 2971 }else { 2972logger -> missingFunctionality ("forcing 32-bit vector type to non 64-bit scalar" ); 2973 } 2974 }else if (builder .isMatrixType (objectTypeId )) { 2975// There are no SPIR-V builtins defined for 3x4 variants of ObjectToWorld/WorldToObject 2976// and we insert a transpose after loading the original non-transposed builtins 2977builder .clearAccessChain (); 2978builder .setAccessChainLValue (object ); 2979object = builder .accessChainLoad (spv::NoPrecision , spv::Decoration ::Max , spv::Decoration ::Max ,objectTypeId , 2980accessMask ,memoryScope ); 2981return builder .createUnaryOp (spv::Op ::OpTranspose ,desiredTypeId ,object ); 2982 2983 }else { 2984logger -> missingFunctionality ("forcing non 32-bit vector type" ); 2985 } 2986 2987return object ; 2988} 2989 2990bool TGlslangToSpvTraverser ::visitUnary (glslang::TVisit /* visit */ , glslang::TIntermUnary * node ) 2991{ 2992builder .setDebugSourceLocation (node -> getLoc ().line ,node -> getLoc ().getFilename ()); 2993 2994SpecConstantOpModeGuard spec_constant_op_mode_setter (& builder ); 2995if (node -> getType ().getQualifier ().isSpecConstant ()) 2996spec_constant_op_mode_setter .turnOnSpecConstantOpMode (); 2997 2998 spv::Id result = spv::NoResult ; 2999 3000// try texturing first 3001result = createImageTextureFunctionCall (node ); 3002if (result != spv::NoResult ) { 3003builder .clearAccessChain (); 3004builder .setAccessChainRValue (result ); 3005 3006return false;// done with this node 3007 } 3008 3009// Non-texturing. 3010 3011if (node -> getOp ()== glslang::EOpArrayLength ) { 3012// Quite special; won't want to evaluate the operand. 3013 3014// Currently, the front-end does not allow .length() on an array until it is sized, 3015// except for the last block membeor of an SSBO. 3016// TODO: If this changes, link-time sized arrays might show up here, and need their 3017// size extracted. 3018 3019// Normal .length() would have been constant folded by the front-end. 3020// So, this has to be block.lastMember.length(). 3021// SPV wants "block" and member number as the operands, go get them. 3022 3023uint32_t bits = node -> getType ().contains64BitInt () ?64 :32 ; 3024 3025 spv::Id length ; 3026if (node -> getOperand ()-> getType ().isCoopMat ()) { 3027 spv::Id typeId = convertGlslangToSpvType (node -> getOperand ()-> getType ()); 3028assert (builder .isCooperativeMatrixType (typeId )); 3029 3030if (node -> getOperand ()-> getType ().isCoopMatKHR ()) { 3031length = builder .createCooperativeMatrixLengthKHR (typeId ); 3032 }else { 3033spec_constant_op_mode_setter .turnOnSpecConstantOpMode (); 3034length = builder .createCooperativeMatrixLengthNV (typeId ); 3035 } 3036 }else if (node -> getOperand ()-> getType ().isCoopVecOrLongVector ()&& 3037 !node -> getOperand ()-> getType ().isArray ()) { 3038// Long/cooperative vectors support v.length() as a compile-time 3039// component count. For arrays of such vectors, .length() must use 3040// OpArrayLength and not the vector-component path. 3041 spv::Id typeId = convertGlslangToSpvType (node -> getOperand ()-> getType ()); 3042if (builder .isCooperativeVectorType (typeId )) { 3043length = builder .getCooperativeVectorNumComponents (typeId ); 3044 }else { 3045length = builder .makeIntConstant (builder .getNumTypeConstituents (typeId )); 3046 } 3047 }else { 3048 glslang::TIntermTyped * block = node -> getOperand ()-> getAsBinaryNode ()-> getLeft (); 3049block -> traverse (this ); 3050unsigned int member = node -> getOperand ()-> getAsBinaryNode ()-> getRight ()-> getAsConstantUnion () 3051-> getConstArray ()[0 ].getUConst (); 3052length = builder .createArrayLength (builder .accessChainGetLValue (),member ,bits ); 3053 } 3054 3055// GLSL semantics say the result of .length() is an int, while SPIR-V says 3056// signedness must be 0. So, convert from SPIR-V unsigned back to GLSL's 3057// AST expectation of a signed result. 3058if (glslangIntermediate -> getSource ()== glslang::EShSourceGlsl ) { 3059if (builder .isInSpecConstCodeGenMode ()) { 3060length = builder .createBinOp (spv::Op ::OpIAdd ,builder .makeIntType (bits ),length ,builder .makeIntConstant (0 )); 3061 }else { 3062length = builder .createUnaryOp (spv::Op ::OpBitcast ,builder .makeIntType (bits ),length ); 3063 } 3064 } 3065 3066builder .clearAccessChain (); 3067builder .setAccessChainRValue (length ); 3068 3069return false; 3070 } 3071 3072// Force variable declaration - Debug Mode Only 3073if (node -> getOp ()== glslang::EOpDeclare ) { 3074builder .clearAccessChain (); 3075node -> getOperand ()-> traverse (this ); 3076builder .clearAccessChain (); 3077return false; 3078 } 3079 3080// Start by evaluating the operand 3081 3082// Does it need a swizzle inversion? If so, evaluation is inverted; 3083// operate first on the swizzle base, then apply the swizzle. 3084 spv::Id invertedType = spv::NoType ; 3085auto resultType = [& invertedType ,& node ,this ](){return invertedType != spv::NoType ? 3086invertedType :convertGlslangToSpvType (node -> getType ()); }; 3087if (node -> getOp ()== glslang::EOpInterpolateAtCentroid ) 3088invertedType = getInvertedSwizzleType (* node -> getOperand ()); 3089 3090builder .clearAccessChain (); 3091TIntermNode * operandNode ; 3092if (invertedType != spv::NoType ) 3093operandNode = node -> getOperand ()-> getAsBinaryNode ()-> getLeft (); 3094else 3095operandNode = node -> getOperand (); 3096 3097operandNode -> traverse (this ); 3098 3099 spv::Id operand = spv::NoResult ; 3100 3101 spv::Builder ::AccessChain ::CoherentFlags lvalueCoherentFlags ; 3102 3103const auto hitObjectOpsWithLvalue = [](glslang::TOperator op ) { 3104switch (op ) { 3105case glslang::EOpReorderThreadNV : 3106case glslang::EOpHitObjectGetCurrentTimeNV : 3107case glslang::EOpHitObjectGetHitKindNV : 3108case glslang::EOpHitObjectGetPrimitiveIndexNV : 3109case glslang::EOpHitObjectGetGeometryIndexNV : 3110case glslang::EOpHitObjectGetInstanceIdNV : 3111case glslang::EOpHitObjectGetInstanceCustomIndexNV : 3112case glslang::EOpHitObjectGetObjectRayDirectionNV : 3113case glslang::EOpHitObjectGetObjectRayOriginNV : 3114case glslang::EOpHitObjectGetWorldRayDirectionNV : 3115case glslang::EOpHitObjectGetWorldRayOriginNV : 3116case glslang::EOpHitObjectGetWorldToObjectNV : 3117case glslang::EOpHitObjectGetObjectToWorldNV : 3118case glslang::EOpHitObjectGetRayTMaxNV : 3119case glslang::EOpHitObjectGetRayTMinNV : 3120case glslang::EOpHitObjectIsEmptyNV : 3121case glslang::EOpHitObjectIsHitNV : 3122case glslang::EOpHitObjectIsMissNV : 3123case glslang::EOpHitObjectRecordEmptyNV : 3124case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV : 3125case glslang::EOpHitObjectGetShaderRecordBufferHandleNV : 3126case glslang::EOpHitObjectGetClusterIdNV : 3127case glslang::EOpHitObjectGetSpherePositionNV : 3128case glslang::EOpHitObjectGetSphereRadiusNV : 3129case glslang::EOpHitObjectIsSphereHitNV : 3130case glslang::EOpHitObjectIsLSSHitNV : 3131case glslang::EOpReorderThreadEXT : 3132case glslang::EOpHitObjectGetCurrentTimeEXT : 3133case glslang::EOpHitObjectGetHitKindEXT : 3134case glslang::EOpHitObjectGetPrimitiveIndexEXT : 3135case glslang::EOpHitObjectGetGeometryIndexEXT : 3136case glslang::EOpHitObjectGetInstanceIdEXT : 3137case glslang::EOpHitObjectGetInstanceCustomIndexEXT : 3138case glslang::EOpHitObjectGetObjectRayDirectionEXT : 3139case glslang::EOpHitObjectGetObjectRayOriginEXT : 3140case glslang::EOpHitObjectGetWorldRayDirectionEXT : 3141case glslang::EOpHitObjectGetWorldRayOriginEXT : 3142case glslang::EOpHitObjectGetWorldToObjectEXT : 3143case glslang::EOpHitObjectGetObjectToWorldEXT : 3144case glslang::EOpHitObjectGetRayTMaxEXT : 3145case glslang::EOpHitObjectGetRayTMinEXT : 3146case glslang::EOpHitObjectGetRayFlagsEXT : 3147case glslang::EOpHitObjectIsEmptyEXT : 3148case glslang::EOpHitObjectIsHitEXT : 3149case glslang::EOpHitObjectIsMissEXT : 3150case glslang::EOpHitObjectRecordEmptyEXT : 3151case glslang::EOpHitObjectGetShaderBindingTableRecordIndexEXT : 3152case glslang::EOpHitObjectGetShaderRecordBufferHandleEXT : 3153return true; 3154default : 3155return false; 3156 } 3157 }; 3158 3159if (node -> getOp ()== glslang::EOpAtomicCounterIncrement || 3160node -> getOp ()== glslang::EOpAtomicCounterDecrement || 3161node -> getOp ()== glslang::EOpAtomicCounter || 3162 (node -> getOp ()== glslang::EOpInterpolateAtCentroid && 3163glslangIntermediate -> getSource ()!= glslang::EShSourceHlsl )|| 3164node -> getOp ()== glslang::EOpRayQueryProceed || 3165node -> getOp ()== glslang::EOpRayQueryGetRayTMin || 3166node -> getOp ()== glslang::EOpRayQueryGetRayFlags || 3167node -> getOp ()== glslang::EOpRayQueryGetWorldRayOrigin || 3168node -> getOp ()== glslang::EOpRayQueryGetWorldRayDirection || 3169node -> getOp ()== glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque || 3170node -> getOp ()== glslang::EOpRayQueryTerminate || 3171node -> getOp ()== glslang::EOpRayQueryConfirmIntersection || 3172 (node -> getOp ()== glslang::EOpSpirvInst && operandNode -> getAsTyped ()-> getQualifier ().isSpirvByReference ())|| 3173hitObjectOpsWithLvalue (node -> getOp ())) { 3174operand = builder .accessChainGetLValue ();// Special case l-value operands 3175lvalueCoherentFlags = builder .getAccessChain ().coherentFlags ; 3176lvalueCoherentFlags |=TranslateCoherent (operandNode -> getAsTyped ()-> getType ()); 3177 }else if (operandNode -> getAsTyped ()-> getQualifier ().isSpirvLiteral ()) { 3178// Will be translated to a literal value, make a placeholder here 3179operand = spv::NoResult ; 3180 }else { 3181operand = accessChainLoad (node -> getOperand ()-> getType ()); 3182 } 3183 3184OpDecorations decorations = {TranslatePrecisionDecoration (node -> getOperationPrecision ()), 3185TranslateNoContractionDecoration (node -> getType ().getQualifier ()), 3186TranslateNonUniformDecoration (node -> getType ().getQualifier ()) }; 3187 3188// it could be a conversion 3189if (!result ) { 3190bool sameUse = !node -> getType ().isCoopMatKHR ()|| !node -> getOperand ()-> getAsTyped ()-> getType ().isCoopMatKHR ()|| 3191node -> getAsTyped ()-> getType ().sameCoopMatUse (node -> getOperand ()-> getAsTyped ()-> getType ()); 3192result = createConversion (node -> getOp (),decorations ,resultType (),operand , 3193node -> getType ().getBasicType (),node -> getOperand ()-> getBasicType (),sameUse ); 3194 } 3195 3196// if not, then possibly an operation 3197if (!result ) 3198result = createUnaryOperation (node -> getOp (),decorations ,resultType (),operand , 3199node -> getOperand ()-> getBasicType (),lvalueCoherentFlags ,node -> getType ()); 3200 3201// it could be attached to a SPIR-V intruction 3202if (!result ) { 3203if (node -> getOp ()== glslang::EOpSpirvInst ) { 3204const auto & spirvInst = node -> getSpirvInstruction (); 3205 spv::IdImmediate idImmOp = {true,operand }; 3206if (operandNode -> getAsTyped ()-> getQualifier ().isSpirvLiteral ()) { 3207// Translate the constant to a literal value 3208 std::vector < unsigned > literals ; 3209 glslang::TVector < const glslang::TIntermConstantUnion *> constants ; 3210constants .push_back (operandNode -> getAsConstantUnion ()); 3211TranslateLiterals (constants ,literals ); 3212idImmOp = {false,literals [0 ]}; 3213 } 3214 3215if (spirvInst .set == "" ) { 3216if (node -> getBasicType ()== glslang::EbtVoid ) 3217builder .createNoResultOp (static_cast < spv::Op > (spirvInst .id ), {idImmOp }); 3218else 3219result = builder .createOp (static_cast < spv::Op > (spirvInst .id ),resultType (), {idImmOp }); 3220 }else { 3221result = builder .createBuiltinCall ( 3222resultType (),spirvInst .set == "GLSL.std.450" ?stdBuiltins :getExtBuiltins (spirvInst .set .c_str ()), 3223spirvInst .id , {idImmOp }); 3224 } 3225 3226if (node -> getBasicType ()== glslang::EbtVoid ) 3227return false;// done with this node 3228 } 3229 } 3230 3231if (result ) { 3232if (invertedType ) { 3233result = createInvertedSwizzle (decorations .precision ,* node -> getOperand (),result ); 3234decorations .addNonUniform (builder ,result ); 3235 } 3236 3237builder .clearAccessChain (); 3238builder .setAccessChainRValue (result ); 3239 3240return false;// done with this node 3241 } 3242 3243// it must be a special case, check... 3244switch (node -> getOp ()) { 3245case glslang::EOpPostIncrement : 3246case glslang::EOpPostDecrement : 3247case glslang::EOpPreIncrement : 3248case glslang::EOpPreDecrement : 3249 { 3250// we need the integer value "1" or the floating point "1.0" to add/subtract 3251 spv::Id one = 0 ; 3252if (node -> getBasicType ()== glslang::EbtFloat ) 3253one = builder .makeFloatConstant (1.0F ); 3254else if (node -> getBasicType ()== glslang::EbtDouble ) 3255one = builder .makeDoubleConstant (1.0 ); 3256else if (node -> getBasicType ()== glslang::EbtFloat16 ) 3257one = builder .makeFloat16Constant (1.0F ); 3258else if (node -> getBasicType ()== glslang::EbtBFloat16 ) 3259one = builder .makeBFloat16Constant (1.0F ); 3260else if (node -> getBasicType ()== glslang::EbtFloatE5M2 ) 3261one = builder .makeFloatE5M2Constant (1.0F ); 3262else if (node -> getBasicType ()== glslang::EbtFloatE4M3 ) 3263one = builder .makeFloatE4M3Constant (1.0F ); 3264else if (node -> getBasicType ()== glslang::EbtFloatE2M1 ) 3265one = builder .makeFloatE2M1Constant (1.0F ); 3266else if (node -> getBasicType ()== glslang::EbtFloatE3M2 ) 3267one = builder .makeFloatE3M2Constant (1.0F ); 3268else if (node -> getBasicType ()== glslang::EbtFloatE2M3 ) 3269one = builder .makeFloatE2M3Constant (1.0F ); 3270else if (node -> getBasicType ()== glslang::EbtFloatUE8M0 ) 3271one = builder .makeFloatUE8M0Constant (1.0F ); 3272else if (node -> getBasicType ()== glslang::EbtFloatMXINT8 ) 3273one = builder .makeFloatMXINT8Constant (1.0F ); 3274else if (node -> getBasicType ()== glslang::EbtInt8 || node -> getBasicType ()== glslang::EbtUint8 ) 3275one = builder .makeInt8Constant (1 ); 3276else if (node -> getBasicType ()== glslang::EbtInt16 || node -> getBasicType ()== glslang::EbtUint16 ) 3277one = builder .makeInt16Constant (1 ); 3278else if (node -> getBasicType ()== glslang::EbtInt64 || node -> getBasicType ()== glslang::EbtUint64 ) 3279one = builder .makeInt64Constant (1 ); 3280else 3281one = builder .makeIntConstant (1 ); 3282 glslang::TOperator op ; 3283if (node -> getOp ()== glslang::EOpPreIncrement || 3284node -> getOp ()== glslang::EOpPostIncrement ) 3285op = glslang::EOpAdd ; 3286else 3287op = glslang::EOpSub ; 3288 3289 spv::Id result = createBinaryOperation (op ,decorations , 3290convertGlslangToSpvType (node -> getType ()),operand ,one , 3291node -> getType ().getBasicType ()); 3292assert (result != spv::NoResult ); 3293 3294// The result of operation is always stored, but conditionally the 3295// consumed result. The consumed result is always an r-value. 3296accessChainStore (node -> getOperand ()-> getType (),result ); 3297builder .clearAccessChain (); 3298if (node -> getOp ()== glslang::EOpPreIncrement || 3299node -> getOp ()== glslang::EOpPreDecrement ) 3300builder .setAccessChainRValue (result ); 3301else 3302builder .setAccessChainRValue (operand ); 3303 } 3304 3305return false; 3306 3307case glslang::EOpAssumeEXT : 3308builder .addCapability (spv::Capability ::ExpectAssumeKHR ); 3309builder .addExtension (spv::E_SPV_KHR_expect_assume ); 3310builder .createNoResultOp (spv::Op ::OpAssumeTrueKHR ,operand ); 3311return false; 3312case glslang::EOpEmitStreamVertex : 3313builder .createNoResultOp (spv::Op ::OpEmitStreamVertex ,operand ); 3314return false; 3315case glslang::EOpEndStreamPrimitive : 3316builder .createNoResultOp (spv::Op ::OpEndStreamPrimitive ,operand ); 3317return false; 3318case glslang::EOpRayQueryTerminate : 3319builder .createNoResultOp (spv::Op ::OpRayQueryTerminateKHR ,operand ); 3320return false; 3321case glslang::EOpRayQueryConfirmIntersection : 3322builder .createNoResultOp (spv::Op ::OpRayQueryConfirmIntersectionKHR ,operand ); 3323return false; 3324case glslang::EOpReorderThreadNV : 3325builder .createNoResultOp (spv::Op ::OpReorderThreadWithHitObjectNV ,operand ); 3326return false; 3327case glslang::EOpReorderThreadEXT : 3328builder .createNoResultOp (spv::Op ::OpReorderThreadWithHitObjectEXT ,operand ); 3329return false; 3330case glslang::EOpHitObjectRecordEmptyNV : 3331builder .createNoResultOp (spv::Op ::OpHitObjectRecordEmptyNV ,operand ); 3332return false; 3333case glslang::EOpHitObjectRecordEmptyEXT : 3334builder .createNoResultOp (spv::Op ::OpHitObjectRecordEmptyEXT ,operand ); 3335return false; 3336 3337case glslang::EOpCreateTensorLayoutNV : 3338result = builder .createOp (spv::Op ::OpCreateTensorLayoutNV ,resultType (), std::vector < spv::Id > {}); 3339builder .clearAccessChain (); 3340builder .setAccessChainRValue (result ); 3341return false; 3342 3343case glslang::EOpCreateTensorViewNV : 3344result = builder .createOp (spv::Op ::OpCreateTensorViewNV ,resultType (), std::vector < spv::Id > {}); 3345builder .clearAccessChain (); 3346builder .setAccessChainRValue (result ); 3347return false; 3348 3349default : 3350logger -> missingFunctionality ("unknown glslang unary" ); 3351return true;// pick up operand as placeholder result 3352 } 3353} 3354 3355// Construct a composite object, recursively copying members if their types don't match 3356spv::Id TGlslangToSpvTraverser ::createCompositeConstruct (spv::Id resultTypeId , std::vector < spv::Id > constituents ) 3357{ 3358for (int c = 0 ;c < (int )constituents .size ();++ c ) { 3359 spv::Id & constituent = constituents [c ]; 3360 spv::Id lType = builder .getContainedTypeId (resultTypeId ,c ); 3361 spv::Id rType = builder .getTypeId (constituent ); 3362if (lType != rType ) { 3363if (glslangIntermediate -> getSpv ().spv >= glslang::EShTargetSpv_1_4 ) { 3364constituent = builder .createUnaryOp (spv::Op ::OpCopyLogical ,lType ,constituent ); 3365 }else if (builder .isStructType (rType )) { 3366 std::vector < spv::Id > rTypeConstituents ; 3367int numrTypeConstituents = builder .getNumTypeConstituents (rType ); 3368for (int i = 0 ;i < numrTypeConstituents ;++ i ) { 3369rTypeConstituents .push_back (builder .createCompositeExtract (constituent , 3370builder .getContainedTypeId (rType ,i ),i )); 3371 } 3372constituents [c ]= createCompositeConstruct (lType ,rTypeConstituents ); 3373 }else { 3374assert (builder .isArrayType (rType )); 3375 std::vector < spv::Id > rTypeConstituents ; 3376int numrTypeConstituents = builder .getNumTypeConstituents (rType ); 3377 3378 spv::Id elementRType = builder .getContainedTypeId (rType ); 3379for (int i = 0 ;i < numrTypeConstituents ;++ i ) { 3380rTypeConstituents .push_back (builder .createCompositeExtract (constituent ,elementRType ,i )); 3381 } 3382constituents [c ]= createCompositeConstruct (lType ,rTypeConstituents ); 3383 } 3384 } 3385 } 3386return builder .createCompositeConstruct (resultTypeId ,constituents ); 3387} 3388 3389void TGlslangToSpvTraverser ::createAbortEXT (const glslang::TIntermSequence & glslangOperands ) 3390{ 3391bool isEmptyMsg = 3392glslangOperands .empty ()|| 3393glslangOperands [0 ]-> getAsConstantUnion ()-> getConstArray ()[0 ].getSConst ()-> empty (); 3394// Add Capability and extensions. 3395builder .addCapability (spv::Capability ::AbortKHR ); 3396builder .addCapability (spv::Capability ::ConstantDataKHR ); 3397builder .addExtension (spv::E_SPV_KHR_constant_data ); 3398builder .addExtension (spv::E_SPV_KHR_abort ); 3399 3400// 1. Get the message string. 3401const auto emptyMsg = glslang::TString ("\0" ); 3402const glslang::TString * msg = 3403isEmptyMsg ?& emptyMsg :glslangOperands [0 ]-> getAsConstantUnion ()-> getConstArray ()[0 ].getSConst (); 3404// 2. Prepare to construct message struct variable, record members' types, data and offsets. 3405 std::vector < int > structMemberOffsets ; 3406 std::vector < spv::Id > structMemberType ; 3407 std::vector < spv::Id > structLoadMemberType ; 3408 std::vector < spv::Id > structMemberData ; 3409structMemberOffsets .push_back (0 ); 3410auto charType = builder .makeIntType (8 ); 3411// 2.1 Get string's length. 3412// If not an empty string, \0 is the final character used for padding. 3413unsigned int msgLen = isEmptyMsg ?1 :msg -> size ()+ 1 ; 3414unsigned int paddingSize = (4 - msgLen %4 ) %4 ; 3415msgLen = msgLen + paddingSize ; 3416 spv::Id constLen = builder .makeUintConstant (msgLen ); 3417// 2.2 Get string's array types. The string needs one type per role: the constant data is 3418// tightly packed, so its result type must not carry ArrayStride, while the message 3419// struct member it feeds does need an explicit layout. One type cannot do both, so 3420// make a tightly packed type for the constant and a laid out type for the member. 3421// Asking makeArrayType for a stride is what keeps the laid out one a distinct type. 3422auto msgConstDataType = builder .makeArrayType (charType ,constLen ,0 ); 3423auto msgArrType = builder .makeArrayType (charType ,constLen ,1 ); 3424// 2.3 Add string constant data. 3425// SPV_KHR_abort does not mandate a form for the message; it is emitted as plain 3426// constant data. Its example uses a specialization constant so that an application 3427// can swap a format modifier at specialization time, but that needs a SpecId the 3428// shader author controls, so it is not something to apply automatically here. 3429auto msgConstData = builder .createConstData (spv::Op ::OpConstantDataKHR ,msgConstDataType , {msg -> c_str ()}); 3430// 2.4 Add decorations for this string. Both types describe the same UTF encoded 3431// characters, so both are marked as such; only the laid out one takes the stride. 3432builder .addDecoration (msgConstDataType , spv::Decoration ::UTFEncodedKHR ); 3433builder .addDecoration (msgArrType , spv::Decoration ::UTFEncodedKHR ); 3434// Array stride for char is 1 byte per element for explicit layout 3435builder .addDecoration (msgArrType , spv::Decoration ::ArrayStride ,1 ); 3436// 2.5 Collect data and type for construct an internal message structure member. 3437// The message value is built from the tightly packed type the constant already has; 3438// the laid out type only appears in the message type operand of OpAbortKHR. 3439structMemberType .push_back (msgConstDataType ); 3440structLoadMemberType .push_back (msgArrType ); 3441structMemberOffsets .push_back (msgLen ); 3442structMemberData .push_back (msgConstData ); 3443// 3. Add extra following arguments/variables' types in member structure. 3444// Matrix members need their stride recorded so they can be explicitly laid out below; 3445// 0 means the member is not a matrix. 3446 std::vector < int > structMemberMatrixStrides ; 3447structMemberMatrixStrides .push_back (0 ); 3448// The message is always packed with scalar rules, so that a given argument list produces 3449// one layout regardless of how the rest of the shader is laid out. A consumer parsing the 3450// message then only ever has to know the one set of rules. 3451for (unsigned int i = 1 ;i < glslangOperands .size ();i ++ ) { 3452 spv::Builder ::AccessChain save = builder .getAccessChain (); 3453builder .clearAccessChain (); 3454// Align this member's offset, then advance past it to get the (not yet aligned) 3455// offset of the next one. 3456const glslang::TType & argType = glslangOperands [i ]-> getAsTyped ()-> getType (); 3457int memberSize = 0 ; 3458int matrixStride = 0 ; 3459int alignment = 3460glslangIntermediate -> getMemberAlignment (argType ,memberSize ,matrixStride , glslang::ElpScalar , false); 3461 glslang::RoundToPow2 (structMemberOffsets .back (),alignment ); 3462structMemberOffsets .push_back (structMemberOffsets .back ()+ memberSize ); 3463// getMemberAlignment's stride is the array stride for an array argument, so ask for 3464// the matrix stride separately - an array of matrices needs the stride of one matrix. 3465structMemberMatrixStrides .push_back ( 3466argType .isMatrix () ?getMatrixStride (argType , glslang::ElpScalar , glslang::ElmColumnMajor ) :0 ); 3467glslangOperands [i ]-> traverse (this ); 3468 spv::Id memberValue = accessChainLoad (argType ); 3469// A bool has no in-memory representation, so lay a bool member out as a 32-bit integer 3470if (argType .getBasicType ()== glslang::EbtBool ) { 3471 spv::Id uintType = builder .makeUintType (32 ); 3472 spv::Id one = builder .makeUintConstant (1 ); 3473 spv::Id zero = builder .makeUintConstant (0 ); 3474if (argType .isVector ()) { 3475uintType = builder .makeVectorType (uintType ,argType .getVectorSize ()); 3476one = builder .smearScalar (spv::NoPrecision ,one ,uintType ); 3477zero = builder .smearScalar (spv::NoPrecision ,zero ,uintType ); 3478 } 3479memberValue = builder .createTriOp (spv::Op ::OpSelect ,uintType ,memberValue ,one ,zero ); 3480 } 3481structMemberData .push_back (memberValue ); 3482// Collect both forms of the member's type. The value is built from the loaded types, 3483// and the message type operand describes the same members explicitly laid out. An 3484// aggregate argument carries layout inside itself - ArrayStride on an array, Offset 3485// and MatrixStride on the members of a nested struct - so only the laid out form has 3486// those. OpAbortKHR only requires the two to match logically, which disregards 3487// decorations, so the value never has to be converted to the laid out form. 3488structMemberType .push_back (builder .getTypeId (structMemberData .back ())); 3489 glslang::TQualifier memberQualifier = argType .getQualifier (); 3490memberQualifier .layoutPacking = glslang::ElpScalar ; 3491if (memberQualifier .layoutMatrix == glslang::ElmNone ) 3492memberQualifier .layoutMatrix = glslang::ElmColumnMajor ; 3493structLoadMemberType .push_back ( 3494convertGlslangToSpvType (argType , glslang::ElpScalar ,memberQualifier , false)); 3495 3496builder .setAccessChain (save ); 3497 } 3498structMemberOffsets .pop_back (); 3499// 4. Construct struct message variable, add abortExt instruction. 3500// Two struct types: the value's own type, and the explicitly laid out type that tells a 3501// consumer where each member sits. Only the latter carries the layout decorations. 3502auto structValueType = builder .makeStructType (structMemberType , {},"abortMessageValueType" ); 3503auto structLoadType = builder .makeStructType (structLoadMemberType , {},"abortMessageLoadType" ); 3504for (unsigned int i = 0 ;i < structMemberOffsets .size ();i ++ ) { 3505builder .addMemberDecoration (structLoadType ,i , spv::Decoration ::Offset ,structMemberOffsets [i ]); 3506// A matrix in an explicitly laid out struct must state its majorness and stride. 3507// The loaded value is always in GLSL's default column-major order. 3508if (structMemberMatrixStrides [i ]!= 0 ) { 3509builder .addMemberDecoration (structLoadType ,i , spv::Decoration ::ColMajor ); 3510builder .addMemberDecoration (structLoadType ,i , spv::Decoration ::MatrixStride , 3511structMemberMatrixStrides [i ]); 3512 } 3513 } 3514// The members of structValueType were taken from these values, so they match exactly and 3515// the builder's plain construct is enough - the traverser's overload, which would convert 3516// a mismatched member, has nothing to do here. 3517auto messageVar = builder .createCompositeConstruct (structValueType ,structMemberData ); 3518builder .makeStatementTerminator (spv::Op ::OpAbortKHR , {structLoadType ,messageVar },"post-abort" ); 3519} 3520 3521spv::Id TGlslangToSpvTraverser ::createCoopMatConversion (spv::Id destType , spv::Id operand , glslang::TBasicType resultBasicType , glslang::TBasicType operandBasicType ,bool sameUse ,bool transpose ) 3522{ 3523 spv::Id result ; 3524if (isTypeInt (operandBasicType )&& isTypeInt (resultBasicType )&& 3525isTypeUnsignedInt (operandBasicType )!= isTypeUnsignedInt (resultBasicType )&& 3526GetNumBits (operandBasicType )!= GetNumBits (resultBasicType )) { 3527 3528// OpSConvert/OpUConvert + OpBitCast 3529operand = createIntWidthConversion (operand ,0 ,destType ,resultBasicType ,operandBasicType ); 3530operandBasicType = resultBasicType ; 3531if (transpose ) { 3532builder .addDecoration (operand , spv::Decoration ::CooperativeMatrixTransposeEXT ); 3533 } 3534return builder .createUnaryOp (spv::Op ::OpBitcast ,destType ,operand ); 3535 } 3536if (isTypeFloat (operandBasicType )&& isTypeFloat (resultBasicType )&& 3537operandBasicType != resultBasicType ) { 3538result = builder .createUnaryOp (spv::Op ::OpFConvert ,destType ,operand ); 3539 }else if (isTypeSignedInt (operandBasicType )&& isTypeFloat (resultBasicType )) { 3540result = builder .createUnaryOp (spv::Op ::OpConvertSToF ,destType ,operand ); 3541 }else if (isTypeUnsignedInt (operandBasicType )&& isTypeFloat (resultBasicType )) { 3542result = builder .createUnaryOp (spv::Op ::OpConvertUToF ,destType ,operand ); 3543 }else if (isTypeFloat (operandBasicType )&& isTypeSignedInt (resultBasicType )) { 3544result = builder .createUnaryOp (spv::Op ::OpConvertFToS ,destType ,operand ); 3545 }else if (isTypeFloat (operandBasicType )&& isTypeUnsignedInt (resultBasicType )) { 3546result = builder .createUnaryOp (spv::Op ::OpConvertFToU ,destType ,operand ); 3547 }else if (isTypeSignedInt (resultBasicType )&& GetNumBits (operandBasicType )!= GetNumBits (resultBasicType )) { 3548result = builder .createUnaryOp (spv::Op ::OpSConvert ,destType ,operand ); 3549 }else if (isTypeUnsignedInt (resultBasicType )&& GetNumBits (operandBasicType )!= GetNumBits (resultBasicType )) { 3550result = builder .createUnaryOp (spv::Op ::OpUConvert ,destType ,operand ); 3551 }else if (!sameUse ) { 3552result = builder .createUnaryOp (spv::Op ::OpCooperativeMatrixConvertUseEXT ,destType ,operand ); 3553 }else { 3554result = builder .createUnaryOp (spv::Op ::OpBitcast ,destType ,operand ); 3555 } 3556if (transpose ) { 3557builder .addDecoration (result , spv::Decoration ::CooperativeMatrixTransposeEXT ); 3558 } 3559return result ; 3560} 3561 3562bool TGlslangToSpvTraverser ::visitAggregate (glslang::TVisit visit , glslang::TIntermAggregate * node ) 3563{ 3564SpecConstantOpModeGuard spec_constant_op_mode_setter (& builder ); 3565if (node -> getType ().getQualifier ().isSpecConstant ()) 3566spec_constant_op_mode_setter .turnOnSpecConstantOpMode (); 3567 3568 spv::Id result = spv::NoResult ; 3569 spv::Id invertedType = spv::NoType ;// to use to override the natural type of the node 3570 std::vector < spv::Builder ::AccessChain > complexLvalues ;// for holding swizzling l-values too complex for 3571// SPIR-V, for an out parameter 3572 std::vector < spv::Id > temporaryLvalues ;// temporaries to pass, as proxies for complexLValues 3573 std::vector < const glslang::TType *> complexLvalueTypes ; 3574 spv::Builder ::AccessChain tensorReadResultLValue = {}; 3575tensorReadResultLValue .base = spv::NoResult ;// deferred tensorReadARM out-arg store target 3576 3577auto resultType = [& invertedType ,& node ,this ](){ 3578if (invertedType != spv::NoType ) { 3579return invertedType ; 3580 }else { 3581auto ret = convertGlslangToSpvType (node -> getType ()); 3582// convertGlslangToSpvType may clobber the debug location, reset it 3583builder .setDebugSourceLocation (node -> getLoc ().line ,node -> getLoc ().getFilename ()); 3584return ret ; 3585 } 3586 }; 3587 3588// try texturing 3589result = createImageTextureFunctionCall (node ); 3590if (result != spv::NoResult ) { 3591builder .clearAccessChain (); 3592builder .setAccessChainRValue (result ); 3593 3594return false; 3595 }else if (node -> getOp ()== glslang::EOpImageStore || 3596node -> getOp ()== glslang::EOpImageStoreLod || 3597node -> getOp ()== glslang::EOpImageAtomicStore ) { 3598// "imageStore" is a special case, which has no result 3599return false; 3600 } 3601 3602 glslang::TOperator binOp = glslang::EOpNull ; 3603bool reduceComparison = true; 3604bool isMatrix = false; 3605bool noReturnValue = false; 3606bool atomic = false; 3607 3608 spv::Builder ::AccessChain ::CoherentFlags lvalueCoherentFlags ; 3609 3610assert (node -> getOp ()); 3611 3612 spv::Decoration precision = TranslatePrecisionDecoration (node -> getOperationPrecision ()); 3613 3614switch (node -> getOp ()) { 3615case glslang::EOpScope : 3616case glslang::EOpSequence : 3617 { 3618if (visit == glslang::EvPreVisit ) { 3619++ sequenceDepth ; 3620if (sequenceDepth == 1 ) { 3621// If this is the parent node of all the functions, we want to see them 3622// early, so all call points have actual SPIR-V functions to reference. 3623// In all cases, still let the traverser visit the children for us. 3624makeFunctions (node -> getAsAggregate ()-> getSequence ()); 3625 3626// Global initializers is specific to the shader entry point, which does not exist in compile-only mode 3627if (!options .compileOnly ) { 3628// Also, we want all globals initializers to go into the beginning of the entry point, before 3629// anything else gets there, so visit out of order, doing them all now. 3630makeGlobalInitializers (node -> getAsAggregate ()-> getSequence ()); 3631 } 3632 3633//Pre process linker objects for ray tracing stages 3634if (glslangIntermediate -> isRayTracingStage ()) 3635collectRayTracingLinkerObjects (); 3636 3637// Initializers are done, don't want to visit again, but functions and link objects need to be processed, 3638// so do them manually. 3639visitFunctions (node -> getAsAggregate ()-> getSequence ()); 3640 3641return false; 3642 }else { 3643if (node -> getOp ()== glslang::EOpScope ) { 3644auto loc = node -> getLoc (); 3645builder .enterLexicalBlock (loc .line ,loc .column ); 3646 } 3647 } 3648 }else { 3649if (sequenceDepth > 1 && node -> getOp ()== glslang::EOpScope ) 3650builder .leaveLexicalBlock (); 3651-- sequenceDepth ; 3652 } 3653 3654return true; 3655 } 3656case glslang::EOpLinkerObjects : 3657 { 3658if (visit == glslang::EvPreVisit ) 3659linkageOnly = true; 3660else 3661linkageOnly = false; 3662 3663return true; 3664 } 3665case glslang::EOpComma : 3666 { 3667// processing from left to right naturally leaves the right-most 3668// lying around in the access chain 3669 glslang::TIntermSequence & glslangOperands = node -> getSequence (); 3670for (int i = 0 ;i < (int )glslangOperands .size ();++ i ) 3671glslangOperands [i ]-> traverse (this ); 3672 3673return false; 3674 } 3675case glslang::EOpFunction : 3676if (visit == glslang::EvPreVisit ) { 3677if (options .generateDebugInfo ) { 3678builder .setDebugSourceLocation (node -> getLoc ().line ,node -> getLoc ().getFilename ()); 3679 } 3680if (isShaderEntryPoint (node )) { 3681inEntryPoint = true; 3682builder .setBuildPoint (shaderEntry -> getLastBlock ()); 3683builder .enterFunction (shaderEntry ); 3684currentFunction = shaderEntry ; 3685 }else { 3686// SPIR-V functions should already be in the functionMap from the prepass 3687// that called makeFunctions(). 3688currentFunction = functionMap [node -> getName ().c_str ()]; 3689 spv::Block * functionBlock = currentFunction -> getEntryBlock (); 3690builder .setBuildPoint (functionBlock ); 3691builder .enterFunction (currentFunction ); 3692 } 3693if (options .generateDebugInfo && !options .emitNonSemanticShaderDebugInfo ) { 3694const auto & loc = node -> getLoc (); 3695const char * sourceFileName = loc .getFilename (); 3696 spv::Id sourceFileId = sourceFileName ?builder .getStringId (sourceFileName ) :builder .getMainFileId (); 3697currentFunction -> setDebugLineInfo (sourceFileId ,loc .line ,loc .column ); 3698 } 3699 }else { 3700// Here we have finished visiting the function (post-visit). Finalize it. 3701if (options .generateDebugInfo ) { 3702if (glslangIntermediate -> getSource ()== glslang::EShSourceGlsl && node -> getSequence ().size ()> 1 ) { 3703auto endLoc = node -> getSequence ()[1 ]-> getAsAggregate ()-> getEndLoc (); 3704builder .setDebugSourceLocation (endLoc .line ,endLoc .getFilename ()); 3705 } 3706 } 3707if (inEntryPoint ) 3708entryPointTerminated = true; 3709builder .leaveFunction (); 3710inEntryPoint = false; 3711currentFunction = nullptr ; 3712 } 3713 3714return true; 3715case glslang::EOpParameters : 3716// Parameters will have been consumed by EOpFunction processing, but not 3717// the body, so we still visited the function node's children, making this 3718// child redundant. 3719return false; 3720case glslang::EOpFunctionCall : 3721 { 3722builder .setDebugSourceLocation (node -> getLoc ().line ,node -> getLoc ().getFilename ()); 3723if (node -> isUserDefined ()) 3724result = handleUserFunctionCall (node ); 3725if (result ) { 3726builder .clearAccessChain (); 3727builder .setAccessChainRValue (result ); 3728 }else 3729logger -> missingFunctionality ("missing user function; linker needs to catch that" ); 3730 3731return false; 3732 } 3733case glslang::EOpConstructMat2x2 : 3734case glslang::EOpConstructMat2x3 : 3735case glslang::EOpConstructMat2x4 : 3736case glslang::EOpConstructMat3x2 : 3737case glslang::EOpConstructMat3x3 : 3738case glslang::EOpConstructMat3x4 : 3739case glslang::EOpConstructMat4x2 : 3740case glslang::EOpConstructMat4x3 : 3741case glslang::EOpConstructMat4x4 : 3742case glslang::EOpConstructDMat2x2 : 3743case glslang::EOpConstructDMat2x3 : 3744case glslang::EOpConstructDMat2x4 : 3745case glslang::EOpConstructDMat3x2 : 3746case glslang::EOpConstructDMat3x3 : 3747case glslang::EOpConstructDMat3x4 : 3748case glslang::EOpConstructDMat4x2 : 3749case glslang::EOpConstructDMat4x3 : 3750case glslang::EOpConstructDMat4x4 : 3751case glslang::EOpConstructIMat2x2 : 3752case glslang::EOpConstructIMat2x3 : 3753case glslang::EOpConstructIMat2x4 : 3754case glslang::EOpConstructIMat3x2 : 3755case glslang::EOpConstructIMat3x3 : 3756case glslang::EOpConstructIMat3x4 : 3757case glslang::EOpConstructIMat4x2 : 3758case glslang::EOpConstructIMat4x3 : 3759case glslang::EOpConstructIMat4x4 : 3760case glslang::EOpConstructUMat2x2 : 3761case glslang::EOpConstructUMat2x3 : 3762case glslang::EOpConstructUMat2x4 : 3763case glslang::EOpConstructUMat3x2 : 3764case glslang::EOpConstructUMat3x3 : 3765case glslang::EOpConstructUMat3x4 : 3766case glslang::EOpConstructUMat4x2 : 3767case glslang::EOpConstructUMat4x3 : 3768case glslang::EOpConstructUMat4x4 : 3769case glslang::EOpConstructBMat2x2 : 3770case glslang::EOpConstructBMat2x3 : 3771case glslang::EOpConstructBMat2x4 : 3772case glslang::EOpConstructBMat3x2 : 3773case glslang::EOpConstructBMat3x3 : 3774case glslang::EOpConstructBMat3x4 : 3775case glslang::EOpConstructBMat4x2 : 3776case glslang::EOpConstructBMat4x3 : 3777case glslang::EOpConstructBMat4x4 : 3778case glslang::EOpConstructF16Mat2x2 : 3779case glslang::EOpConstructF16Mat2x3 : 3780case glslang::EOpConstructF16Mat2x4 : 3781case glslang::EOpConstructF16Mat3x2 : 3782case glslang::EOpConstructF16Mat3x3 : 3783case glslang::EOpConstructF16Mat3x4 : 3784case glslang::EOpConstructF16Mat4x2 : 3785case glslang::EOpConstructF16Mat4x3 : 3786case glslang::EOpConstructF16Mat4x4 : 3787isMatrix = true; 3788 [[fallthrough ]]; 3789case glslang::EOpConstructFloat : 3790case glslang::EOpConstructVec2 : 3791case glslang::EOpConstructVec3 : 3792case glslang::EOpConstructVec4 : 3793case glslang::EOpConstructDouble : 3794case glslang::EOpConstructDVec2 : 3795case glslang::EOpConstructDVec3 : 3796case glslang::EOpConstructDVec4 : 3797case glslang::EOpConstructFloat16 : 3798case glslang::EOpConstructF16Vec2 : 3799case glslang::EOpConstructF16Vec3 : 3800case glslang::EOpConstructF16Vec4 : 3801case glslang::EOpConstructBFloat16 : 3802case glslang::EOpConstructBF16Vec2 : 3803case glslang::EOpConstructBF16Vec3 : 3804case glslang::EOpConstructBF16Vec4 : 3805case glslang::EOpConstructFloatE5M2 : 3806case glslang::EOpConstructFloatE5M2Vec2 : 3807case glslang::EOpConstructFloatE5M2Vec3 : 3808case glslang::EOpConstructFloatE5M2Vec4 : 3809case glslang::EOpConstructFloatE4M3 : 3810case glslang::EOpConstructFloatE4M3Vec2 : 3811case glslang::EOpConstructFloatE4M3Vec3 : 3812case glslang::EOpConstructFloatE4M3Vec4 : 3813case glslang::EOpConstructFloatE2M1 : 3814case glslang::EOpConstructFloatE2M1Vec2 : 3815case glslang::EOpConstructFloatE2M1Vec3 : 3816case glslang::EOpConstructFloatE2M1Vec4 : 3817case glslang::EOpConstructFloatE3M2 : 3818case glslang::EOpConstructFloatE3M2Vec2 : 3819case glslang::EOpConstructFloatE3M2Vec3 : 3820case glslang::EOpConstructFloatE3M2Vec4 : 3821case glslang::EOpConstructFloatE2M3 : 3822case glslang::EOpConstructFloatE2M3Vec2 : 3823case glslang::EOpConstructFloatE2M3Vec3 : 3824case glslang::EOpConstructFloatE2M3Vec4 : 3825case glslang::EOpConstructFloatUE8M0 : 3826case glslang::EOpConstructFloatUE8M0Vec2 : 3827case glslang::EOpConstructFloatUE8M0Vec3 : 3828case glslang::EOpConstructFloatUE8M0Vec4 : 3829case glslang::EOpConstructFloatMXINT8 : 3830case glslang::EOpConstructFloatMXINT8Vec2 : 3831case glslang::EOpConstructFloatMXINT8Vec3 : 3832case glslang::EOpConstructFloatMXINT8Vec4 : 3833case glslang::EOpConstructBool : 3834case glslang::EOpConstructBVec2 : 3835case glslang::EOpConstructBVec3 : 3836case glslang::EOpConstructBVec4 : 3837case glslang::EOpConstructInt8 : 3838case glslang::EOpConstructI8Vec2 : 3839case glslang::EOpConstructI8Vec3 : 3840case glslang::EOpConstructI8Vec4 : 3841case glslang::EOpConstructUint8 : 3842case glslang::EOpConstructU8Vec2 : 3843case glslang::EOpConstructU8Vec3 : 3844case glslang::EOpConstructU8Vec4 : 3845case glslang::EOpConstructInt16 : 3846case glslang::EOpConstructI16Vec2 : 3847case glslang::EOpConstructI16Vec3 : 3848case glslang::EOpConstructI16Vec4 : 3849case glslang::EOpConstructUint16 : 3850case glslang::EOpConstructU16Vec2 : 3851case glslang::EOpConstructU16Vec3 : 3852case glslang::EOpConstructU16Vec4 : 3853case glslang::EOpConstructInt : 3854case glslang::EOpConstructIVec2 : 3855case glslang::EOpConstructIVec3 : 3856case glslang::EOpConstructIVec4 : 3857case glslang::EOpConstructUint : 3858case glslang::EOpConstructUVec2 : 3859case glslang::EOpConstructUVec3 : 3860case glslang::EOpConstructUVec4 : 3861case glslang::EOpConstructInt64 : 3862case glslang::EOpConstructI64Vec2 : 3863case glslang::EOpConstructI64Vec3 : 3864case glslang::EOpConstructI64Vec4 : 3865case glslang::EOpConstructUint64 : 3866case glslang::EOpConstructU64Vec2 : 3867case glslang::EOpConstructU64Vec3 : 3868case glslang::EOpConstructU64Vec4 : 3869case glslang::EOpConstructStruct : 3870case glslang::EOpConstructTextureSampler : 3871case glslang::EOpConstructReference : 3872case glslang::EOpConstructCooperativeMatrixNV : 3873case glslang::EOpConstructCooperativeMatrixKHR : 3874case glslang::EOpConstructCooperativeVectorNV : 3875case glslang::EOpConstructSaturated : 3876 { 3877builder .setDebugSourceLocation (node -> getLoc ().line ,node -> getLoc ().getFilename ()); 3878 std::vector < spv::Id > arguments ; 3879translateArguments (* node ,arguments ,lvalueCoherentFlags ); 3880 spv::Id constructed ; 3881if (node -> getOp ()== glslang::EOpConstructTextureSampler ) { 3882const glslang::TType & texType = node -> getSequence ()[0 ]-> getAsTyped ()-> getType (); 3883if (glslangIntermediate -> getSpv ().spv >= glslang::EShTargetSpv_1_6 && 3884texType .getSampler ().isBuffer ()) { 3885// SamplerBuffer is not supported in spirv1.6 so 3886// `samplerBuffer(textureBuffer, sampler)` is a no-op 3887// and textureBuffer is the result going forward 3888constructed = arguments [0 ]; 3889 }else 3890constructed = builder .createOp (spv::Op ::OpSampledImage ,resultType (),arguments ); 3891 }else if (node -> getOp ()== glslang::EOpConstructCooperativeMatrixKHR && 3892node -> getType ().isCoopMatKHR ()&& node -> getSequence ()[0 ]-> getAsTyped ()-> getType ().isCoopMatKHR ()&& 3893 !node -> getAsTyped ()-> getType ().sameCoopMatUse (node -> getSequence ()[0 ]-> getAsTyped ()-> getType ())) { 3894enableCoopMatConversions (); 3895constructed = builder .createCooperativeMatrixConversion (resultType (),arguments [0 ]); 3896 }else if (node -> getType ().isCoopVecOrLongVector ()&& 3897arguments .size ()== 1 && 3898builder .getTypeId (arguments [0 ])== resultType ()) { 3899constructed = arguments [0 ]; 3900 }else if (node -> getOp ()== glslang::EOpConstructStruct || 3901node -> getOp ()== glslang::EOpConstructCooperativeMatrixNV || 3902node -> getOp ()== glslang::EOpConstructCooperativeMatrixKHR || 3903node -> getType ().isArray ()|| 3904// Handle constructing coopvec from one component here, to avoid the component 3905// getting smeared 3906 (node -> getType ().hasSpecConstantVectorComponents ()&& arguments .size ()== 1 && builder .isScalar (arguments [0 ]))) { 3907 std::vector < spv::Id > constituents ; 3908for (int c = 0 ;c < (int )arguments .size ();++ c ) 3909constituents .push_back (arguments [c ]); 3910constructed = createCompositeConstruct (resultType (),constituents ); 3911 }else if (isMatrix ) 3912constructed = builder .createMatrixConstructor (precision ,arguments ,resultType ()); 3913else if (node -> getOp ()== glslang::EOpConstructSaturated ) { 3914OpDecorations decorations = {TranslatePrecisionDecoration (node -> getOperationPrecision ()), 3915TranslateNoContractionDecoration (node -> getType ().getQualifier ()), 3916TranslateNonUniformDecoration (lvalueCoherentFlags ) }; 3917 3918auto operand = node -> getSequence ()[1 ]-> getAsTyped (); 3919 3920bool sameUse = !node -> getType ().isCoopMatKHR ()|| !operand -> getType ().isCoopMatKHR ()|| 3921node -> getAsTyped ()-> getType ().sameCoopMatUse (operand -> getType ()); 3922 3923constructed = createConversion (node -> getOp (),decorations ,resultType (),arguments [1 ], 3924node -> getType ().getBasicType (),operand -> getBasicType (),sameUse ); 3925builder .addDecoration (constructed , spv::Decoration ::SaturatedToLargestFloat8NormalConversionEXT ); 3926builder .createStore (constructed ,arguments [0 ]); 3927 } 3928else 3929constructed = builder .createConstructor (precision ,arguments ,resultType ()); 3930 3931if (node -> getType ().getQualifier ().isNonUniform ()) { 3932auto & extensions = glslangIntermediate -> getRequestedExtensions (); 3933if (extensions .find ("GL_EXT_descriptor_heap" )== extensions .end ()) { 3934builder .addDecoration (constructed , spv::Decoration ::NonUniformEXT ); 3935 } 3936 } 3937 3938builder .clearAccessChain (); 3939builder .setAccessChainRValue (constructed ); 3940 3941return false; 3942 } 3943 3944// These six are component-wise compares with component-wise results. 3945// Forward on to createBinaryOperation(), requesting a vector result. 3946case glslang::EOpLessThan : 3947case glslang::EOpGreaterThan : 3948case glslang::EOpLessThanEqual : 3949case glslang::EOpGreaterThanEqual : 3950case glslang::EOpVectorEqual : 3951case glslang::EOpVectorNotEqual : 3952 { 3953// Map the operation to a binary 3954binOp = node -> getOp (); 3955reduceComparison = false; 3956switch (node -> getOp ()) { 3957case glslang::EOpVectorEqual :binOp = glslang::EOpVectorEqual ;break ; 3958case glslang::EOpVectorNotEqual :binOp = glslang::EOpVectorNotEqual ;break ; 3959default :binOp = node -> getOp ();break ; 3960 } 3961 3962break ; 3963 } 3964case glslang::EOpMul : 3965// component-wise matrix multiply 3966binOp = glslang::EOpMul ; 3967break ; 3968case glslang::EOpOuterProduct : 3969// two vectors multiplied to make a matrix 3970binOp = glslang::EOpOuterProduct ; 3971break ; 3972case glslang::EOpDot : 3973 { 3974// for scalar dot product, use multiply 3975 glslang::TIntermSequence & glslangOperands = node -> getSequence (); 3976if (!glslangOperands [0 ]-> getAsTyped ()-> getType ().isLongVector ()&& 3977glslangOperands [0 ]-> getAsTyped ()-> getVectorSize ()== 1 ) 3978binOp = glslang::EOpMul ; 3979else if (isTypeFloat (node -> getType ().getBasicType ())) 3980binOp = glslang::EOpDot ; 3981break ; 3982 } 3983case glslang::EOpMod : 3984// when an aggregate, this is the floating-point mod built-in function, 3985// which can be emitted by the one in createBinaryOperation() 3986binOp = glslang::EOpMod ; 3987break ; 3988 3989case glslang::EOpEmitVertex : 3990case glslang::EOpEndPrimitive : 3991case glslang::EOpBarrier : 3992case glslang::EOpControlBarrierArriveEXT : 3993case glslang::EOpControlBarrierWaitEXT : 3994case glslang::EOpMemoryBarrier : 3995case glslang::EOpMemoryBarrierAtomicCounter : 3996case glslang::EOpMemoryBarrierBuffer : 3997case glslang::EOpMemoryBarrierImage : 3998case glslang::EOpMemoryBarrierShared : 3999case glslang::EOpGroupMemoryBarrier : 4000case glslang::EOpDeviceMemoryBarrier : 4001case glslang::EOpAllMemoryBarrierWithGroupSync : 4002case glslang::EOpDeviceMemoryBarrierWithGroupSync : 4003case glslang::EOpWorkgroupMemoryBarrier : 4004case glslang::EOpWorkgroupMemoryBarrierWithGroupSync : 4005case glslang::EOpSubgroupBarrier : 4006case glslang::EOpSubgroupMemoryBarrier : 4007case glslang::EOpSubgroupMemoryBarrierBuffer : 4008case glslang::EOpSubgroupMemoryBarrierImage : 4009case glslang::EOpSubgroupMemoryBarrierShared : 4010noReturnValue = true; 4011// These all have 0 operands and will naturally finish up in the code below for 0 operands 4012break ; 4013 4014case glslang::EOpAtomicAdd : 4015case glslang::EOpAtomicSubtract : 4016case glslang::EOpAtomicMin : 4017case glslang::EOpAtomicMax : 4018case glslang::EOpAtomicAnd : 4019case glslang::EOpAtomicOr : 4020case glslang::EOpAtomicXor : 4021case glslang::EOpAtomicExchange : 4022case glslang::EOpAtomicCompSwap : 4023atomic = true; 4024break ; 4025 4026case glslang::EOpAtomicStore : 4027noReturnValue = true; 4028 [[fallthrough ]]; 4029case glslang::EOpAtomicLoad : 4030atomic = true; 4031break ; 4032 4033case glslang::EOpAtomicCounterAdd : 4034case glslang::EOpAtomicCounterSubtract : 4035case glslang::EOpAtomicCounterMin : 4036case glslang::EOpAtomicCounterMax : 4037case glslang::EOpAtomicCounterAnd : 4038case glslang::EOpAtomicCounterOr : 4039case glslang::EOpAtomicCounterXor : 4040case glslang::EOpAtomicCounterExchange : 4041case glslang::EOpAtomicCounterCompSwap : 4042builder .addExtension ("SPV_KHR_shader_atomic_counter_ops" ); 4043builder .addCapability (spv::Capability ::AtomicStorageOps ); 4044atomic = true; 4045break ; 4046 4047case glslang::EOpAbsDifference : 4048case glslang::EOpAddSaturate : 4049case glslang::EOpSubSaturate : 4050case glslang::EOpAverage : 4051case glslang::EOpAverageRounded : 4052case glslang::EOpMul32x16 : 4053builder .addCapability (spv::Capability ::IntegerFunctions2INTEL ); 4054builder .addExtension ("SPV_INTEL_shader_integer_functions2" ); 4055binOp = node -> getOp (); 4056break ; 4057 4058case glslang::EOpExpectEXT : 4059builder .addCapability (spv::Capability ::ExpectAssumeKHR ); 4060builder .addExtension (spv::E_SPV_KHR_expect_assume ); 4061binOp = node -> getOp (); 4062break ; 4063 4064case glslang::EOpIgnoreIntersectionNV : 4065case glslang::EOpTerminateRayNV : 4066case glslang::EOpTraceNV : 4067case glslang::EOpTraceRayMotionNV : 4068case glslang::EOpTraceKHR : 4069case glslang::EOpExecuteCallableNV : 4070case glslang::EOpExecuteCallableKHR : 4071case glslang::EOpWritePackedPrimitiveIndices4x8NV : 4072case glslang::EOpEmitMeshTasksEXT : 4073case glslang::EOpSetMeshOutputsEXT : 4074noReturnValue = true; 4075break ; 4076case glslang::EOpRayQueryInitialize : 4077case glslang::EOpRayQueryTerminate : 4078case glslang::EOpRayQueryGenerateIntersection : 4079case glslang::EOpRayQueryConfirmIntersection : 4080builder .addExtension ("SPV_KHR_ray_query" ); 4081builder .addCapability (spv::Capability ::RayQueryKHR ); 4082noReturnValue = true; 4083break ; 4084case glslang::EOpRayQueryProceed : 4085case glslang::EOpRayQueryGetIntersectionType : 4086case glslang::EOpRayQueryGetRayTMin : 4087case glslang::EOpRayQueryGetRayFlags : 4088case glslang::EOpRayQueryGetIntersectionT : 4089case glslang::EOpRayQueryGetIntersectionInstanceCustomIndex : 4090case glslang::EOpRayQueryGetIntersectionInstanceId : 4091case glslang::EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset : 4092case glslang::EOpRayQueryGetIntersectionGeometryIndex : 4093case glslang::EOpRayQueryGetIntersectionPrimitiveIndex : 4094case glslang::EOpRayQueryGetIntersectionBarycentrics : 4095case glslang::EOpRayQueryGetIntersectionFrontFace : 4096case glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque : 4097case glslang::EOpRayQueryGetIntersectionObjectRayDirection : 4098case glslang::EOpRayQueryGetIntersectionObjectRayOrigin : 4099case glslang::EOpRayQueryGetWorldRayDirection : 4100case glslang::EOpRayQueryGetWorldRayOrigin : 4101case glslang::EOpRayQueryGetIntersectionObjectToWorld : 4102case glslang::EOpRayQueryGetIntersectionWorldToObject : 4103builder .addExtension ("SPV_KHR_ray_query" ); 4104builder .addCapability (spv::Capability ::RayQueryKHR ); 4105break ; 4106case glslang::EOpCooperativeMatrixLoad : 4107case glslang::EOpCooperativeMatrixStore : 4108case glslang::EOpCooperativeMatrixLoadNV : 4109case glslang::EOpCooperativeMatrixStoreNV : 4110case glslang::EOpCooperativeMatrixLoadTensorNV : 4111case glslang::EOpCooperativeMatrixStoreTensorNV : 4112case glslang::EOpCooperativeMatrixReduceNV : 4113case glslang::EOpCooperativeMatrixPerElementOpNV : 4114case glslang::EOpCooperativeMatrixTransposeNV : 4115case glslang::EOpCooperativeVectorMatMulNV : 4116case glslang::EOpCooperativeVectorMatMulAddNV : 4117case glslang::EOpCooperativeVectorLoadNV : 4118case glslang::EOpCooperativeVectorStoreNV : 4119case glslang::EOpCooperativeVectorOuterProductAccumulateNV : 4120case glslang::EOpCooperativeVectorReduceSumAccumulateNV : 4121noReturnValue = true; 4122break ; 4123case glslang::EOpBeginInvocationInterlock : 4124case glslang::EOpEndInvocationInterlock : 4125builder .addExtension (spv::E_SPV_EXT_fragment_shader_interlock ); 4126noReturnValue = true; 4127break ; 4128 4129case glslang::EOpHitObjectTraceRayNV : 4130case glslang::EOpHitObjectTraceRayMotionNV : 4131case glslang::EOpHitObjectGetAttributesNV : 4132case glslang::EOpHitObjectExecuteShaderNV : 4133case glslang::EOpHitObjectRecordEmptyNV : 4134case glslang::EOpHitObjectRecordMissNV : 4135case glslang::EOpHitObjectRecordMissMotionNV : 4136case glslang::EOpHitObjectRecordHitNV : 4137case glslang::EOpHitObjectRecordHitMotionNV : 4138case glslang::EOpHitObjectRecordHitWithIndexNV : 4139case glslang::EOpHitObjectRecordHitWithIndexMotionNV : 4140case glslang::EOpReorderThreadNV : 4141noReturnValue = true; 4142 [[fallthrough ]]; 4143case glslang::EOpHitObjectIsEmptyNV : 4144case glslang::EOpHitObjectIsMissNV : 4145case glslang::EOpHitObjectIsHitNV : 4146case glslang::EOpHitObjectGetRayTMinNV : 4147case glslang::EOpHitObjectGetRayTMaxNV : 4148case glslang::EOpHitObjectGetObjectRayOriginNV : 4149case glslang::EOpHitObjectGetObjectRayDirectionNV : 4150case glslang::EOpHitObjectGetWorldRayOriginNV : 4151case glslang::EOpHitObjectGetWorldRayDirectionNV : 4152case glslang::EOpHitObjectGetObjectToWorldNV : 4153case glslang::EOpHitObjectGetWorldToObjectNV : 4154case glslang::EOpHitObjectGetInstanceCustomIndexNV : 4155case glslang::EOpHitObjectGetInstanceIdNV : 4156case glslang::EOpHitObjectGetGeometryIndexNV : 4157case glslang::EOpHitObjectGetPrimitiveIndexNV : 4158case glslang::EOpHitObjectGetHitKindNV : 4159case glslang::EOpHitObjectGetCurrentTimeNV : 4160case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV : 4161case glslang::EOpHitObjectGetShaderRecordBufferHandleNV : 4162builder .addExtension (spv::E_SPV_NV_shader_invocation_reorder ); 4163builder .addCapability (spv::Capability ::ShaderInvocationReorderNV ); 4164break ; 4165 4166case glslang::EOpHitObjectGetLSSPositionsNV : 4167case glslang::EOpHitObjectGetLSSRadiiNV : 4168builder .addExtension (spv::E_SPV_NV_linear_swept_spheres ); 4169builder .addCapability (spv::Capability ::ShaderInvocationReorderNV ); 4170builder .addCapability (spv::Capability ::RayTracingLinearSweptSpheresGeometryNV ); 4171noReturnValue = true; 4172break ; 4173 4174case glslang::EOpRayQueryGetIntersectionLSSPositionsNV : 4175case glslang::EOpRayQueryGetIntersectionLSSRadiiNV : 4176builder .addExtension (spv::E_SPV_NV_linear_swept_spheres ); 4177builder .addCapability (spv::Capability ::RayQueryKHR ); 4178builder .addCapability (spv::Capability ::RayTracingLinearSweptSpheresGeometryNV ); 4179noReturnValue = true; 4180break ; 4181 4182case glslang::EOpRayQueryGetIntersectionSpherePositionNV : 4183case glslang::EOpRayQueryGetIntersectionSphereRadiusNV : 4184case glslang::EOpRayQueryIsSphereHitNV : 4185builder .addExtension (spv::E_SPV_NV_linear_swept_spheres ); 4186builder .addCapability (spv::Capability ::RayQueryKHR ); 4187builder .addCapability (spv::Capability ::RayTracingSpheresGeometryNV ); 4188builder .addCapability (spv::Capability ::RayTracingLinearSweptSpheresGeometryNV ); 4189break ; 4190 4191case glslang::EOpRayQueryGetIntersectionLSSHitValueNV : 4192case glslang::EOpRayQueryIsLSSHitNV : 4193builder .addExtension (spv::E_SPV_NV_linear_swept_spheres ); 4194builder .addCapability (spv::Capability ::RayQueryKHR ); 4195builder .addCapability (spv::Capability ::RayTracingLinearSweptSpheresGeometryNV ); 4196break ; 4197 4198case glslang::EOpHitObjectTraceRayEXT : 4199case glslang::EOpHitObjectTraceRayMotionEXT : 4200case glslang::EOpHitObjectGetAttributesEXT : 4201case glslang::EOpHitObjectExecuteShaderEXT : 4202case glslang::EOpHitObjectRecordEmptyEXT : 4203case glslang::EOpHitObjectRecordMissEXT : 4204case glslang::EOpHitObjectRecordMissMotionEXT : 4205case glslang::EOpReorderThreadEXT : 4206case glslang::EOpHitObjectSetShaderBindingTableRecordIndexEXT : 4207case glslang::EOpHitObjectReorderExecuteEXT : 4208case glslang::EOpHitObjectTraceReorderExecuteEXT : 4209case glslang::EOpHitObjectTraceMotionReorderExecuteEXT : 4210case glslang::EOpHitObjectRecordFromQueryEXT : 4211case glslang::EOpHitObjectGetIntersectionTriangleVertexPositionsEXT : 4212noReturnValue = true; 4213 [[fallthrough ]]; 4214case glslang::EOpHitObjectIsEmptyEXT : 4215case glslang::EOpHitObjectIsMissEXT : 4216case glslang::EOpHitObjectIsHitEXT : 4217case glslang::EOpHitObjectGetRayTMinEXT : 4218case glslang::EOpHitObjectGetRayTMaxEXT : 4219case glslang::EOpHitObjectGetRayFlagsEXT : 4220case glslang::EOpHitObjectGetObjectRayOriginEXT : 4221case glslang::EOpHitObjectGetObjectRayDirectionEXT : 4222case glslang::EOpHitObjectGetWorldRayOriginEXT : 4223case glslang::EOpHitObjectGetWorldRayDirectionEXT : 4224case glslang::EOpHitObjectGetObjectToWorldEXT : 4225case glslang::EOpHitObjectGetWorldToObjectEXT : 4226case glslang::EOpHitObjectGetInstanceCustomIndexEXT : 4227case glslang::EOpHitObjectGetInstanceIdEXT : 4228case glslang::EOpHitObjectGetGeometryIndexEXT : 4229case glslang::EOpHitObjectGetPrimitiveIndexEXT : 4230case glslang::EOpHitObjectGetHitKindEXT : 4231case glslang::EOpHitObjectGetCurrentTimeEXT : 4232case glslang::EOpHitObjectGetShaderBindingTableRecordIndexEXT : 4233case glslang::EOpHitObjectGetShaderRecordBufferHandleEXT : 4234builder .addExtension (spv::E_SPV_EXT_shader_invocation_reorder ); 4235builder .addCapability (spv::Capability ::ShaderInvocationReorderEXT ); 4236break ; 4237 4238case glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT : 4239builder .addExtension (spv::E_SPV_KHR_ray_tracing_position_fetch ); 4240builder .addCapability (spv::Capability ::RayQueryPositionFetchKHR ); 4241noReturnValue = true; 4242break ; 4243case glslang::EOpImageSampleWeightedQCOM : 4244builder .addCapability (spv::Capability ::TextureSampleWeightedQCOM ); 4245builder .addExtension (spv::E_SPV_QCOM_image_processing ); 4246break ; 4247case glslang::EOpImageBoxFilterQCOM : 4248builder .addCapability (spv::Capability ::TextureBoxFilterQCOM ); 4249builder .addExtension (spv::E_SPV_QCOM_image_processing ); 4250break ; 4251case glslang::EOpImageBlockMatchSADQCOM : 4252case glslang::EOpImageBlockMatchSSDQCOM : 4253builder .addCapability (spv::Capability ::TextureBlockMatchQCOM ); 4254builder .addExtension (spv::E_SPV_QCOM_image_processing ); 4255break ; 4256case glslang::EOpTensorWriteARM : 4257noReturnValue = true; 4258break ; 4259 4260case glslang::EOpImageBlockMatchWindowSSDQCOM : 4261case glslang::EOpImageBlockMatchWindowSADQCOM : 4262builder .addCapability (spv::Capability ::TextureBlockMatchQCOM ); 4263builder .addExtension (spv::E_SPV_QCOM_image_processing ); 4264builder .addCapability (spv::Capability ::TextureBlockMatch2QCOM ); 4265builder .addExtension (spv::E_SPV_QCOM_image_processing2 ); 4266break ; 4267 4268case glslang::EOpImageBlockMatchGatherSSDQCOM : 4269case glslang::EOpImageBlockMatchGatherSADQCOM : 4270builder .addCapability (spv::Capability ::TextureBlockMatchQCOM ); 4271builder .addExtension (spv::E_SPV_QCOM_image_processing ); 4272builder .addCapability (spv::Capability ::TextureBlockMatch2QCOM ); 4273builder .addExtension (spv::E_SPV_QCOM_image_processing2 ); 4274break ; 4275 4276case glslang::EOpFetchMicroTriangleVertexPositionNV : 4277case glslang::EOpFetchMicroTriangleVertexBarycentricNV : 4278builder .addExtension (spv::E_SPV_NV_displacement_micromap ); 4279builder .addCapability (spv::Capability ::DisplacementMicromapNV ); 4280break ; 4281 4282case glslang::EOpRayQueryGetIntersectionClusterIdNV : 4283builder .addExtension (spv::E_SPV_NV_cluster_acceleration_structure ); 4284builder .addCapability (spv::Capability ::RayQueryKHR ); 4285builder .addCapability (spv::Capability ::RayTracingClusterAccelerationStructureNV ); 4286break ; 4287 4288case glslang::EOpCooperativeMatrixGetCoordinateEXT : 4289builder .addExtension (spv::E_SPV_EXT_cooperative_matrix_maintenance1 ); 4290builder .addCapability (spv::Capability ::CooperativeMatrixGetCoordinateEXT ); 4291break ; 4292 4293case glslang::EOpDebugPrintf : 4294noReturnValue = true; 4295break ; 4296 4297default : 4298break ; 4299 } 4300 4301// 4302// See if it maps to a regular operation. 4303// 4304if (binOp != glslang::EOpNull ) { 4305 glslang::TIntermTyped * left = node -> getSequence ()[0 ]-> getAsTyped (); 4306 glslang::TIntermTyped * right = node -> getSequence ()[1 ]-> getAsTyped (); 4307assert (left && right ); 4308 4309builder .clearAccessChain (); 4310left -> traverse (this ); 4311 spv::Id leftId = accessChainLoad (left -> getType ()); 4312 4313builder .clearAccessChain (); 4314right -> traverse (this ); 4315 spv::Id rightId = accessChainLoad (right -> getType ()); 4316 4317builder .setDebugSourceLocation (node -> getLoc ().line ,node -> getLoc ().getFilename ()); 4318OpDecorations decorations = {precision , 4319TranslateNoContractionDecoration (node -> getType ().getQualifier ()), 4320TranslateNonUniformDecoration (node -> getType ().getQualifier ()) }; 4321result = createBinaryOperation (binOp ,decorations , 4322resultType (),leftId ,rightId , 4323left -> getType ().getBasicType (),reduceComparison ); 4324 4325// code above should only make binOp that exists in createBinaryOperation 4326assert (result != spv::NoResult ); 4327builder .clearAccessChain (); 4328builder .setAccessChainRValue (result ); 4329 4330return false; 4331 } 4332 4333// 4334// Create the list of operands. 4335// 4336 glslang::TIntermSequence & glslangOperands = node -> getSequence (); 4337 std::vector < spv::Id > operands ; 4338 std::vector < spv::IdImmediate > memoryAccessOperands ; 4339if (node -> getOp ()== glslang::EOpAbortEXT ) { 4340createAbortEXT (glslangOperands ); 4341return false; 4342 } 4343for (int arg = 0 ;arg < (int )glslangOperands .size ();++ arg ) { 4344// special case l-value operands; there are just a few 4345bool lvalue = false; 4346switch (node -> getOp ()) { 4347case glslang::EOpModf : 4348if (arg == 1 ) 4349lvalue = true; 4350break ; 4351 4352 4353 4354case glslang::EOpHitObjectRecordFromQueryEXT : 4355case glslang::EOpHitObjectGetIntersectionTriangleVertexPositionsEXT : 4356if (arg == 0 || arg == 1 ) 4357lvalue = true; 4358break ; 4359 4360case glslang::EOpHitObjectRecordHitNV : 4361case glslang::EOpHitObjectRecordHitMotionNV : 4362case glslang::EOpHitObjectRecordHitWithIndexNV : 4363case glslang::EOpHitObjectRecordHitWithIndexMotionNV : 4364case glslang::EOpHitObjectTraceRayNV : 4365case glslang::EOpHitObjectTraceRayMotionNV : 4366case glslang::EOpHitObjectExecuteShaderNV : 4367case glslang::EOpHitObjectRecordMissNV : 4368case glslang::EOpHitObjectRecordMissMotionNV : 4369case glslang::EOpHitObjectGetAttributesNV : 4370case glslang::EOpHitObjectGetClusterIdNV : 4371case glslang::EOpHitObjectTraceRayEXT : 4372case glslang::EOpHitObjectTraceRayMotionEXT : 4373case glslang::EOpHitObjectExecuteShaderEXT : 4374case glslang::EOpHitObjectRecordMissEXT : 4375case glslang::EOpHitObjectRecordMissMotionEXT : 4376case glslang::EOpHitObjectGetAttributesEXT : 4377case glslang::EOpHitObjectSetShaderBindingTableRecordIndexEXT : 4378case glslang::EOpHitObjectReorderExecuteEXT : 4379case glslang::EOpHitObjectTraceReorderExecuteEXT : 4380case glslang::EOpHitObjectTraceMotionReorderExecuteEXT : 4381if (arg == 0 ) 4382lvalue = true; 4383break ; 4384 4385case glslang::EOpHitObjectGetLSSPositionsNV : 4386case glslang::EOpHitObjectGetLSSRadiiNV : 4387lvalue = true; 4388break ; 4389 4390case glslang::EOpRayQueryInitialize : 4391case glslang::EOpRayQueryTerminate : 4392case glslang::EOpRayQueryConfirmIntersection : 4393case glslang::EOpRayQueryProceed : 4394case glslang::EOpRayQueryGenerateIntersection : 4395case glslang::EOpRayQueryGetIntersectionType : 4396case glslang::EOpRayQueryGetIntersectionT : 4397case glslang::EOpRayQueryGetIntersectionInstanceCustomIndex : 4398case glslang::EOpRayQueryGetIntersectionInstanceId : 4399case glslang::EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset : 4400case glslang::EOpRayQueryGetIntersectionGeometryIndex : 4401case glslang::EOpRayQueryGetIntersectionPrimitiveIndex : 4402case glslang::EOpRayQueryGetIntersectionBarycentrics : 4403case glslang::EOpRayQueryGetIntersectionFrontFace : 4404case glslang::EOpRayQueryGetIntersectionObjectRayDirection : 4405case glslang::EOpRayQueryGetIntersectionObjectRayOrigin : 4406case glslang::EOpRayQueryGetIntersectionObjectToWorld : 4407case glslang::EOpRayQueryGetIntersectionWorldToObject : 4408case glslang::EOpRayQueryGetIntersectionClusterIdNV : 4409case glslang::EOpRayQueryGetIntersectionSpherePositionNV : 4410case glslang::EOpRayQueryGetIntersectionSphereRadiusNV : 4411case glslang::EOpRayQueryGetIntersectionLSSHitValueNV : 4412case glslang::EOpRayQueryIsSphereHitNV : 4413case glslang::EOpRayQueryIsLSSHitNV : 4414if (arg == 0 ) 4415lvalue = true; 4416break ; 4417 4418case glslang::EOpAtomicAdd : 4419case glslang::EOpAtomicSubtract : 4420case glslang::EOpAtomicMin : 4421case glslang::EOpAtomicMax : 4422case glslang::EOpAtomicAnd : 4423case glslang::EOpAtomicOr : 4424case glslang::EOpAtomicXor : 4425case glslang::EOpAtomicExchange : 4426case glslang::EOpAtomicCompSwap : 4427if (arg == 0 ) 4428lvalue = true; 4429break ; 4430 4431case glslang::EOpFrexp : 4432if (arg == 1 ) 4433lvalue = true; 4434break ; 4435case glslang::EOpInterpolateAtSample : 4436case glslang::EOpInterpolateAtOffset : 4437case glslang::EOpInterpolateAtVertex : 4438if (arg == 0 ) { 4439// If GLSL, use the address of the interpolant argument. 4440// If HLSL, use an internal version of OpInterolates that takes 4441// the rvalue of the interpolant. A fixup pass in spirv-opt 4442// legalization will remove the OpLoad and convert to an lvalue. 4443// Had to do this because legalization will only propagate a 4444// builtin into an rvalue. 4445lvalue = glslangIntermediate -> getSource ()!= glslang::EShSourceHlsl ; 4446 4447// Does it need a swizzle inversion? If so, evaluation is inverted; 4448// operate first on the swizzle base, then apply the swizzle. 4449// That is, we transform 4450// 4451// interpolate(v.zy) -> interpolate(v).zy 4452// 4453if (glslangOperands [0 ]-> getAsOperator ()&& 4454glslangOperands [0 ]-> getAsOperator ()-> getOp ()== glslang::EOpVectorSwizzle ) 4455invertedType = convertGlslangToSpvType ( 4456glslangOperands [0 ]-> getAsBinaryNode ()-> getLeft ()-> getType ()); 4457 } 4458break ; 4459case glslang::EOpAtomicLoad : 4460case glslang::EOpAtomicStore : 4461case glslang::EOpAtomicCounterAdd : 4462case glslang::EOpAtomicCounterSubtract : 4463case glslang::EOpAtomicCounterMin : 4464case glslang::EOpAtomicCounterMax : 4465case glslang::EOpAtomicCounterAnd : 4466case glslang::EOpAtomicCounterOr : 4467case glslang::EOpAtomicCounterXor : 4468case glslang::EOpAtomicCounterExchange : 4469case glslang::EOpAtomicCounterCompSwap : 4470if (arg == 0 ) 4471lvalue = true; 4472break ; 4473case glslang::EOpAddCarry : 4474case glslang::EOpSubBorrow : 4475if (arg == 2 ) 4476lvalue = true; 4477break ; 4478case glslang::EOpUMulExtended : 4479case glslang::EOpIMulExtended : 4480if (arg >=2 ) 4481lvalue = true; 4482break ; 4483case glslang::EOpCooperativeMatrixLoad : 4484case glslang::EOpCooperativeMatrixLoadNV : 4485case glslang::EOpCooperativeMatrixLoadTensorNV : 4486case glslang::EOpCooperativeVectorLoadNV : 4487if (arg == 0 || arg == 1 ) 4488lvalue = true; 4489break ; 4490case glslang::EOpCooperativeMatrixStore : 4491case glslang::EOpCooperativeMatrixStoreNV : 4492case glslang::EOpCooperativeMatrixStoreTensorNV : 4493case glslang::EOpCooperativeVectorStoreNV : 4494if (arg == 1 ) 4495lvalue = true; 4496break ; 4497case glslang::EOpCooperativeVectorMatMulNV : 4498if (arg == 0 || arg == 3 ) 4499lvalue = true; 4500break ; 4501case glslang::EOpCooperativeVectorMatMulAddNV : 4502if (arg == 0 || arg == 3 || arg == 6 ) 4503lvalue = true; 4504break ; 4505case glslang::EOpCooperativeVectorOuterProductAccumulateNV : 4506if (arg == 2 ) 4507lvalue = true; 4508break ; 4509case glslang::EOpCooperativeVectorReduceSumAccumulateNV : 4510if (arg == 1 ) 4511lvalue = true; 4512break ; 4513case glslang::EOpCooperativeMatrixReduceNV : 4514case glslang::EOpCooperativeMatrixPerElementOpNV : 4515case glslang::EOpCooperativeMatrixTransposeNV : 4516if (arg == 0 ) 4517lvalue = true; 4518break ; 4519case glslang::EOpSpirvInst : 4520if (glslangOperands [arg ]-> getAsTyped ()-> getQualifier ().isSpirvByReference ()) 4521lvalue = true; 4522break ; 4523case glslang::EOpReorderThreadNV : 4524case glslang::EOpReorderThreadEXT : 4525//Three variants of reorderThreadNV, two of them use hitObjectNV 4526if (arg == 0 && glslangOperands .size ()!= 2 ) 4527lvalue = true; 4528break ; 4529case glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT : 4530case glslang::EOpRayQueryGetIntersectionLSSPositionsNV : 4531case glslang::EOpRayQueryGetIntersectionLSSRadiiNV : 4532if (arg == 0 || arg == 2 ) 4533lvalue = true; 4534break ; 4535case glslang::EOpTensorReadARM : 4536if (arg == 2 ) 4537lvalue = true; 4538break ; 4539default : 4540break ; 4541 } 4542builder .clearAccessChain (); 4543if (invertedType != spv::NoType && arg == 0 ) 4544glslangOperands [0 ]-> getAsBinaryNode ()-> getLeft ()-> traverse (this ); 4545else 4546glslangOperands [arg ]-> traverse (this ); 4547 4548bool isCoopMat = node -> getOp ()== glslang::EOpCooperativeMatrixLoad || 4549node -> getOp ()== glslang::EOpCooperativeMatrixStore || 4550node -> getOp ()== glslang::EOpCooperativeMatrixLoadNV || 4551node -> getOp ()== glslang::EOpCooperativeMatrixStoreNV || 4552node -> getOp ()== glslang::EOpCooperativeMatrixLoadTensorNV || 4553node -> getOp ()== glslang::EOpCooperativeMatrixStoreTensorNV ; 4554bool isCoopVec = node -> getOp ()== glslang::EOpCooperativeVectorLoadNV || 4555node -> getOp ()== glslang::EOpCooperativeVectorStoreNV ; 4556if (isCoopMat || isCoopVec ) { 4557 4558if (arg == 1 ) { 4559 spv::Builder ::AccessChain ::CoherentFlags coherentFlags {}; 4560unsigned int alignment {}; 4561if (isCoopMat ) { 4562// fold "element" parameter into the access chain 4563 spv::Builder ::AccessChain save = builder .getAccessChain (); 4564builder .clearAccessChain (); 4565glslangOperands [2 ]-> traverse (this ); 4566 4567 spv::Id elementId = accessChainLoad (glslangOperands [2 ]-> getAsTyped ()-> getType ()); 4568 4569builder .setAccessChain (save ); 4570 4571// Point to the first element of the array. 4572builder .accessChainPush (elementId , 4573TranslateCoherent (glslangOperands [arg ]-> getAsTyped ()-> getType ()), 4574glslangOperands [arg ]-> getAsTyped ()-> getType ().getBufferReferenceAlignment ()); 4575coherentFlags = builder .getAccessChain ().coherentFlags ; 4576alignment = builder .getAccessChain ().alignment ; 4577 }else { 4578coherentFlags = builder .getAccessChain ().coherentFlags ; 4579coherentFlags |=TranslateCoherent (glslangOperands [arg ]-> getAsTyped ()-> getType ()); 4580alignment = 16 ; 4581 } 4582 4583 spv::MemoryAccessMask memoryAccess = TranslateMemoryAccess (coherentFlags ); 4584if (node -> getOp ()== glslang::EOpCooperativeMatrixLoad || 4585node -> getOp ()== glslang::EOpCooperativeMatrixLoadNV || 4586node -> getOp ()== glslang::EOpCooperativeMatrixLoadTensorNV || 4587node -> getOp ()== glslang::EOpCooperativeVectorLoadNV ) 4588memoryAccess = (memoryAccess & ~spv::MemoryAccessMask ::MakePointerAvailableKHR ); 4589if (node -> getOp ()== glslang::EOpCooperativeMatrixStore || 4590node -> getOp ()== glslang::EOpCooperativeMatrixStoreNV || 4591node -> getOp ()== glslang::EOpCooperativeMatrixStoreTensorNV || 4592node -> getOp ()== glslang::EOpCooperativeVectorStoreNV ) 4593memoryAccess = (memoryAccess & ~spv::MemoryAccessMask ::MakePointerVisibleKHR ); 4594if (builder .getStorageClass (builder .getAccessChain ().base )== 4595 spv::StorageClass ::PhysicalStorageBufferEXT ) { 4596memoryAccess = (spv::MemoryAccessMask )(memoryAccess | spv::MemoryAccessMask ::Aligned ); 4597 } 4598 4599memoryAccessOperands .push_back (spv::IdImmediate (false,memoryAccess )); 4600 4601if (anySet (memoryAccess , spv::MemoryAccessMask ::Aligned )) { 4602memoryAccessOperands .push_back (spv::IdImmediate (false,alignment )); 4603 } 4604 4605if (anySet (memoryAccess , 4606 spv::MemoryAccessMask ::MakePointerAvailableKHR | spv::MemoryAccessMask ::MakePointerVisibleKHR )) { 4607memoryAccessOperands .push_back (spv::IdImmediate (true, 4608builder .makeUintConstant (TranslateMemoryScope (coherentFlags )))); 4609 } 4610 }else if (isCoopMat && arg == 2 ) { 4611continue ; 4612 } 4613 } 4614 4615// for l-values, pass the address, for r-values, pass the value 4616if (lvalue ) { 4617if (invertedType == spv::NoType && !builder .isSpvLvalue ()) { 4618// SPIR-V cannot represent an l-value containing a swizzle that doesn't 4619// reduce to a simple access chain. So, we need a temporary vector to 4620// receive the result, and must later swizzle that into the original 4621// l-value. 4622complexLvalues .push_back (builder .getAccessChain ()); 4623complexLvalueTypes .push_back (& glslangOperands [arg ]-> getAsTyped ()-> getType ()); 4624temporaryLvalues .push_back (builder .createVariable ( 4625 spv::NoPrecision , spv::StorageClass ::Function , 4626builder .accessChainGetInferredType (),"swizzleTemp" )); 4627operands .push_back (temporaryLvalues .back ()); 4628 }else { 4629if (node -> getOp ()== glslang::EOpTensorReadARM && arg == 2 ) { 4630// tensorReadARM stores the result after emitting the op, so keep the 4631// original l-value access chain and avoid materializing a transient 4632// pointer that may not preserve descriptor-heap indexing. 4633tensorReadResultLValue = builder .getAccessChain (); 4634// Keep the operand slot so optional tensor operands keep their 4635// existing indices in the later lowering logic. 4636operands .push_back (spv::NoResult ); 4637 }else { 4638operands .push_back (builder .accessChainGetLValue ()); 4639 } 4640 } 4641lvalueCoherentFlags = builder .getAccessChain ().coherentFlags ; 4642lvalueCoherentFlags |=TranslateCoherent (glslangOperands [arg ]-> getAsTyped ()-> getType ()); 4643 }else { 4644builder .setDebugSourceLocation (node -> getLoc ().line ,node -> getLoc ().getFilename ()); 4645 glslang::TOperator glslangOp = node -> getOp (); 4646if (arg == 1 && 4647 (glslangOp == glslang::EOpRayQueryGetIntersectionType || 4648glslangOp == glslang::EOpRayQueryGetIntersectionT || 4649glslangOp == glslang::EOpRayQueryGetIntersectionInstanceCustomIndex || 4650glslangOp == glslang::EOpRayQueryGetIntersectionInstanceId || 4651glslangOp == glslang::EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset || 4652glslangOp == glslang::EOpRayQueryGetIntersectionGeometryIndex || 4653glslangOp == glslang::EOpRayQueryGetIntersectionPrimitiveIndex || 4654glslangOp == glslang::EOpRayQueryGetIntersectionBarycentrics || 4655glslangOp == glslang::EOpRayQueryGetIntersectionFrontFace || 4656glslangOp == glslang::EOpRayQueryGetIntersectionObjectRayDirection || 4657glslangOp == glslang::EOpRayQueryGetIntersectionObjectRayOrigin || 4658glslangOp == glslang::EOpRayQueryGetIntersectionObjectToWorld || 4659glslangOp == glslang::EOpRayQueryGetIntersectionWorldToObject || 4660glslangOp == glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT || 4661glslangOp == glslang::EOpRayQueryGetIntersectionClusterIdNV || 4662glslangOp == glslang::EOpRayQueryGetIntersectionSpherePositionNV || 4663glslangOp == glslang::EOpRayQueryGetIntersectionSphereRadiusNV || 4664glslangOp == glslang::EOpRayQueryGetIntersectionLSSHitValueNV || 4665glslangOp == glslang::EOpRayQueryGetIntersectionLSSPositionsNV || 4666glslangOp == glslang::EOpRayQueryGetIntersectionLSSRadiiNV || 4667glslangOp == glslang::EOpRayQueryIsLSSHitNV || 4668glslangOp == glslang::EOpRayQueryIsSphereHitNV 4669 )) { 4670bool cond = glslangOperands [arg ]-> getAsConstantUnion ()-> getConstArray ()[0 ].getBConst (); 4671operands .push_back (builder .makeIntConstant (cond ?1 :0 )); 4672 }else if ((arg == 10 && glslangOp == glslang::EOpTraceKHR )|| 4673 (arg == 11 && glslangOp == glslang::EOpTraceRayMotionNV )|| 4674 (arg == 1 && glslangOp == glslang::EOpExecuteCallableKHR )|| 4675 (arg == 1 && glslangOp == glslang::EOpHitObjectExecuteShaderNV )|| 4676 (arg == 1 && glslangOp == glslang::EOpHitObjectExecuteShaderEXT )|| 4677 (arg == 11 && glslangOp == glslang::EOpHitObjectTraceRayNV )|| 4678 (arg == 11 && glslangOp == glslang::EOpHitObjectTraceRayEXT )|| 4679 (arg == 12 && glslangOp == glslang::EOpHitObjectTraceRayMotionNV )|| 4680 (arg == 12 && glslangOp == glslang::EOpHitObjectTraceRayMotionEXT )|| 4681 (arg == 12 && glslangOp == glslang::EOpHitObjectTraceMotionReorderExecuteEXT && glslangOperands .size ()== 13 )|| 4682 (arg == 14 && glslangOp == glslang::EOpHitObjectTraceMotionReorderExecuteEXT && glslangOperands .size ()== 15 )|| 4683 (arg == 11 && glslangOp == glslang::EOpHitObjectTraceReorderExecuteEXT && glslangOperands .size ()== 12 )|| 4684 (arg == 13 && glslangOp == glslang::EOpHitObjectTraceReorderExecuteEXT && glslangOperands .size ()== 14 )|| 4685 (arg == 1 && glslangOp == glslang::EOpHitObjectReorderExecuteEXT && glslangOperands .size ()== 2 )|| 4686 (arg == 3 && glslangOp == glslang::EOpHitObjectReorderExecuteEXT && glslangOperands .size ()== 4 )) { 4687const int set = glslangOp == glslang::EOpExecuteCallableKHR ?1 :0 ; 4688const int location = glslangOperands [arg ]-> getAsConstantUnion ()-> getConstArray ()[0 ].getUConst (); 4689auto itNode = locationToSymbol [set ].find (location ); 4690if (itNode == locationToSymbol [set ].end ()) { 4691logger -> missingFunctionality ("ray tracing location with no matching payload/callable data declaration" ); 4692break ; 4693 } 4694visitSymbol (itNode -> second ); 4695 spv::Id symId = getSymbolId (itNode -> second ); 4696operands .push_back (symId ); 4697 }else if ((arg == 12 && glslangOp == glslang::EOpHitObjectRecordHitNV )|| 4698 (arg == 13 && glslangOp == glslang::EOpHitObjectRecordHitMotionNV )|| 4699 (arg == 11 && glslangOp == glslang::EOpHitObjectRecordHitWithIndexNV )|| 4700 (arg == 12 && glslangOp == glslang::EOpHitObjectRecordHitWithIndexMotionNV )|| 4701 (arg == 3 && glslangOp == glslang::EOpHitObjectRecordFromQueryEXT )|| 4702 (arg == 1 && glslangOp == glslang::EOpHitObjectGetAttributesEXT )|| 4703 (arg == 1 && glslangOp == glslang::EOpHitObjectGetAttributesNV )) { 4704const int location = glslangOperands [arg ]-> getAsConstantUnion ()-> getConstArray ()[0 ].getUConst (); 4705const int set = 2 ; 4706auto itNode = locationToSymbol [set ].find (location ); 4707if (itNode == locationToSymbol [set ].end ()) { 4708logger -> missingFunctionality ("ray tracing location with no matching hit object attribute declaration" ); 4709break ; 4710 } 4711visitSymbol (itNode -> second ); 4712 spv::Id symId = getSymbolId (itNode -> second ); 4713operands .push_back (symId ); 4714 }else if (glslangOperands [arg ]-> getAsTyped ()-> getQualifier ().isSpirvLiteral ()) { 4715// Will be translated to a literal value, make a placeholder here 4716operands .push_back (spv::NoResult ); 4717 }else if (glslangOperands [arg ]-> getAsTyped ()-> getBasicType ()== glslang::EbtFunction ) { 4718 spv::Function * function = functionMap [glslangOperands [arg ]-> getAsSymbolNode ()-> getMangledName ().c_str ()]; 4719assert (function ); 4720operands .push_back (function -> getId ()); 4721 }else { 4722operands .push_back (accessChainLoad (glslangOperands [arg ]-> getAsTyped ()-> getType ())); 4723 } 4724 } 4725 } 4726 4727builder .setDebugSourceLocation (node -> getLoc ().line ,node -> getLoc ().getFilename ()); 4728if (node -> getOp ()== glslang::EOpCooperativeMatrixLoadTensorNV ) { 4729 std::vector < spv::IdImmediate > idImmOps ; 4730 4731builder .addCapability (spv::Capability ::CooperativeMatrixTensorAddressingNV ); 4732builder .addExtension (spv::E_SPV_NV_cooperative_matrix2 ); 4733 4734 spv::Id object = builder .createLoad (operands [0 ], spv::NoPrecision ); 4735 4736idImmOps .push_back (spv::IdImmediate (true,operands [1 ]));// Pointer 4737idImmOps .push_back (spv::IdImmediate (true,object ));// Object 4738idImmOps .push_back (spv::IdImmediate (true,operands [2 ]));// tensorLayout 4739 4740idImmOps .insert (idImmOps .end (),memoryAccessOperands .begin (),memoryAccessOperands .end ());// memoryaccess 4741 4742// initialize tensor operands to zero, then OR in flags based on the operands 4743size_t tensorOpIdx = idImmOps .size (); 4744idImmOps .push_back (spv::IdImmediate (false,0 )); 4745 4746// Order in `operands` follows GLSL argument order: 4747// [optional tensorView] [optional decodeFunc] [optional decodeVectorFunc] 4748// The emitted tensor-addressing operand order is the same (bit order: 4749// TensorView 0x1, DecodeFunc 0x2, DecodeVectorFunc 0x4), so we just 4750// bin operands by source position. 4751 spv::Id viewId = 0 ; 4752 spv::Id scalarFuncId = 0 ; 4753 spv::Id vectorFuncId = 0 ; 4754uint32_t i = 3 ; 4755if (i < operands .size ()&& builder .isTensorView (operands [i ])) 4756viewId = operands [i ++ ]; 4757if (i < operands .size ()) 4758scalarFuncId = operands [i ++ ]; 4759if (i < operands .size ()) 4760vectorFuncId = operands [i ++ ]; 4761assert (i == operands .size ()); 4762 4763if (viewId != 0 ) { 4764addMask (idImmOps [tensorOpIdx ].word , spv::TensorAddressingOperandsMask ::TensorView ); 4765idImmOps .push_back (spv::IdImmediate (true,viewId )); 4766 } 4767if (scalarFuncId != 0 ) { 4768addMask (idImmOps [tensorOpIdx ].word , spv::TensorAddressingOperandsMask ::DecodeFunc ); 4769builder .addCapability (spv::Capability ::CooperativeMatrixBlockLoadsNV ); 4770idImmOps .push_back (spv::IdImmediate (true,scalarFuncId )); 4771 } 4772if (vectorFuncId != 0 ) { 4773addMask (idImmOps [tensorOpIdx ].word , spv::TensorAddressingOperandsMask ::DecodeVectorFunc ); 4774builder .addCapability (spv::Capability ::CooperativeMatrixDecodeVectorNV ); 4775builder .addExtension (spv::E_SPV_NV_cooperative_matrix_decode_vector ); 4776idImmOps .push_back (spv::IdImmediate (true,vectorFuncId )); 4777 } 4778 4779// get the pointee type 4780 spv::Id typeId = builder .getContainedTypeId (builder .getTypeId (operands [0 ])); 4781assert (builder .isCooperativeMatrixType (typeId )); 4782// do the op 4783 spv::Id result = builder .createOp (spv::Op ::OpCooperativeMatrixLoadTensorNV ,typeId ,idImmOps ); 4784// store the result to the pointer (out param 'm') 4785builder .createStore (result ,operands [0 ]); 4786result = 0 ; 4787 }else if (node -> getOp ()== glslang::EOpCooperativeMatrixLoad || 4788node -> getOp ()== glslang::EOpCooperativeMatrixLoadNV ) { 4789 std::vector < spv::IdImmediate > idImmOps ; 4790 4791idImmOps .push_back (spv::IdImmediate (true,operands [1 ]));// buf 4792if (node -> getOp ()== glslang::EOpCooperativeMatrixLoad ) { 4793idImmOps .push_back (spv::IdImmediate (true,operands [3 ]));// matrixLayout 4794auto layout = (spv::CooperativeMatrixLayout )builder .getConstantScalar (operands [3 ]); 4795if (layout == spv::CooperativeMatrixLayout ::RowBlockedInterleavedARM || 4796layout == spv::CooperativeMatrixLayout ::ColumnBlockedInterleavedARM ) { 4797builder .addExtension (spv::E_SPV_ARM_cooperative_matrix_layouts ); 4798builder .addCapability (spv::Capability ::CooperativeMatrixLayoutsARM ); 4799 } 4800idImmOps .push_back (spv::IdImmediate (true,operands [2 ]));// stride 4801 }else { 4802idImmOps .push_back (spv::IdImmediate (true,operands [2 ]));// stride 4803idImmOps .push_back (spv::IdImmediate (true,operands [3 ]));// colMajor 4804 } 4805idImmOps .insert (idImmOps .end (),memoryAccessOperands .begin (),memoryAccessOperands .end ()); 4806// get the pointee type 4807 spv::Id typeId = builder .getContainedTypeId (builder .getTypeId (operands [0 ])); 4808assert (builder .isCooperativeMatrixType (typeId )); 4809// do the op 4810 spv::Id result = node -> getOp ()== glslang::EOpCooperativeMatrixLoad 4811 ?builder .createOp (spv::Op ::OpCooperativeMatrixLoadKHR ,typeId ,idImmOps ) 4812 :builder .createOp (spv::Op ::OpCooperativeMatrixLoadNV ,typeId ,idImmOps ); 4813// store the result to the pointer (out param 'm') 4814builder .createStore (result ,operands [0 ]); 4815result = 0 ; 4816 }else if (node -> getOp ()== glslang::EOpCooperativeMatrixStoreTensorNV ) { 4817 std::vector < spv::IdImmediate > idImmOps ; 4818 4819idImmOps .push_back (spv::IdImmediate (true,operands [1 ]));// buf 4820idImmOps .push_back (spv::IdImmediate (true,operands [0 ]));// object 4821 4822builder .addCapability (spv::Capability ::CooperativeMatrixTensorAddressingNV ); 4823builder .addExtension (spv::E_SPV_NV_cooperative_matrix2 ); 4824 4825idImmOps .push_back (spv::IdImmediate (true,operands [2 ]));// tensorLayout 4826 4827idImmOps .insert (idImmOps .end (),memoryAccessOperands .begin (),memoryAccessOperands .end ());// memoryaccess 4828 4829if (operands .size ()> 3 ) { 4830idImmOps .push_back (spv::IdImmediate (false, spv::TensorAddressingOperandsMask ::TensorView )); 4831idImmOps .push_back (spv::IdImmediate (true,operands [3 ]));// tensorView 4832 }else { 4833idImmOps .push_back (spv::IdImmediate (false,0 )); 4834 } 4835 4836builder .createNoResultOp (spv::Op ::OpCooperativeMatrixStoreTensorNV ,idImmOps ); 4837result = 0 ; 4838 }else if (node -> getOp ()== glslang::EOpCooperativeMatrixStore || 4839node -> getOp ()== glslang::EOpCooperativeMatrixStoreNV ) { 4840 std::vector < spv::IdImmediate > idImmOps ; 4841 4842idImmOps .push_back (spv::IdImmediate (true,operands [1 ]));// buf 4843idImmOps .push_back (spv::IdImmediate (true,operands [0 ]));// object 4844if (node -> getOp ()== glslang::EOpCooperativeMatrixStore ) { 4845idImmOps .push_back (spv::IdImmediate (true,operands [3 ]));// matrixLayout 4846auto layout = (spv::CooperativeMatrixLayout )builder .getConstantScalar (operands [3 ]); 4847if (layout == spv::CooperativeMatrixLayout ::RowBlockedInterleavedARM || 4848layout == spv::CooperativeMatrixLayout ::ColumnBlockedInterleavedARM ) { 4849builder .addExtension (spv::E_SPV_ARM_cooperative_matrix_layouts ); 4850builder .addCapability (spv::Capability ::CooperativeMatrixLayoutsARM ); 4851 } 4852idImmOps .push_back (spv::IdImmediate (true,operands [2 ]));// stride 4853 }else { 4854idImmOps .push_back (spv::IdImmediate (true,operands [2 ]));// stride 4855idImmOps .push_back (spv::IdImmediate (true,operands [3 ]));// colMajor 4856 } 4857idImmOps .insert (idImmOps .end (),memoryAccessOperands .begin (),memoryAccessOperands .end ()); 4858 4859if (node -> getOp ()== glslang::EOpCooperativeMatrixStore ) 4860builder .createNoResultOp (spv::Op ::OpCooperativeMatrixStoreKHR ,idImmOps ); 4861else 4862builder .createNoResultOp (spv::Op ::OpCooperativeMatrixStoreNV ,idImmOps ); 4863result = 0 ; 4864 }else if (node -> getOp ()== glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT ) { 4865 std::vector < spv::IdImmediate > idImmOps ; 4866 4867idImmOps .push_back (spv::IdImmediate (true,operands [0 ]));// q 4868idImmOps .push_back (spv::IdImmediate (true,operands [1 ]));// committed 4869 4870 spv::Id typeId = builder .makeArrayType (builder .makeVectorType (builder .makeFloatType (32 ),3 ), 4871builder .makeUintConstant (3 ),0 ); 4872// do the op 4873 4874 spv::Op spvOp = spv::Op ::OpRayQueryGetIntersectionTriangleVertexPositionsKHR ; 4875 4876 spv::Id result = builder .createOp (spvOp ,typeId ,idImmOps ); 4877// store the result to the pointer (out param 'm') 4878builder .createStore (result ,operands [2 ]); 4879result = 0 ; 4880 }else if (node -> getOp ()== glslang::EOpRayQueryGetIntersectionLSSPositionsNV ) { 4881 std::vector < spv::IdImmediate > idImmOps ; 4882 4883idImmOps .push_back (spv::IdImmediate (true,operands [0 ]));// q 4884idImmOps .push_back (spv::IdImmediate (true,operands [1 ]));// committed 4885 4886 spv::Id typeId = builder .makeArrayType (builder .makeVectorType (builder .makeFloatType (32 ),3 ), 4887builder .makeUintConstant (2 ),0 ); 4888// do the op 4889 4890 spv::Op spvOp = spv::Op ::OpRayQueryGetIntersectionLSSPositionsNV ; 4891 4892 spv::Id result = builder .createOp (spvOp ,typeId ,idImmOps ); 4893// store the result to the pointer (out param 'm') 4894builder .createStore (result ,operands [2 ]); 4895result = 0 ; 4896 }else if (node -> getOp ()== glslang::EOpRayQueryGetIntersectionLSSRadiiNV ) { 4897 std::vector < spv::IdImmediate > idImmOps ; 4898 4899idImmOps .push_back (spv::IdImmediate (true,operands [0 ]));// q 4900idImmOps .push_back (spv::IdImmediate (true,operands [1 ]));// committed 4901 4902 spv::Id typeId = builder .makeArrayType (builder .makeFloatType (32 ), 4903builder .makeUintConstant (2 ),0 ); 4904// do the op 4905 4906 spv::Op spvOp = spv::Op ::OpRayQueryGetIntersectionLSSRadiiNV ; 4907 4908 spv::Id result = builder .createOp (spvOp ,typeId ,idImmOps ); 4909// store the result to the pointer (out param 'm') 4910builder .createStore (result ,operands [2 ]); 4911result = 0 ; 4912 }else if (node -> getOp ()== glslang::EOpHitObjectGetLSSPositionsNV ) { 4913 std::vector < spv::IdImmediate > idImmOps ; 4914 4915idImmOps .push_back (spv::IdImmediate (true,operands [0 ]));// hitObject 4916 4917 spv::Op spvOp = spv::Op ::OpHitObjectGetLSSPositionsNV ; 4918 spv::Id typeId = builder .makeArrayType (builder .makeVectorType (builder .makeFloatType (32 ),3 ), 4919builder .makeUintConstant (2 ),0 ); 4920 4921 spv::Id result = builder .createOp (spvOp ,typeId ,idImmOps ); 4922// store the result to the pointer (out param 'm') 4923builder .createStore (result ,operands [1 ]); 4924result = 0 ; 4925 }else if (node -> getOp ()== glslang::EOpHitObjectGetLSSRadiiNV ) { 4926 std::vector < spv::IdImmediate > idImmOps ; 4927 4928idImmOps .push_back (spv::IdImmediate (true,operands [0 ]));// hitObject 4929 4930 spv::Op spvOp = spv::Op ::OpHitObjectGetLSSRadiiNV ; 4931 spv::Id typeId = builder .makeArrayType (builder .makeFloatType (32 ), 4932builder .makeUintConstant (2 ),0 ); 4933 4934 spv::Id result = builder .createOp (spvOp ,typeId ,idImmOps ); 4935// store the result to the pointer (out param 'm') 4936builder .createStore (result ,operands [1 ]); 4937result = 0 ; 4938 }else if (node -> getOp ()== glslang::EOpHitObjectGetIntersectionTriangleVertexPositionsEXT ) { 4939 std::vector < spv::IdImmediate > idImmOps ; 4940 4941idImmOps .push_back (spv::IdImmediate (true,operands [0 ]));// hitObject 4942 4943 spv::Op spvOp = spv::Op ::OpHitObjectGetIntersectionTriangleVertexPositionsEXT ; 4944 spv::Id typeId = builder .makeArrayType (builder .makeVectorType (builder .makeFloatType (32 ),3 ), 4945builder .makeUintConstant (3 ),0 ); 4946 4947 spv::Id result = builder .createOp (spvOp ,typeId ,idImmOps ); 4948// store the result to the pointer (out param 'm') 4949builder .createStore (result ,operands [1 ]); 4950result = 0 ; 4951 }else if (node -> getOp ()== glslang::EOpCooperativeMatrixMulAdd ) { 4952auto matrixOperands = spv::CooperativeMatrixOperandsMask ::MaskNone ; 4953 4954// If the optional operand is present, initialize matrixOperands to that value. 4955if (glslangOperands .size ()== 4 && glslangOperands [3 ]-> getAsConstantUnion ()) { 4956matrixOperands = (spv::CooperativeMatrixOperandsMask )glslangOperands [3 ]-> getAsConstantUnion ()-> getConstArray ()[0 ].getIConst (); 4957 } 4958 4959// Determine Cooperative Matrix Operands bits from the signedness of the types. 4960if (isTypeSignedInt (glslangOperands [0 ]-> getAsTyped ()-> getBasicType ())) 4961addMask (matrixOperands , spv::CooperativeMatrixOperandsMask ::MatrixASignedComponentsKHR ); 4962if (isTypeSignedInt (glslangOperands [1 ]-> getAsTyped ()-> getBasicType ())) 4963addMask (matrixOperands , spv::CooperativeMatrixOperandsMask ::MatrixBSignedComponentsKHR ); 4964if (isTypeSignedInt (glslangOperands [2 ]-> getAsTyped ()-> getBasicType ())) 4965addMask (matrixOperands , spv::CooperativeMatrixOperandsMask ::MatrixCSignedComponentsKHR ); 4966if (isTypeSignedInt (node -> getBasicType ())) 4967addMask (matrixOperands , spv::CooperativeMatrixOperandsMask ::MatrixResultSignedComponentsKHR ); 4968 4969 std::vector < spv::IdImmediate > idImmOps ; 4970idImmOps .push_back (spv::IdImmediate (true,operands [0 ])); 4971idImmOps .push_back (spv::IdImmediate (true,operands [1 ])); 4972idImmOps .push_back (spv::IdImmediate (true,operands [2 ])); 4973if (matrixOperands != spv::CooperativeMatrixOperandsMask ::MaskNone ) 4974idImmOps .push_back (spv::IdImmediate (false,matrixOperands )); 4975 4976result = builder .createOp (spv::Op ::OpCooperativeMatrixMulAddKHR ,resultType (),idImmOps ); 4977 }else if (node -> getOp ()== glslang::EOpCooperativeMatrixReduceNV ) { 4978if (glslangIntermediate -> usingCoopMatMaint1 ()) { 4979builder .addCapability (spv::Capability ::CooperativeMatrixReductionsEXT ); 4980builder .addExtension (spv::E_SPV_EXT_cooperative_matrix_maintenance1 ); 4981 }else { 4982builder .addCapability (spv::Capability ::CooperativeMatrixReductionsNV ); 4983builder .addExtension (spv::E_SPV_NV_cooperative_matrix2 ); 4984 } 4985 4986 spv::Op opcode = spv::Op ::OpCooperativeMatrixReduceNV ; 4987unsigned mask = glslangOperands [2 ]-> getAsConstantUnion ()-> getConstArray ()[0 ].getUConst (); 4988 4989 spv::Id typeId = builder .getContainedTypeId (builder .getTypeId (operands [0 ])); 4990assert (builder .isCooperativeMatrixType (typeId )); 4991 4992result = builder .createCooperativeMatrixReduce (opcode ,typeId ,operands [1 ],mask ,operands [3 ]); 4993// store the result to the pointer (out param 'm') 4994builder .createStore (result ,operands [0 ]); 4995result = 0 ; 4996 }else if (node -> getOp ()== glslang::EOpCooperativeMatrixPerElementOpNV ) { 4997if (glslangIntermediate -> usingCoopMatMaint1 ()) { 4998builder .addCapability (spv::Capability ::CooperativeMatrixPerElementOperationsEXT ); 4999builder .addExtension (spv::E_SPV_EXT_cooperative_matrix_maintenance1 ); 5000 }else { 5001builder .addCapability (spv::Capability ::CooperativeMatrixPerElementOperationsNV ); 5002builder .addExtension (spv::E_SPV_NV_cooperative_matrix2 ); 5003 } 5004 5005 spv::Id typeId = builder .getContainedTypeId (builder .getTypeId (operands [0 ])); 5006assert (builder .isCooperativeMatrixType (typeId )); 5007 5008result = builder .createCooperativeMatrixPerElementOp (typeId ,operands ); 5009// store the result to the pointer 5010builder .createStore (result ,operands [0 ]); 5011result = 0 ; 5012 }else if (node -> getOp ()== glslang::EOpCooperativeMatrixTransposeNV ) { 5013enableCoopMatConversions (); 5014 5015 spv::Id typeId = builder .getContainedTypeId (builder .getTypeId (operands [0 ])); 5016assert (builder .isCooperativeMatrixType (typeId )); 5017 5018if (glslangIntermediate -> usingCoopMatMaint1 ()) { 5019auto resultBasicType = glslangOperands [0 ]-> getAsTyped ()-> getBasicType (); 5020auto operandBasicType = glslangOperands [1 ]-> getAsTyped ()-> getBasicType (); 5021bool sameUse = glslangOperands [0 ]-> getAsTyped ()-> getType ().sameCoopMatUse (glslangOperands [1 ]-> getAsTyped ()-> getType ()); 5022 5023result = createCoopMatConversion (typeId ,operands [1 ],resultBasicType ,operandBasicType ,sameUse , true); 5024 }else { 5025result = builder .createUnaryOp (spv::Op ::OpCooperativeMatrixTransposeNV ,typeId ,operands [1 ]); 5026 } 5027// store the result to the pointer 5028builder .createStore (result ,operands [0 ]); 5029result = 0 ; 5030 }else if (node -> getOp ()== glslang::EOpBitCastArrayQCOM ) { 5031builder .addCapability (spv::Capability ::CooperativeMatrixConversionQCOM ); 5032builder .addExtension (spv::E_SPV_QCOM_cooperative_matrix_conversion ); 5033result = builder .createUnaryOp (spv::Op ::OpBitCastArrayQCOM ,resultType (),operands [0 ]); 5034 }else if (node -> getOp ()== glslang::EOpCompositeConstructCoopMatQCOM ) { 5035builder .addCapability (spv::Capability ::CooperativeMatrixConversionQCOM ); 5036builder .addExtension (spv::E_SPV_QCOM_cooperative_matrix_conversion ); 5037result = builder .createUnaryOp (spv::Op ::OpCompositeConstructCoopMatQCOM ,resultType (),operands [0 ]); 5038 }else if (node -> getOp ()== glslang::EOpCompositeExtractCoopMatQCOM ) { 5039builder .addCapability (spv::Capability ::CooperativeMatrixConversionQCOM ); 5040builder .addExtension (spv::E_SPV_QCOM_cooperative_matrix_conversion ); 5041result = builder .createUnaryOp (spv::Op ::OpCompositeExtractCoopMatQCOM ,resultType (),operands [0 ]); 5042 }else if (node -> getOp ()== glslang::EOpExtractSubArrayQCOM ) { 5043builder .addCapability (spv::Capability ::CooperativeMatrixConversionQCOM ); 5044builder .addExtension (spv::E_SPV_QCOM_cooperative_matrix_conversion ); 5045 5046 std::vector < spv::Id > arguments {operands [0 ],operands [1 ] };; 5047result = builder .createOp (spv::Op ::OpExtractSubArrayQCOM ,resultType (),arguments ); 5048 }else if (node -> getOp ()== glslang::EOpCooperativeVectorMatMulNV || 5049node -> getOp ()== glslang::EOpCooperativeVectorMatMulAddNV ) { 5050auto matrixOperands = spv::CooperativeMatrixOperandsMask ::MaskNone ; 5051 5052bool isMulAdd = node -> getOp ()== glslang::EOpCooperativeVectorMatMulAddNV ; 5053 5054// Determine Cooperative Matrix Operands bits from the signedness of the types. 5055 5056if (isTypeSignedInt (glslangOperands [1 ]-> getAsTyped ()-> getBasicType ())) 5057addMask (matrixOperands , spv::CooperativeMatrixOperandsMask ::MatrixBSignedComponentsKHR ); 5058if (isTypeSignedInt (glslangOperands [0 ]-> getAsTyped ()-> getBasicType ())) 5059addMask (matrixOperands , spv::CooperativeMatrixOperandsMask ::MatrixResultSignedComponentsKHR ); 5060 5061uint32_t opIdx = 1 ; 5062 std::vector < spv::IdImmediate > idImmOps ; 5063idImmOps .push_back (spv::IdImmediate (true,operands [opIdx ++ ]));// Input 5064idImmOps .push_back (spv::IdImmediate (true,operands [opIdx ++ ]));// InputInterpretation 5065idImmOps .push_back (spv::IdImmediate (true,operands [opIdx ++ ]));// Matrix 5066idImmOps .push_back (spv::IdImmediate (true,operands [opIdx ++ ]));// MatrixOffset 5067idImmOps .push_back (spv::IdImmediate (true,operands [opIdx ++ ]));// MatrixInterpretation 5068if (isMulAdd ) { 5069idImmOps .push_back (spv::IdImmediate (true,operands [opIdx ++ ]));// Bias 5070idImmOps .push_back (spv::IdImmediate (true,operands [opIdx ++ ]));// BiasOffset 5071idImmOps .push_back (spv::IdImmediate (true,operands [opIdx ++ ]));// BiasInterpretation 5072 } 5073idImmOps .push_back (spv::IdImmediate (true,operands [opIdx ++ ]));// M 5074idImmOps .push_back (spv::IdImmediate (true,operands [opIdx ++ ]));// K 5075idImmOps .push_back (spv::IdImmediate (true,operands [opIdx ++ ]));// MemoryLayout 5076idImmOps .push_back (spv::IdImmediate (true,operands [opIdx ++ ]));// Transpose 5077idImmOps .push_back (spv::IdImmediate (true,operands [opIdx ++ ]));// MatrixStride 5078if (matrixOperands != spv::CooperativeMatrixOperandsMask ::MaskNone ) 5079idImmOps .push_back (spv::IdImmediate (false,matrixOperands ));// Cooperative Matrix Operands 5080 5081// get the pointee type 5082 spv::Id typeId = builder .getContainedTypeId (builder .getTypeId (operands [0 ])); 5083assert (builder .isCooperativeVectorType (typeId )); 5084// do the op 5085 spv::Id result = builder .createOp (isMulAdd ? spv::Op ::OpCooperativeVectorMatrixMulAddNV : spv::Op ::OpCooperativeVectorMatrixMulNV ,typeId ,idImmOps ); 5086// store the result to the pointer (out param 'res') 5087builder .createStore (result ,operands [0 ]); 5088result = 0 ; 5089 }else if (node -> getOp ()== glslang::EOpCooperativeVectorLoadNV ) { 5090 std::vector < spv::IdImmediate > idImmOps ; 5091 5092idImmOps .push_back (spv::IdImmediate (true,operands [1 ]));// buf 5093idImmOps .push_back (spv::IdImmediate (true,operands [2 ]));// offset 5094idImmOps .insert (idImmOps .end (),memoryAccessOperands .begin (),memoryAccessOperands .end ()); 5095// get the pointee type 5096 spv::Id typeId = builder .getContainedTypeId (builder .getTypeId (operands [0 ])); 5097assert (builder .isCooperativeVectorType (typeId )); 5098// do the op 5099 spv::Id result = builder .createOp (spv::Op ::OpCooperativeVectorLoadNV ,typeId ,idImmOps ); 5100// store the result to the pointer (out param 'v') 5101builder .createStore (result ,operands [0 ]); 5102result = 0 ; 5103 }else if (node -> getOp ()== glslang::EOpCooperativeVectorStoreNV ) { 5104 std::vector < spv::IdImmediate > idImmOps ; 5105 5106idImmOps .push_back (spv::IdImmediate (true,operands [1 ]));// buf 5107idImmOps .push_back (spv::IdImmediate (true,operands [2 ]));// offset 5108idImmOps .push_back (spv::IdImmediate (true,operands [0 ]));// object 5109idImmOps .insert (idImmOps .end (),memoryAccessOperands .begin (),memoryAccessOperands .end ()); 5110builder .createNoResultOp (spv::Op ::OpCooperativeVectorStoreNV ,idImmOps ); 5111result = 0 ; 5112 }else if (node -> getOp ()== glslang::EOpCooperativeVectorOuterProductAccumulateNV ) { 5113builder .addCapability (spv::Capability ::CooperativeVectorTrainingNV ); 5114builder .addExtension (spv::E_SPV_NV_cooperative_vector ); 5115 5116 std::vector < spv::IdImmediate > idImmOps ; 5117 5118idImmOps .push_back (spv::IdImmediate (true,operands [2 ]));// Matrix 5119idImmOps .push_back (spv::IdImmediate (true,operands [3 ]));// Offset 5120idImmOps .push_back (spv::IdImmediate (true,operands [0 ]));// A 5121idImmOps .push_back (spv::IdImmediate (true,operands [1 ]));// B 5122idImmOps .push_back (spv::IdImmediate (true,operands [5 ]));// MemoryLayout 5123idImmOps .push_back (spv::IdImmediate (true,operands [6 ]));// MatrixInterpretation 5124idImmOps .push_back (spv::IdImmediate (true,operands [4 ]));// Stride 5125builder .createNoResultOp (spv::Op ::OpCooperativeVectorOuterProductAccumulateNV ,idImmOps ); 5126result = 0 ; 5127 }else if (node -> getOp ()== glslang::EOpCooperativeVectorReduceSumAccumulateNV ) { 5128builder .addCapability (spv::Capability ::CooperativeVectorTrainingNV ); 5129builder .addExtension (spv::E_SPV_NV_cooperative_vector ); 5130 5131 std::vector < spv::IdImmediate > idImmOps ; 5132 5133idImmOps .push_back (spv::IdImmediate (true,operands [1 ]));// Buf 5134idImmOps .push_back (spv::IdImmediate (true,operands [2 ]));// Offset 5135idImmOps .push_back (spv::IdImmediate (true,operands [0 ]));// A 5136builder .createNoResultOp (spv::Op ::OpCooperativeVectorReduceSumAccumulateNV ,idImmOps ); 5137result = 0 ; 5138 }else if (node -> getOp ()== glslang::EOpTensorReadARM || 5139node -> getOp ()== glslang::EOpTensorWriteARM ) { 5140const bool isWrite = node -> getOp ()== glslang::EOpTensorWriteARM ; 5141const unsigned int tensorMinOperandCount = 3 ; 5142assert (operands .size () >=tensorMinOperandCount ); 5143 std::vector < spv::IdImmediate > idImmOps ; 5144 5145idImmOps .push_back (spv::IdImmediate (true,operands [0 ]));// tensor 5146idImmOps .push_back (spv::IdImmediate (true,operands [1 ]));// coords 5147if (isWrite ) { 5148idImmOps .push_back (spv::IdImmediate (true,operands [2 ]));// value 5149 } 5150 5151// Analyze the tensor operands 5152 spv::IdImmediate tensorOperands = { false,uint32_t (spv::TensorOperandsMask ::MaskNone ) }; 5153bool pushExtraArg = false; 5154if (operands .size ()> tensorMinOperandCount ) { 5155auto enumVal = builder .getConstantScalar (operands [tensorMinOperandCount ]); 5156 5157if (enumVal & uint32_t (spv::TensorOperandsMask ::NontemporalARM )) { 5158tensorOperands .word |=uint32_t (spv::TensorOperandsMask ::NontemporalARM ); 5159 } 5160if (enumVal & uint32_t (spv::TensorOperandsMask ::OutOfBoundsValueARM )) { 5161tensorOperands .word |=uint32_t (spv::TensorOperandsMask ::OutOfBoundsValueARM ); 5162assert (operands .size () >=tensorMinOperandCount + 2 && 5163"TensorOperandsOutOfBoundsValueMask requires an additional value" ); 5164pushExtraArg = true; 5165 } 5166 } 5167 5168// Append optional tensor operands if the mask was non-zero. 5169if (tensorOperands .word ) { 5170idImmOps .push_back (tensorOperands ); 5171if (pushExtraArg ) 5172idImmOps .push_back (spv::IdImmediate (true,operands [tensorMinOperandCount + 1 ])); 5173 } 5174 5175if (isWrite ) { 5176builder .createNoResultOp (spv::Op ::OpTensorWriteARM ,idImmOps ); 5177result = 0 ; 5178 }else { 5179// Use the result argument type as the OpTensorReadARM result type. 5180const glslang::TType & resArgType = glslangOperands [2 ]-> getAsTyped ()-> getType (); 5181 spv::Id retType = convertGlslangToSpvType (resArgType ); 5182result = builder .createOp (spv::Op ::OpTensorReadARM ,retType ,idImmOps ); 5183// Store the result to the result argument. 5184assert (tensorReadResultLValue .base != spv::NoResult ); 5185builder .setAccessChain (tensorReadResultLValue ); 5186accessChainStore (resArgType ,result ); 5187 } 5188 }else if (node -> getOp ()== glslang::EOpTensorSizeARM ) { 5189// Expected operands are (tensor, dimension) 5190assert (operands .size ()== 2 ); 5191 5192 spv::Id tensorOp = operands [0 ]; 5193 spv::Id dimOp = operands [1 ]; 5194assert (builder .isTensorTypeARM (builder .getTypeId (tensorOp ))&& "operand #0 must be a tensor" ); 5195 5196 std::vector < spv::IdImmediate > idImmOps ; 5197idImmOps .push_back (spv::IdImmediate (true,tensorOp )); 5198idImmOps .push_back (spv::IdImmediate (true,dimOp )); 5199result = builder .createOp (spv::Op ::OpTensorQuerySizeARM ,resultType (),idImmOps ); 5200 }else if (atomic ) { 5201// Handle all atomics 5202 glslang::TBasicType typeProxy = (node -> getOp ()== glslang::EOpAtomicStore ) 5203 ?node -> getSequence ()[0 ]-> getAsTyped ()-> getBasicType () :node -> getBasicType (); 5204result = createAtomicOperation (node -> getOp (),precision ,resultType (),operands ,typeProxy , 5205lvalueCoherentFlags ,node -> getType ()); 5206 }else if (node -> getOp ()== glslang::EOpSpirvInst ) { 5207const auto & spirvInst = node -> getSpirvInstruction (); 5208 std::vector < spv::IdImmediate > idImmOps ; 5209for (unsigned int i = 0 ;i < glslangOperands .size ();++ i ) { 5210if (glslangOperands [i ]-> getAsTyped ()-> getQualifier ().isSpirvLiteral ()) { 5211// Translate the constant to a literal value 5212 std::vector < unsigned > literals ; 5213 glslang::TVector < const glslang::TIntermConstantUnion *> constants ; 5214constants .push_back (glslangOperands [i ]-> getAsConstantUnion ()); 5215TranslateLiterals (constants ,literals ); 5216idImmOps .push_back ({false,literals [0 ]}); 5217 }else 5218idImmOps .push_back ({true,operands [i ]}); 5219 } 5220 5221if (spirvInst .set == "" ) { 5222if (node -> getBasicType ()== glslang::EbtVoid ) 5223builder .createNoResultOp (static_cast < spv::Op > (spirvInst .id ),idImmOps ); 5224else 5225result = builder .createOp (static_cast < spv::Op > (spirvInst .id ),resultType (),idImmOps ); 5226 }else { 5227result = builder .createBuiltinCall ( 5228resultType (),spirvInst .set == "GLSL.std.450" ?stdBuiltins :getExtBuiltins (spirvInst .set .c_str ()), 5229spirvInst .id ,idImmOps ); 5230 } 5231noReturnValue = node -> getBasicType ()== glslang::EbtVoid ; 5232 }else if (node -> getOp ()== glslang::EOpDebugPrintf ) { 5233if (!nonSemanticDebugPrintf ) { 5234nonSemanticDebugPrintf = builder .import ("NonSemantic.DebugPrintf" ); 5235 } 5236result = builder .createBuiltinCall (builder .makeVoidType (),nonSemanticDebugPrintf , spv::NonSemanticDebugPrintfDebugPrintf ,operands ); 5237builder .addExtension (spv::E_SPV_KHR_non_semantic_info ); 5238 }else { 5239// Pass through to generic operations. 5240switch (glslangOperands .size ()) { 5241case 0 : 5242result = createNoArgOperation (node -> getOp (),precision ,resultType ()); 5243break ; 5244case 1 : 5245 { 5246OpDecorations decorations = {precision , 5247TranslateNoContractionDecoration (node -> getType ().getQualifier ()), 5248TranslateNonUniformDecoration (node -> getType ().getQualifier ()) }; 5249result = createUnaryOperation ( 5250node -> getOp (),decorations , 5251resultType (),operands .front (), 5252glslangOperands [0 ]-> getAsTyped ()-> getBasicType (),lvalueCoherentFlags ,node -> getType ()); 5253 } 5254break ; 5255default : 5256result = createMiscOperation (node -> getOp (),precision ,resultType (),operands ,node -> getBasicType ()); 5257break ; 5258 } 5259 5260if (invertedType != spv::NoResult ) 5261result = createInvertedSwizzle (precision ,* glslangOperands [0 ]-> getAsBinaryNode (),result ); 5262 5263for (unsigned int i = 0 ;i < temporaryLvalues .size ();++ i ) { 5264builder .setAccessChain (complexLvalues [i ]); 5265accessChainStore (* complexLvalueTypes [i ],builder .createLoad (temporaryLvalues [i ], spv::NoPrecision )); 5266 } 5267 } 5268 5269if (noReturnValue ) 5270return false; 5271 5272if (!result ) { 5273logger -> missingFunctionality ("unknown glslang aggregate" ); 5274return true;// pick up a child as a placeholder operand 5275 }else { 5276builder .clearAccessChain (); 5277builder .setAccessChainRValue (result ); 5278return false; 5279 } 5280} 5281 5282// This path handles both if-then-else and ?: 5283// The if-then-else has a node type of void, while 5284// ?: has either a void or a non-void node type 5285// 5286// Leaving the result, when not void: 5287// GLSL only has r-values as the result of a :?, but 5288// if we have an l-value, that can be more efficient if it will 5289// become the base of a complex r-value expression, because the 5290// next layer copies r-values into memory to use the access-chain mechanism 5291bool TGlslangToSpvTraverser ::visitSelection (glslang::TVisit /* visit */ , glslang::TIntermSelection * node ) 5292{ 5293// see if OpSelect can handle it 5294const auto isOpSelectable = [& ]() { 5295if (node -> getBasicType ()== glslang::EbtVoid ) 5296return false; 5297// OpSelect can do all other types starting with SPV 1.4 5298if (glslangIntermediate -> getSpv ().spv < glslang::EShTargetSpv_1_4 ) { 5299// pre-1.4, only scalars and vectors can be handled 5300if ((!node -> getType ().isScalar ()&& !node -> getType ().isVector ())) 5301return false; 5302 } 5303return true; 5304 }; 5305 5306// See if it simple and safe, or required, to execute both sides. 5307// Crucially, side effects must be either semantically required or avoided, 5308// and there are performance trade-offs. 5309// Return true if required or a good idea (and safe) to execute both sides, 5310// false otherwise. 5311const auto bothSidesPolicy = [& ]()-> bool { 5312// do we have both sides? 5313if (node -> getTrueBlock ()== nullptr || 5314node -> getFalseBlock ()== nullptr ) 5315return false; 5316 5317// required? (unless we write additional code to look for side effects 5318// and make performance trade-offs if none are present) 5319if (!node -> getShortCircuit ()) 5320return true; 5321 5322// if not required to execute both, decide based on performance/practicality... 5323 5324if (!isOpSelectable ()) 5325return false; 5326 5327assert (node -> getType ()== node -> getTrueBlock ()-> getAsTyped ()-> getType ()&& 5328node -> getType ()== node -> getFalseBlock ()-> getAsTyped ()-> getType ()); 5329 5330// return true if a single operand to ? : is okay for OpSelect 5331const auto operandOkay = [](glslang::TIntermTyped * node ) { 5332return node -> getAsSymbolNode ()|| node -> getType ().getQualifier ().isConstant (); 5333 }; 5334 5335return operandOkay (node -> getTrueBlock ()-> getAsTyped ())&& 5336operandOkay (node -> getFalseBlock ()-> getAsTyped ()); 5337 }; 5338 5339 spv::Id result = spv::NoResult ;// upcoming result selecting between trueValue and falseValue 5340// emit the condition before doing anything with selection 5341node -> getCondition ()-> traverse (this ); 5342 spv::Id condition = accessChainLoad (node -> getCondition ()-> getType ()); 5343 5344// Find a way of executing both sides and selecting the right result. 5345const auto executeBothSides = [& ]()-> void { 5346// execute both sides 5347 spv::Id resultType = convertGlslangToSpvType (node -> getType ()); 5348node -> getTrueBlock ()-> traverse (this ); 5349 spv::Id trueValue = accessChainLoad (node -> getTrueBlock ()-> getAsTyped ()-> getType ()); 5350node -> getFalseBlock ()-> traverse (this ); 5351 spv::Id falseValue = accessChainLoad (node -> getFalseBlock ()-> getAsTyped ()-> getType ()); 5352 5353builder .setDebugSourceLocation (node -> getLoc ().line ,node -> getLoc ().getFilename ()); 5354 5355// done if void 5356if (node -> getBasicType ()== glslang::EbtVoid ) 5357return ; 5358 5359// emit code to select between trueValue and falseValue 5360// see if OpSelect can handle the result type, and that the SPIR-V types 5361// of the inputs match the result type. 5362if (isOpSelectable ()) { 5363// Emit OpSelect for this selection. 5364 5365// smear condition to vector, if necessary (AST is always scalar) 5366// Before 1.4, smear like for mix(), starting with 1.4, keep it scalar 5367if (glslangIntermediate -> getSpv ().spv < glslang::EShTargetSpv_1_4 && builder .isVector (trueValue )) { 5368condition = builder .smearScalar (spv::NoPrecision ,condition , 5369builder .makeVectorType (builder .makeBoolType (), 5370builder .getNumComponents (trueValue ))); 5371 } 5372 5373// If the types do not match, it is because of mismatched decorations on aggregates. 5374// Since isOpSelectable only lets us get here for SPIR-V >= 1.4, we can use OpCopyObject 5375// to get matching types. 5376if (builder .getTypeId (trueValue )!= resultType ) { 5377trueValue = builder .createUnaryOp (spv::Op ::OpCopyLogical ,resultType ,trueValue ); 5378 } 5379if (builder .getTypeId (falseValue )!= resultType ) { 5380falseValue = builder .createUnaryOp (spv::Op ::OpCopyLogical ,resultType ,falseValue ); 5381 } 5382 5383// OpSelect 5384result = builder .createTriOp (spv::Op ::OpSelect ,resultType ,condition ,trueValue ,falseValue ); 5385 5386builder .clearAccessChain (); 5387builder .setAccessChainRValue (result ); 5388 }else { 5389// We need control flow to select the result. 5390// TODO: Once SPIR-V OpSelect allows arbitrary types, eliminate this path. 5391result = builder .createVariable (TranslatePrecisionDecoration (node -> getType ()), 5392 spv::StorageClass ::Function ,resultType ); 5393 5394// Selection control: 5395const spv::SelectionControlMask control = TranslateSelectionControl (* node ); 5396 5397// make an "if" based on the value created by the condition 5398 spv::Builder ::If ifBuilder (condition ,control ,builder ); 5399 5400// emit the "then" statement 5401builder .clearAccessChain (); 5402builder .setAccessChainLValue (result ); 5403multiTypeStore (node -> getType (),trueValue ); 5404 5405ifBuilder .makeBeginElse (); 5406// emit the "else" statement 5407builder .clearAccessChain (); 5408builder .setAccessChainLValue (result ); 5409multiTypeStore (node -> getType (),falseValue ); 5410 5411// finish off the control flow 5412ifBuilder .makeEndIf (); 5413 5414builder .clearAccessChain (); 5415builder .setAccessChainLValue (result ); 5416 } 5417 }; 5418 5419// Execute the one side needed, as per the condition 5420const auto executeOneSide = [& ]() { 5421// Always emit control flow. 5422if (node -> getBasicType ()!= glslang::EbtVoid ) { 5423result = builder .createVariable (TranslatePrecisionDecoration (node -> getType ()), spv::StorageClass ::Function , 5424convertGlslangToSpvType (node -> getType ())); 5425 } 5426 5427// Selection control: 5428const spv::SelectionControlMask control = TranslateSelectionControl (* node ); 5429 5430// make an "if" based on the value created by the condition 5431 spv::Builder ::If ifBuilder (condition ,control ,builder ); 5432 5433// emit the "then" statement 5434if (node -> getTrueBlock ()!= nullptr ) { 5435node -> getTrueBlock ()-> traverse (this ); 5436if (result != spv::NoResult ) { 5437 spv::Id load = accessChainLoad (node -> getTrueBlock ()-> getAsTyped ()-> getType ()); 5438 5439builder .clearAccessChain (); 5440builder .setAccessChainLValue (result ); 5441multiTypeStore (node -> getType (),load ); 5442 } 5443 } 5444 5445if (node -> getFalseBlock ()!= nullptr ) { 5446ifBuilder .makeBeginElse (); 5447// emit the "else" statement 5448node -> getFalseBlock ()-> traverse (this ); 5449if (result != spv::NoResult ) { 5450 spv::Id load = accessChainLoad (node -> getFalseBlock ()-> getAsTyped ()-> getType ()); 5451 5452builder .clearAccessChain (); 5453builder .setAccessChainLValue (result ); 5454multiTypeStore (node -> getType (),load ); 5455 } 5456 } 5457 5458// finish off the control flow 5459ifBuilder .makeEndIf (); 5460 5461if (result != spv::NoResult ) { 5462builder .clearAccessChain (); 5463builder .setAccessChainLValue (result ); 5464 } 5465 }; 5466 5467// Try for OpSelect (or a requirement to execute both sides) 5468if (bothSidesPolicy ()) { 5469SpecConstantOpModeGuard spec_constant_op_mode_setter (& builder ); 5470if (node -> getType ().getQualifier ().isSpecConstant ()) 5471spec_constant_op_mode_setter .turnOnSpecConstantOpMode (); 5472executeBothSides (); 5473 }else 5474executeOneSide (); 5475 5476return false; 5477} 5478 5479bool TGlslangToSpvTraverser ::visitSwitch (glslang::TVisit /* visit */ , glslang::TIntermSwitch * node ) 5480{ 5481// emit and get the condition before doing anything with switch 5482node -> getCondition ()-> traverse (this ); 5483 spv::Id selector = accessChainLoad (node -> getCondition ()-> getAsTyped ()-> getType ()); 5484 5485// Selection control: 5486const spv::SelectionControlMask control = TranslateSwitchControl (* node ); 5487 5488// browse the children to sort out code segments 5489int defaultSegment = -1 ; 5490 std::vector < TIntermNode *> codeSegments ; 5491 glslang::TIntermSequence & sequence = node -> getBody ()-> getSequence (); 5492 std::vector < int > caseValues ; 5493 std::vector < int > valueIndexToSegment (sequence .size ());// note: probably not all are used, it is an overestimate 5494for (glslang::TIntermSequence ::iterator c = sequence .begin ();c != sequence .end ();++ c ) { 5495TIntermNode * child = * c ; 5496if (child -> getAsBranchNode ()&& child -> getAsBranchNode ()-> getFlowOp ()== glslang::EOpDefault ) 5497defaultSegment = (int )codeSegments .size (); 5498else if (child -> getAsBranchNode ()&& child -> getAsBranchNode ()-> getFlowOp ()== glslang::EOpCase ) { 5499valueIndexToSegment [caseValues .size ()]= (int )codeSegments .size (); 5500caseValues .push_back (child -> getAsBranchNode ()-> getExpression ()-> getAsConstantUnion () 5501-> getConstArray ()[0 ].getIConst ()); 5502 }else 5503codeSegments .push_back (child ); 5504 } 5505 5506// handle the case where the last code segment is missing, due to no code 5507// statements between the last case and the end of the switch statement 5508if ((caseValues .size ()&& (int )codeSegments .size ()== valueIndexToSegment [caseValues .size ()- 1 ])|| 5509 (int )codeSegments .size ()== defaultSegment ) 5510codeSegments .push_back (nullptr ); 5511 5512// make the switch statement 5513 std::vector < spv::Block *> segmentBlocks ;// returned, as the blocks allocated in the call 5514builder .makeSwitch (selector ,control , (int )codeSegments .size (),caseValues ,valueIndexToSegment ,defaultSegment , 5515segmentBlocks ); 5516 5517// emit all the code in the segments 5518breakForLoop .push (false); 5519for (unsigned int s = 0 ;s < codeSegments .size ();++ s ) { 5520builder .nextSwitchSegment (segmentBlocks ,s ); 5521if (codeSegments [s ]) 5522codeSegments [s ]-> traverse (this ); 5523else 5524builder .addSwitchBreak (true); 5525 } 5526breakForLoop .pop (); 5527 5528builder .endSwitch (segmentBlocks ); 5529 5530return false; 5531} 5532 5533void TGlslangToSpvTraverser ::visitConstantUnion (glslang::TIntermConstantUnion * node ) 5534{ 5535if (node -> getQualifier ().isSpirvLiteral ()) 5536return ;// Translated to a literal value, skip further processing 5537 5538int nextConst = 0 ; 5539 spv::Id constant = createSpvConstantFromConstUnionArray (node -> getType (),node -> getConstArray (),nextConst , false); 5540 5541builder .clearAccessChain (); 5542builder .setAccessChainRValue (constant ); 5543} 5544 5545bool TGlslangToSpvTraverser ::visitLoop (glslang::TVisit /* visit */ , glslang::TIntermLoop * node ) 5546{ 5547auto blocks = builder .makeNewLoop (); 5548builder .createBranch (true,& blocks .head ); 5549 5550// Loop control: 5551 std::vector < unsigned int > operands ; 5552const spv::LoopControlMask control = TranslateLoopControl (* node ,operands ); 5553 5554// Spec requires back edges to target header blocks, and every header block 5555// must dominate its merge block. Make a header block first to ensure these 5556// conditions are met. By definition, it will contain OpLoopMerge, followed 5557// by a block-ending branch. But we don't want to put any other body/test 5558// instructions in it, since the body/test may have arbitrary instructions, 5559// including merges of its own. 5560builder .setBuildPoint (& blocks .head ); 5561builder .setDebugSourceLocation (node -> getLoc ().line ,node -> getLoc ().getFilename ()); 5562builder .createLoopMerge (& blocks .merge ,& blocks .continue_target ,control ,operands ); 5563if (node -> testFirst ()&& node -> getTest ()) { 5564 spv::Block & test = builder .makeNewBlock (); 5565builder .createBranch (true,& test ); 5566 5567builder .setBuildPoint (& test ); 5568node -> getTest ()-> traverse (this ); 5569 spv::Id condition = accessChainLoad (node -> getTestExpr ()-> getType ()); 5570builder .createConditionalBranch (condition ,& blocks .body ,& blocks .merge ); 5571 5572builder .setBuildPoint (& blocks .body ); 5573breakForLoop .push (true); 5574if (node -> getBody ()) 5575node -> getBody ()-> traverse (this ); 5576builder .createBranch (true,& blocks .continue_target ); 5577breakForLoop .pop (); 5578 5579builder .setBuildPoint (& blocks .continue_target ); 5580if (node -> getTerminal ()) 5581node -> getTerminal ()-> traverse (this ); 5582builder .createBranch (true,& blocks .head ); 5583 }else { 5584builder .setDebugSourceLocation (node -> getLoc ().line ,node -> getLoc ().getFilename ()); 5585builder .createBranch (true,& blocks .body ); 5586 5587breakForLoop .push (true); 5588builder .setBuildPoint (& blocks .body ); 5589if (node -> getBody ()) 5590node -> getBody ()-> traverse (this ); 5591builder .createBranch (true,& blocks .continue_target ); 5592breakForLoop .pop (); 5593 5594builder .setBuildPoint (& blocks .continue_target ); 5595if (node -> getTerminal ()) 5596node -> getTerminal ()-> traverse (this ); 5597if (node -> getTest ()) { 5598node -> getTest ()-> traverse (this ); 5599 spv::Id condition = 5600accessChainLoad (node -> getTestExpr ()-> getType ()); 5601builder .createConditionalBranch (condition ,& blocks .head ,& blocks .merge ); 5602 }else { 5603// TODO: unless there was a break/return/discard instruction 5604// somewhere in the body, this is an infinite loop, so we should 5605// issue a warning. 5606builder .createBranch (true,& blocks .head ); 5607 } 5608 } 5609builder .setBuildPoint (& blocks .merge ); 5610builder .closeLoop (); 5611return false; 5612} 5613 5614bool TGlslangToSpvTraverser ::visitBranch (glslang::TVisit /* visit */ , glslang::TIntermBranch * node ) 5615{ 5616if (node -> getExpression ()) 5617node -> getExpression ()-> traverse (this ); 5618 5619builder .setDebugSourceLocation (node -> getLoc ().line ,node -> getLoc ().getFilename ()); 5620 5621switch (node -> getFlowOp ()) { 5622case glslang::EOpKill : 5623if (glslangIntermediate -> getSpv ().spv >= glslang::EShTargetSpv_1_6 ) { 5624if (glslangIntermediate -> getDiscardIsTerminate ()&& glslangIntermediate -> getSource ()== glslang::EShSourceGlsl ) { 5625builder .makeStatementTerminator (spv::Op ::OpTerminateInvocation ,"post-terminate-invocation" ); 5626 }else { 5627builder .addCapability (spv::Capability ::DemoteToHelperInvocation ); 5628builder .createNoResultOp (spv::Op ::OpDemoteToHelperInvocationEXT ); 5629 } 5630 }else { 5631builder .makeStatementTerminator (spv::Op ::OpKill ,"post-discard" ); 5632 } 5633break ; 5634case glslang::EOpTerminateInvocation : 5635builder .addExtension (spv::E_SPV_KHR_terminate_invocation ); 5636builder .makeStatementTerminator (spv::Op ::OpTerminateInvocation ,"post-terminate-invocation" ); 5637break ; 5638case glslang::EOpBreak : 5639if (breakForLoop .top ()) 5640builder .createLoopExit (); 5641else 5642builder .addSwitchBreak (false); 5643break ; 5644case glslang::EOpContinue : 5645builder .createLoopContinue (); 5646break ; 5647case glslang::EOpReturn : 5648if (node -> getExpression ()!= nullptr ) { 5649const glslang::TType & glslangReturnType = node -> getExpression ()-> getType (); 5650 spv::Id returnId = accessChainLoad (glslangReturnType ); 5651if (builder .getTypeId (returnId )!= currentFunction -> getReturnType ()|| 5652TranslatePrecisionDecoration (glslangReturnType )!= currentFunction -> getReturnPrecision ()) { 5653builder .clearAccessChain (); 5654 spv::Id copyId = builder .createVariable (currentFunction -> getReturnPrecision (), 5655 spv::StorageClass ::Function ,currentFunction -> getReturnType ()); 5656builder .setAccessChainLValue (copyId ); 5657multiTypeStore (glslangReturnType ,returnId ); 5658returnId = builder .createLoad (copyId ,currentFunction -> getReturnPrecision ()); 5659 } 5660builder .makeReturn (false,returnId ); 5661 }else 5662builder .makeReturn (false); 5663 5664builder .clearAccessChain (); 5665break ; 5666 5667case glslang::EOpDemote : 5668builder .createNoResultOp (spv::Op ::OpDemoteToHelperInvocationEXT ); 5669builder .addExtension (spv::E_SPV_EXT_demote_to_helper_invocation ); 5670builder .addCapability (spv::Capability ::DemoteToHelperInvocationEXT ); 5671break ; 5672case glslang::EOpTerminateRayKHR : 5673builder .makeStatementTerminator (spv::Op ::OpTerminateRayKHR ,"post-terminateRayKHR" ); 5674break ; 5675case glslang::EOpIgnoreIntersectionKHR : 5676builder .makeStatementTerminator (spv::Op ::OpIgnoreIntersectionKHR ,"post-ignoreIntersectionKHR" ); 5677break ; 5678 5679default : 5680assert (0 ); 5681break ; 5682 } 5683 5684return false; 5685} 5686 5687bool TGlslangToSpvTraverser ::visitVariableDecl (glslang::TVisit visit , glslang::TIntermVariableDecl * node ) 5688{ 5689if (visit == glslang::EvPreVisit ) { 5690builder .setDebugSourceLocation (node -> getDeclSymbol ()-> getLoc ().line ,node -> getDeclSymbol ()-> getLoc ().getFilename ()); 5691// We touch the symbol once here to create the debug info. 5692getSymbolId (node -> getDeclSymbol ()); 5693 } 5694 5695return true; 5696} 5697 5698 5699spv::Id TGlslangToSpvTraverser ::createSpvVariable (const glslang::TIntermSymbol * node , spv::Id forcedType ) 5700{ 5701// First, steer off constants, which are not SPIR-V variables, but 5702// can still have a mapping to a SPIR-V Id. 5703// This includes specialization constants. 5704if (node -> getQualifier ().isConstant ()) { 5705 spv::Id result = createSpvConstant (* node ); 5706if (result != spv::NoResult ) { 5707auto name = node -> getAsSymbolNode ()-> getAccessName ().c_str (); 5708auto typeId = convertGlslangToSpvType (node -> getType ()); 5709builder .createConstVariable (typeId ,name ,result ,currentFunction == nullptr ); 5710return result ; 5711 } 5712 } 5713 5714// Now, handle actual variables 5715 spv::StorageClass storageClass = TranslateStorageClass (node -> getType ()); 5716 spv::Id spvType = forcedType == spv::NoType ?convertGlslangToSpvType (node -> getType ()) 5717 :forcedType ; 5718 5719const bool contains16BitType = node -> getType ().contains16BitFloat ()|| 5720node -> getType ().contains16BitInt (); 5721if (contains16BitType ) { 5722switch (storageClass ) { 5723case spv::StorageClass ::Input : 5724case spv::StorageClass ::Output : 5725builder .addIncorporatedExtension (spv::E_SPV_KHR_16bit_storage , spv::Spv_1_3 ); 5726builder .addCapability (spv::Capability ::StorageInputOutput16 ); 5727break ; 5728case spv::StorageClass ::Uniform : 5729builder .addIncorporatedExtension (spv::E_SPV_KHR_16bit_storage , spv::Spv_1_3 ); 5730if (node -> getType ().getQualifier ().storage == glslang::EvqBuffer ) 5731builder .addCapability (spv::Capability ::StorageUniformBufferBlock16 ); 5732else 5733builder .addCapability (spv::Capability ::StorageUniform16 ); 5734break ; 5735case spv::StorageClass ::PushConstant : 5736builder .addIncorporatedExtension (spv::E_SPV_KHR_16bit_storage , spv::Spv_1_3 ); 5737builder .addCapability (spv::Capability ::StoragePushConstant16 ); 5738break ; 5739case spv::StorageClass ::StorageBuffer : 5740case spv::StorageClass ::PhysicalStorageBufferEXT : 5741builder .addIncorporatedExtension (spv::E_SPV_KHR_16bit_storage , spv::Spv_1_3 ); 5742builder .addCapability (spv::Capability ::StorageUniformBufferBlock16 ); 5743break ; 5744case spv::StorageClass ::TileAttachmentQCOM : 5745builder .addCapability (spv::Capability ::TileShadingQCOM ); 5746break ; 5747default : 5748if (storageClass == spv::StorageClass ::Workgroup && 5749node -> getType ().getBasicType ()== glslang::EbtBlock ) { 5750builder .addCapability (spv::Capability ::WorkgroupMemoryExplicitLayout16BitAccessKHR ); 5751break ; 5752 } 5753if (node -> getType ().contains16BitFloat ()) 5754builder .addCapability (spv::Capability ::Float16 ); 5755if (node -> getType ().contains16BitInt ()) 5756builder .addCapability (spv::Capability ::Int16 ); 5757break ; 5758 } 5759 } 5760 5761if (node -> getType ().contains8BitInt ()) { 5762if (storageClass == spv::StorageClass ::PushConstant ) { 5763builder .addIncorporatedExtension (spv::E_SPV_KHR_8bit_storage , spv::Spv_1_5 ); 5764builder .addCapability (spv::Capability ::StoragePushConstant8 ); 5765 }else if (storageClass == spv::StorageClass ::Uniform ) { 5766builder .addIncorporatedExtension (spv::E_SPV_KHR_8bit_storage , spv::Spv_1_5 ); 5767builder .addCapability (spv::Capability ::UniformAndStorageBuffer8BitAccess ); 5768 }else if (storageClass == spv::StorageClass ::StorageBuffer ) { 5769builder .addIncorporatedExtension (spv::E_SPV_KHR_8bit_storage , spv::Spv_1_5 ); 5770builder .addCapability (spv::Capability ::StorageBuffer8BitAccess ); 5771 }else if (storageClass == spv::StorageClass ::Workgroup && 5772node -> getType ().getBasicType ()== glslang::EbtBlock ) { 5773builder .addCapability (spv::Capability ::WorkgroupMemoryExplicitLayout8BitAccessKHR ); 5774 }else { 5775builder .addCapability (spv::Capability ::Int8 ); 5776 } 5777 } 5778 5779const char * name = node -> getName ().c_str (); 5780if (glslang::IsAnonymous (name )) 5781name = "" ; 5782 5783 spv::Id initializer = spv::NoResult ; 5784 5785if (node -> getType ().getQualifier ().storage == glslang::EvqUniform && !node -> getConstArray ().empty ()) { 5786int nextConst = 0 ; 5787initializer = createSpvConstantFromConstUnionArray (node -> getType (), 5788node -> getConstArray (), 5789nextConst , 5790 false/* specConst */ ); 5791 }else if (node -> getType ().getQualifier ().isNullInit ()) { 5792initializer = builder .makeNullConstant (spvType ); 5793 } 5794 5795 spv::Id var = builder .createVariable (spv::NoPrecision ,storageClass ,spvType ,name ,initializer , false); 5796 5797if (options .emitNonSemanticShaderDebugInfo && storageClass != spv::StorageClass ::Function ) { 5798// Create variable alias for retargeted symbols if any. 5799// Notably, this is only applicable to built-in variables so that it is okay to only use name as the key. 5800auto [itBegin ,itEnd ]= glslangIntermediate -> getBuiltinAliasLookup ().equal_range (name ); 5801for (auto it = itBegin ;it != itEnd ;++ it ) { 5802builder .createDebugGlobalVariable (builder .getDebugType (spvType ),it -> second .c_str (),var ); 5803 } 5804 } 5805 5806 std::vector < spv::Decoration > topLevelDecorations ; 5807 glslang::TQualifier typeQualifier = node -> getType ().getQualifier (); 5808TranslateMemoryDecoration (typeQualifier ,topLevelDecorations ,glslangIntermediate -> usingVulkanMemoryModel ()); 5809for (auto deco :topLevelDecorations ) { 5810builder .addDecoration (var ,deco ); 5811 } 5812return var ; 5813} 5814 5815// Return type Id of the sampled type. 5816spv::Id TGlslangToSpvTraverser ::getSampledType (const glslang::TSampler & sampler ) 5817{ 5818switch (sampler .type ) { 5819case glslang::EbtInt :return builder .makeIntType (32 ); 5820case glslang::EbtUint :return builder .makeUintType (32 ); 5821case glslang::EbtFloat :return builder .makeFloatType (32 ); 5822case glslang::EbtFloat16 : 5823builder .addExtension (spv::E_SPV_AMD_gpu_shader_half_float_fetch ); 5824builder .addCapability (spv::Capability ::Float16ImageAMD ); 5825return builder .makeFloatType (16 ); 5826case glslang::EbtInt64 : 5827builder .addExtension (spv::E_SPV_EXT_shader_image_int64 ); 5828builder .addCapability (spv::Capability ::Int64ImageEXT ); 5829return builder .makeIntType (64 ); 5830case glslang::EbtUint64 : 5831builder .addExtension (spv::E_SPV_EXT_shader_image_int64 ); 5832builder .addCapability (spv::Capability ::Int64ImageEXT ); 5833return builder .makeUintType (64 ); 5834default : 5835assert (0 ); 5836return builder .makeFloatType (32 ); 5837 } 5838} 5839 5840// If node is a swizzle operation, return the type that should be used if 5841// the swizzle base is first consumed by another operation, before the swizzle 5842// is applied. 5843spv::Id TGlslangToSpvTraverser ::getInvertedSwizzleType (const glslang::TIntermTyped & node ) 5844{ 5845if (node .getAsOperator ()&& 5846node .getAsOperator ()-> getOp ()== glslang::EOpVectorSwizzle ) 5847return convertGlslangToSpvType (node .getAsBinaryNode ()-> getLeft ()-> getType ()); 5848else 5849return spv::NoType ; 5850} 5851 5852// When inverting a swizzle with a parent op, this function 5853// will apply the swizzle operation to a completed parent operation. 5854spv::Id TGlslangToSpvTraverser ::createInvertedSwizzle (spv::Decoration precision ,const glslang::TIntermTyped & node , 5855 spv::Id parentResult ) 5856{ 5857 std::vector < unsigned > swizzle ; 5858convertSwizzle (* node .getAsBinaryNode ()-> getRight ()-> getAsAggregate (),swizzle ); 5859return builder .createRvalueSwizzle (precision ,convertGlslangToSpvType (node .getType ()),parentResult ,swizzle ); 5860} 5861 5862// Convert a glslang AST swizzle node to a swizzle vector for building SPIR-V. 5863void TGlslangToSpvTraverser ::convertSwizzle (const glslang::TIntermAggregate & node , std::vector < unsigned >& swizzle ) 5864{ 5865const glslang::TIntermSequence & swizzleSequence = node .getSequence (); 5866for (int i = 0 ;i < (int )swizzleSequence .size ();++ i ) 5867swizzle .push_back (swizzleSequence [i ]-> getAsConstantUnion ()-> getConstArray ()[0 ].getIConst ()); 5868} 5869 5870// Convert from a glslang type to an SPV type, by calling into a 5871// recursive version of this function. This establishes the inherited 5872// layout state rooted from the top-level type. 5873spv::Id TGlslangToSpvTraverser ::convertGlslangToSpvType (const glslang::TType & type ,bool forwardReferenceOnly ) 5874{ 5875return convertGlslangToSpvType (type ,getExplicitLayout (type ),type .getQualifier (), false,forwardReferenceOnly ); 5876} 5877 5878spv::LinkageType TGlslangToSpvTraverser ::convertGlslangLinkageToSpv (glslang::TLinkType linkType ) 5879{ 5880switch (linkType ) { 5881case glslang::ELinkExport : 5882return spv::LinkageType ::Export ; 5883default : 5884return spv::LinkageType ::Max ; 5885 } 5886} 5887 5888// Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id. 5889// explicitLayout can be kept the same throughout the hierarchical recursive walk. 5890// Mutually recursive with convertGlslangStructToSpvType(). 5891spv::Id TGlslangToSpvTraverser ::convertGlslangToSpvType (const glslang::TType & type , 5892 glslang::TLayoutPacking explicitLayout ,const glslang::TQualifier & qualifier , 5893bool lastBufferBlockMember ,bool forwardReferenceOnly ) 5894{ 5895 spv::Id spvType = spv::NoResult ; 5896 5897switch (type .getBasicType ()) { 5898case glslang::EbtVoid : 5899spvType = builder .makeVoidType (); 5900assert (!type .isArray ()); 5901break ; 5902case glslang::EbtBool : 5903// "transparent" bool doesn't exist in SPIR-V. The GLSL convention is 5904// a 32-bit int where non-0 means true. 5905if (explicitLayout != glslang::ElpNone ) 5906spvType = builder .makeUintType (32 ); 5907else 5908spvType = builder .makeBoolType (); 5909break ; 5910case glslang::EbtInt : 5911spvType = builder .makeIntType (32 ); 5912break ; 5913case glslang::EbtUint : 5914spvType = builder .makeUintType (32 ); 5915break ; 5916case glslang::EbtFloat : 5917spvType = builder .makeFloatType (32 ); 5918break ; 5919case glslang::EbtDouble : 5920spvType = builder .makeFloatType (64 ); 5921break ; 5922case glslang::EbtFloat16 : 5923spvType = builder .makeFloatType (16 ); 5924break ; 5925case glslang::EbtBFloat16 : 5926spvType = builder .makeBFloat16Type (); 5927break ; 5928case glslang::EbtFloatE5M2 : 5929spvType = builder .makeFloatE5M2Type (); 5930break ; 5931case glslang::EbtFloatE4M3 : 5932spvType = builder .makeFloatE4M3Type (); 5933break ; 5934case glslang::EbtFloatE2M1 : 5935spvType = builder .makeFloatE2M1Type (); 5936break ; 5937case glslang::EbtFloatE3M2 : 5938spvType = builder .makeFloatE3M2Type (); 5939break ; 5940case glslang::EbtFloatE2M3 : 5941spvType = builder .makeFloatE2M3Type (); 5942break ; 5943case glslang::EbtFloatUE8M0 : 5944spvType = builder .makeFloatUE8M0Type (); 5945break ; 5946case glslang::EbtFloatMXINT8 : 5947spvType = builder .makeFloatMXINT8Type (); 5948break ; 5949case glslang::EbtInt8 : 5950spvType = builder .makeIntType (8 ); 5951break ; 5952case glslang::EbtUint8 : 5953spvType = builder .makeUintType (8 ); 5954break ; 5955case glslang::EbtInt16 : 5956spvType = builder .makeIntType (16 ); 5957break ; 5958case glslang::EbtUint16 : 5959spvType = builder .makeUintType (16 ); 5960break ; 5961case glslang::EbtInt64 : 5962spvType = builder .makeIntType (64 ); 5963break ; 5964case glslang::EbtUint64 : 5965spvType = builder .makeUintType (64 ); 5966break ; 5967case glslang::EbtAtomicUint : 5968builder .addCapability (spv::Capability ::AtomicStorage ); 5969spvType = builder .makeUintType (32 ); 5970break ; 5971case glslang::EbtAccStruct : 5972switch (glslangIntermediate -> getStage ()) { 5973case EShLangRayGen : 5974case EShLangIntersect : 5975case EShLangAnyHit : 5976case EShLangClosestHit : 5977case EShLangMiss : 5978case EShLangCallable : 5979// these all should have the RayTracingNV/KHR capability already 5980break ; 5981default : 5982 { 5983auto & extensions = glslangIntermediate -> getRequestedExtensions (); 5984if (extensions .find ("GL_EXT_ray_query" )!= extensions .end ()) { 5985builder .addExtension (spv::E_SPV_KHR_ray_query ); 5986builder .addCapability (spv::Capability ::RayQueryKHR ); 5987 } 5988 } 5989break ; 5990 } 5991spvType = builder .makeAccelerationStructureType (); 5992break ; 5993case glslang::EbtRayQuery : 5994 { 5995auto & extensions = glslangIntermediate -> getRequestedExtensions (); 5996if (extensions .find ("GL_EXT_ray_query" )!= extensions .end ()) { 5997builder .addExtension (spv::E_SPV_KHR_ray_query ); 5998builder .addCapability (spv::Capability ::RayQueryKHR ); 5999 } 6000spvType = builder .makeRayQueryType (); 6001 } 6002break ; 6003case glslang::EbtReference : 6004 { 6005// Make the forward pointer, then recurse to convert the structure type, then 6006// patch up the forward pointer with a real pointer type. 6007if (forwardPointers .find (type .getReferentType ())== forwardPointers .end ()) { 6008 spv::Id forwardId = builder .makeForwardPointer (spv::StorageClass ::PhysicalStorageBufferEXT ); 6009forwardPointers [type .getReferentType ()]= forwardId ; 6010 } 6011spvType = forwardPointers [type .getReferentType ()]; 6012if (!forwardReferenceOnly ) { 6013 spv::Id referentType = convertGlslangToSpvType (* type .getReferentType ()); 6014builder .makePointerFromForwardPointer (spv::StorageClass ::PhysicalStorageBufferEXT , 6015forwardPointers [type .getReferentType ()], 6016referentType ); 6017 } 6018 } 6019break ; 6020case glslang::EbtSampler : 6021 { 6022const glslang::TSampler & sampler = type .getSampler (); 6023 std::string debugName ; 6024 6025if (sampler .isPureSampler ()) { 6026if (options .emitNonSemanticShaderDebugInfo ) { 6027if (glslangIntermediate -> getSource ()== glslang::EShSourceGlsl ) { 6028debugName = sampler .getString (); 6029 } 6030else { 6031debugName = "type.sampler" ; 6032 } 6033 } 6034spvType = builder .makeSamplerType (debugName .c_str ()); 6035 }else { 6036// an image is present, make its type 6037if (options .emitNonSemanticShaderDebugInfo ) { 6038if (glslangIntermediate -> getSource ()== glslang::EShSourceGlsl ) { 6039debugName = sampler .removeCombined ().getString (); 6040 } 6041else { 6042switch (sampler .dim ) { 6043case glslang::Esd1D :debugName = "type.1d.image" ;break ; 6044case glslang::Esd2D :debugName = "type.2d.image" ;break ; 6045case glslang::Esd3D :debugName = "type.3d.image" ;break ; 6046case glslang::EsdCube :debugName = "type.cube.image" ;break ; 6047default :debugName = "type.image" ;break ; 6048 } 6049 } 6050 } 6051spvType = builder .makeImageType (getSampledType (sampler ),TranslateDimensionality (sampler ), 6052sampler .isShadow (),sampler .isArrayed (),sampler .isMultiSample (), 6053sampler .isImageClass () ?2 :1 ,TranslateImageFormat (type ),debugName .c_str ()); 6054if (sampler .isCombined ()&& 6055 (!sampler .isBuffer ()|| glslangIntermediate -> getSpv ().spv < glslang::EShTargetSpv_1_6 )) { 6056// Already has both image and sampler, make the combined type. Only combine sampler to 6057// buffer if before SPIR-V 1.6. 6058if (options .emitNonSemanticShaderDebugInfo ) { 6059if (glslangIntermediate -> getSource ()== glslang::EShSourceGlsl ) { 6060debugName = sampler .getString (); 6061 } 6062else { 6063debugName = "type.sampled.image" ; 6064 } 6065 } 6066spvType = builder .makeSampledImageType (spvType ,debugName .c_str ()); 6067 } 6068 } 6069 } 6070break ; 6071case glslang::EbtStruct : 6072case glslang::EbtBlock : 6073 { 6074// If it's an inner declared heap buffer or uniform block, using OpTypeBufferEXT 6075// to convert it to an untyped type. 6076if (type .getQualifier ().layoutDescriptorHeap && type .getQualifier ().descriptorHeapDescriptorNode ) { 6077spvType = builder .makeUntypedPointer (TranslateStorageClass (type ), true); 6078break ; 6079 } 6080 6081// If we've seen this struct type, return it 6082const glslang::TTypeList * glslangMembers = type .getStruct (); 6083 6084// Try to share structs for different layouts, but not yet for other 6085// kinds of qualification (primarily not yet including interpolant qualification). 6086if (!HasNonLayoutQualifiers (type ,qualifier )) 6087spvType = structMap [explicitLayout ][qualifier .layoutMatrix ][glslangMembers ]; 6088if (spvType != spv::NoResult ) 6089break ; 6090 6091// else, we haven't seen it... 6092if (type .getBasicType ()== glslang::EbtBlock ) 6093memberRemapper [glslangMembers ].resize (glslangMembers -> size ()); 6094spvType = convertGlslangStructToSpvType (type ,glslangMembers ,explicitLayout ,qualifier ); 6095 } 6096break ; 6097case glslang::EbtString : 6098// no type used for OpString 6099return 0 ; 6100 6101case glslang::EbtHitObjectNV : { 6102builder .addExtension (spv::E_SPV_NV_shader_invocation_reorder ); 6103builder .addCapability (spv::Capability ::ShaderInvocationReorderNV ); 6104spvType = builder .makeHitObjectNVType (); 6105 } 6106break ; 6107 6108case glslang::EbtHitObjectEXT : { 6109builder .addExtension (spv::E_SPV_EXT_shader_invocation_reorder ); 6110builder .addCapability (spv::Capability ::ShaderInvocationReorderEXT ); 6111spvType = builder .makeHitObjectEXTType (); 6112 } 6113break ; 6114case glslang::EbtSpirvType : { 6115// GL_EXT_spirv_intrinsics 6116const auto & spirvType = type .getSpirvType (); 6117const auto & spirvInst = spirvType .spirvInst ; 6118 6119 std::vector < spv::IdImmediate > operands ; 6120for (const auto & typeParam :spirvType .typeParams ) { 6121if (typeParam .getAsConstant ()!= nullptr ) { 6122// Constant expression 6123auto constant = typeParam .getAsConstant (); 6124if (constant -> isLiteral ()) { 6125if (constant -> getBasicType ()== glslang::EbtFloat ) { 6126float floatValue = static_cast < float > (constant -> getConstArray ()[0 ].getDConst ()); 6127unsigned literal ; 6128 static_assert(sizeof (literal )== sizeof (floatValue ),"sizeof(unsigned) != sizeof(float)" ); 6129memcpy (& literal ,& floatValue ,sizeof (literal )); 6130operands .push_back ({false,literal }); 6131 }else if (constant -> getBasicType ()== glslang::EbtInt ) { 6132unsigned literal = constant -> getConstArray ()[0 ].getIConst (); 6133operands .push_back ({false,literal }); 6134 }else if (constant -> getBasicType ()== glslang::EbtUint ) { 6135unsigned literal = constant -> getConstArray ()[0 ].getUConst (); 6136operands .push_back ({false,literal }); 6137 }else if (constant -> getBasicType ()== glslang::EbtBool ) { 6138unsigned literal = constant -> getConstArray ()[0 ].getBConst (); 6139operands .push_back ({false,literal }); 6140 }else if (constant -> getBasicType ()== glslang::EbtString ) { 6141auto str = constant -> getConstArray ()[0 ].getSConst ()-> c_str (); 6142unsigned literal = 0 ; 6143char * literalPtr = reinterpret_cast < char *> (& literal ); 6144unsigned charCount = 0 ; 6145char ch = 0 ; 6146do { 6147ch = * (str ++ ); 6148* (literalPtr ++ )= ch ; 6149++ charCount ; 6150if (charCount == 4 ) { 6151operands .push_back ({false,literal }); 6152literalPtr = reinterpret_cast < char *> (& literal ); 6153charCount = 0 ; 6154 } 6155 }while (ch != 0 ); 6156 6157// Partial literal is padded with 0 6158if (charCount > 0 ) { 6159for (;charCount < 4 ;++ charCount ) 6160* (literalPtr ++ )= 0 ; 6161operands .push_back ({false,literal }); 6162 } 6163 }else 6164assert (0 );// Unexpected type 6165 }else 6166operands .push_back ({true,createSpvConstant (* constant )}); 6167 }else { 6168// Type specifier 6169assert (typeParam .getAsType ()!= nullptr ); 6170operands .push_back ({true,convertGlslangToSpvType (* typeParam .getAsType ())}); 6171 } 6172 } 6173 6174assert (spirvInst .set == "" );// Currently, couldn't be extended instructions. 6175spvType = builder .makeGenericType (static_cast < spv::Op > (spirvInst .id ),operands ); 6176 6177break ; 6178 } 6179case glslang::EbtTensorLayoutNV : 6180 { 6181builder .addCapability (spv::Capability ::TensorAddressingNV ); 6182builder .addExtension (spv::E_SPV_NV_tensor_addressing ); 6183 6184 std::vector < spv::IdImmediate > operands ; 6185for (uint32_t i = 0 ;i < 2 ;++ i ) { 6186operands .push_back ({true,makeArraySizeId (* type .getTypeParameters ()-> arraySizes ,i , true)}); 6187 } 6188spvType = builder .makeGenericType (spv::Op ::OpTypeTensorLayoutNV ,operands ); 6189break ; 6190 } 6191case glslang::EbtTensorViewNV : 6192 { 6193builder .addCapability (spv::Capability ::TensorAddressingNV ); 6194builder .addExtension (spv::E_SPV_NV_tensor_addressing ); 6195 6196uint32_t dim = type .getTypeParameters ()-> arraySizes -> getDimSize (0 ); 6197assert (dim >=1 && dim <=5 ); 6198 std::vector < spv::IdImmediate > operands ; 6199for (uint32_t i = 0 ;i < dim + 2 ;++ i ) { 6200operands .push_back ({true,makeArraySizeId (* type .getTypeParameters ()-> arraySizes ,i , true,i == 1 )}); 6201 } 6202spvType = builder .makeGenericType (spv::Op ::OpTypeTensorViewNV ,operands ); 6203break ; 6204 } 6205default : 6206assert (0 ); 6207break ; 6208 } 6209 6210if (type .isMatrix ()) 6211spvType = builder .makeMatrixType (spvType ,type .getMatrixCols (),type .getMatrixRows ()); 6212else { 6213// If this variable has a vector element count greater than 1, create a SPIR-V vector 6214if (type .getVectorSize ()> 1 ) 6215spvType = builder .makeVectorType (spvType ,type .getVectorSize ()); 6216 } 6217 6218if (type .isCoopMatNV ()) { 6219builder .addCapability (spv::Capability ::CooperativeMatrixNV ); 6220builder .addExtension (spv::E_SPV_NV_cooperative_matrix ); 6221 6222if (type .getBasicType ()== glslang::EbtFloat16 ) 6223builder .addCapability (spv::Capability ::Float16 ); 6224if (type .getBasicType ()== glslang::EbtUint8 || 6225type .getBasicType ()== glslang::EbtInt8 ) { 6226builder .addCapability (spv::Capability ::Int8 ); 6227 } 6228 6229 spv::Id scope = makeArraySizeId (* type .getTypeParameters ()-> arraySizes ,1 ); 6230 spv::Id rows = makeArraySizeId (* type .getTypeParameters ()-> arraySizes ,2 ); 6231 spv::Id cols = makeArraySizeId (* type .getTypeParameters ()-> arraySizes ,3 ); 6232 6233spvType = builder .makeCooperativeMatrixTypeNV (spvType ,scope ,rows ,cols ); 6234 } 6235 6236if (type .isCoopMatKHR ()) { 6237builder .addCapability (spv::Capability ::CooperativeMatrixKHR ); 6238builder .addExtension (spv::E_SPV_KHR_cooperative_matrix ); 6239 6240if (type .getBasicType ()== glslang::EbtBFloat16 ) { 6241builder .addExtension (spv::E_SPV_KHR_bfloat16 ); 6242builder .addCapability (spv::Capability ::BFloat16CooperativeMatrixKHR ); 6243 } 6244 6245if (type .getBasicType ()== glslang::EbtFloatE5M2 || type .getBasicType ()== glslang::EbtFloatE4M3 ) { 6246builder .addExtension (spv::E_SPV_EXT_float8 ); 6247builder .addCapability (spv::Capability ::Float8CooperativeMatrixEXT ); 6248 } 6249 6250if (type .getBasicType ()== glslang::EbtFloat16 ) 6251builder .addCapability (spv::Capability ::Float16 ); 6252if (type .getBasicType ()== glslang::EbtUint8 || type .getBasicType ()== glslang::EbtInt8 ) { 6253builder .addCapability (spv::Capability ::Int8 ); 6254 } 6255 6256 spv::Id scope = makeArraySizeId (* type .getTypeParameters ()-> arraySizes ,0 ); 6257 spv::Id rows = makeArraySizeId (* type .getTypeParameters ()-> arraySizes ,1 ); 6258 spv::Id cols = makeArraySizeId (* type .getTypeParameters ()-> arraySizes ,2 ); 6259 spv::Id use = makeArraySizeId (* type .getTypeParameters ()-> arraySizes ,3 , true); 6260 6261spvType = builder .makeCooperativeMatrixTypeKHR (spvType ,scope ,rows ,cols ,use ); 6262 } 6263else if (type .isTensorARM ()) { 6264builder .addCapability (spv::Capability ::TensorsARM ); 6265builder .addExtension (spv::E_SPV_ARM_tensors ); 6266if (type .getBasicType ()== glslang::EbtInt8 || type .getBasicType ()== glslang::EbtUint8 ) { 6267builder .addCapability (spv::Capability ::Int8 ); 6268 }else if (type .getBasicType ()== glslang::EbtInt16 || 6269type .getBasicType ()== glslang::EbtUint16 ) { 6270builder .addCapability (spv::Capability ::Int16 ); 6271 }else if (type .getBasicType ()== glslang::EbtInt64 || 6272type .getBasicType ()== glslang::EbtUint64 ) { 6273builder .addCapability (spv::Capability ::Int64 ); 6274 }else if (type .getBasicType ()== glslang::EbtFloat16 ) { 6275builder .addCapability (spv::Capability ::Float16 ); 6276 } 6277 6278 spv::Id rank = makeArraySizeId (* type .getTypeParameters ()-> arraySizes ,0 ); 6279 6280spvType = builder .makeTensorTypeARM (spvType ,rank ); 6281 } 6282 6283if (type .isCoopVecNV ()) { 6284builder .addCapability (spv::Capability ::CooperativeVectorNV ); 6285builder .addExtension (spv::E_SPV_NV_cooperative_vector ); 6286 6287if (type .getBasicType ()== glslang::EbtFloat16 ) 6288builder .addCapability (spv::Capability ::Float16 ); 6289if (type .getBasicType ()== glslang::EbtUint8 || type .getBasicType ()== glslang::EbtInt8 ) { 6290builder .addCapability (spv::Capability ::Int8 ); 6291 } 6292 6293 spv::Id components = makeArraySizeId (* type .getTypeParameters ()-> arraySizes ,0 ); 6294 6295spvType = builder .makeCooperativeVectorTypeNV (spvType ,components ); 6296 } 6297 6298if (type .isLongVector ()) { 6299// SPIR-V LongVectorEXT not needed when component count is literal 2-4. 6300const bool needLongVectorCap = type .hasSpecConstantVectorComponents ()|| 6301 (type .getTypeParameters ()-> arraySizes -> getDimSize (0 )< 2 || 6302type .getTypeParameters ()-> arraySizes -> getDimSize (0 )> 4 ); 6303if (needLongVectorCap ) { 6304builder .addCapability (spv::Capability ::LongVectorEXT ); 6305builder .addExtension (spv::E_SPV_EXT_long_vector ); 6306 } 6307 6308if (type .getBasicType ()== glslang::EbtFloat16 ) 6309builder .addCapability (spv::Capability ::Float16 ); 6310if (type .getBasicType ()== glslang::EbtUint8 || type .getBasicType ()== glslang::EbtInt8 ) { 6311builder .addCapability (spv::Capability ::Int8 ); 6312 } 6313 6314if (type .hasSpecConstantVectorComponents ()) { 6315 spv::Id components = makeArraySizeId (* type .getTypeParameters ()-> arraySizes ,0 ); 6316spvType = builder .makeCooperativeVectorTypeNV (spvType ,components ); 6317 }else { 6318spvType = builder .makeVectorType (spvType ,type .getTypeParameters ()-> arraySizes -> getDimSize (0 )); 6319 } 6320 } 6321 6322if (type .isArray ()) { 6323if (type .getQualifier ().layoutDescriptorHeap && containsDescHeapDescriptorType (type )) { 6324 std::vector < spv::Id > arrayStrides = descHeapLayout .getOrCreateArrayStrides (type ); 6325assert ((int )arrayStrides .size ()== type .getArraySizes ()-> getNumDims ()); 6326int strideIndex = 0 ; 6327 6328for (int dim = type .getArraySizes ()-> getNumDims ()- 1 ;dim > 0 ;-- dim ) { 6329spvType = builder .makeArrayType (spvType ,makeArraySizeId (* type .getArraySizes (),dim ),1 ); 6330builder .addDecorationId (spvType , spv::Decoration ::ArrayStrideIdEXT ,arrayStrides [strideIndex ++ ]); 6331 } 6332 6333if (type .isSizedArray ()&& !type .isImplicitlySizedArray ()) 6334spvType = builder .makeArrayType (spvType ,makeArraySizeId (* type .getArraySizes (),0 ),1 ); 6335else 6336spvType = builder .makeRuntimeArray (spvType ); 6337builder .addDecorationId (spvType , spv::Decoration ::ArrayStrideIdEXT ,arrayStrides [strideIndex ]); 6338 }else { 6339 glslang::TLayoutPacking arrayLayout = type .getQualifier ().layoutDescriptorHeap ? glslang::ElpScalar :explicitLayout ; 6340int stride = 0 ;// keep this 0 unless doing an explicit layout; 0 will mean no decoration, no stride 6341 6342// Do all but the outer dimension 6343if (type .getArraySizes ()-> getNumDims ()> 1 ) { 6344// We need to decorate array strides for types needing explicit layout, except blocks. 6345if (arrayLayout != glslang::ElpNone && type .getBasicType ()!= glslang::EbtBlock ) { 6346// Use a dummy glslang type for querying internal strides of 6347// arrays of arrays, but using just a one-dimensional array. 6348 glslang::TType simpleArrayType (type ,0 );// deference type of the array 6349while (simpleArrayType .getArraySizes ()-> getNumDims ()> 1 ) 6350simpleArrayType .getArraySizes ()-> dereference (); 6351 6352// Will compute the higher-order strides here, rather than making a whole 6353// pile of types and doing repetitive recursion on their contents. 6354stride = getArrayStride (simpleArrayType ,arrayLayout ,qualifier .layoutMatrix ); 6355 } 6356 6357// make the arrays 6358for (int dim = type .getArraySizes ()-> getNumDims ()- 1 ;dim > 0 ;-- dim ) { 6359spvType = builder .makeArrayType (spvType ,makeArraySizeId (* type .getArraySizes (),dim ),stride ); 6360if (stride > 0 ) 6361builder .addDecoration (spvType , spv::Decoration ::ArrayStride ,stride ); 6362stride *=type .getArraySizes ()-> getDimSize (dim ); 6363 } 6364 }else { 6365// single-dimensional array, and don't yet have stride 6366// We need to decorate array strides for types needing explicit layout, except blocks. 6367if (arrayLayout != glslang::ElpNone && type .getBasicType ()!= glslang::EbtBlock ) 6368stride = getArrayStride (type ,arrayLayout ,qualifier .layoutMatrix ); 6369 } 6370 6371// Do the outer dimension, which might not be known for a runtime-sized array. 6372// (Unsized arrays that survive through linking will be runtime-sized arrays) 6373const bool useRuntimeDescHeapArray = 6374type .getQualifier ().layoutDescriptorHeap && type .isImplicitlySizedArray (); 6375if (type .isSizedArray ()&& !useRuntimeDescHeapArray ) 6376spvType = builder .makeArrayType (spvType ,makeArraySizeId (* type .getArraySizes (),0 ),stride ); 6377else { 6378// If we see an runtime array in a buffer_reference, it is not a descriptor 6379if (!lastBufferBlockMember && type .getBasicType ()!= glslang::EbtReference && 6380 !type .getQualifier ().layoutDescriptorHeap ) { 6381builder .addIncorporatedExtension ("SPV_EXT_descriptor_indexing" , spv::Spv_1_5 ); 6382builder .addCapability (spv::Capability ::RuntimeDescriptorArrayEXT ); 6383 } 6384spvType = builder .makeRuntimeArray (spvType ); 6385 } 6386if (stride > 0 ) 6387builder .addDecoration (spvType , spv::Decoration ::ArrayStride ,stride ); 6388 } 6389 } 6390 6391return spvType ; 6392} 6393 6394// Apply SPIR-V decorations to the SPIR-V object (provided by SPIR-V ID). If member index is provided, the 6395// decorations are applied to this member. 6396void TGlslangToSpvTraverser ::applySpirvDecorate (const glslang::TType & type , spv::Id id , std::optional < int > member ) 6397{ 6398assert (type .getQualifier ().hasSpirvDecorate ()); 6399 6400const glslang::TSpirvDecorate & spirvDecorate = type .getQualifier ().getSpirvDecorate (); 6401 6402// Add spirv_decorate 6403for (auto & decorate :spirvDecorate .decorates ) { 6404if (!decorate .second .empty ()) { 6405 std::vector < unsigned > literals ; 6406TranslateLiterals (decorate .second ,literals ); 6407if (member .has_value ()) 6408builder .addMemberDecoration (id ,* member ,static_cast < spv::Decoration > (decorate .first ),literals ); 6409else 6410builder .addDecoration (id ,static_cast < spv::Decoration > (decorate .first ),literals ); 6411 }else { 6412if (member .has_value ()) 6413builder .addMemberDecoration (id ,* member ,static_cast < spv::Decoration > (decorate .first )); 6414else 6415builder .addDecoration (id ,static_cast < spv::Decoration > (decorate .first )); 6416 } 6417 } 6418 6419// Add spirv_decorate_id 6420if (member .has_value ()) { 6421// spirv_decorate_id not applied to members 6422assert (spirvDecorate .decorateIds .empty ()); 6423 }else { 6424for (auto & decorateId :spirvDecorate .decorateIds ) { 6425 std::vector < spv::Id > operandIds ; 6426assert (!decorateId .second .empty ()); 6427for (auto extraOperand :decorateId .second ) { 6428if (extraOperand -> getQualifier ().isFrontEndConstant ()) 6429operandIds .push_back (createSpvConstant (* extraOperand )); 6430else 6431operandIds .push_back (getSymbolId (extraOperand -> getAsSymbolNode ())); 6432 } 6433builder .addDecorationId (id ,static_cast < spv::Decoration > (decorateId .first ),operandIds ); 6434 } 6435 } 6436 6437// Add spirv_decorate_string 6438for (auto & decorateString :spirvDecorate .decorateStrings ) { 6439 std::vector < const char *> strings ; 6440assert (!decorateString .second .empty ()); 6441for (auto extraOperand :decorateString .second ) { 6442const char * string = extraOperand -> getConstArray ()[0 ].getSConst ()-> c_str (); 6443strings .push_back (string ); 6444 } 6445if (member .has_value ()) 6446builder .addMemberDecoration (id ,* member ,static_cast < spv::Decoration > (decorateString .first ),strings ); 6447else 6448builder .addDecoration (id ,static_cast < spv::Decoration > (decorateString .first ),strings ); 6449 } 6450} 6451 6452// TODO: this functionality should exist at a higher level, in creating the AST 6453// 6454// Identify interface members that don't have their required extension turned on. 6455// 6456bool TGlslangToSpvTraverser ::filterMember (const glslang::TType & member ) 6457{ 6458auto & extensions = glslangIntermediate -> getRequestedExtensions (); 6459 6460if (member .getFieldName ()== "gl_SecondaryViewportMaskNV" && 6461extensions .find ("GL_NV_stereo_view_rendering" )== extensions .end ()) 6462return true; 6463if (member .getFieldName ()== "gl_SecondaryPositionNV" && 6464extensions .find ("GL_NV_stereo_view_rendering" )== extensions .end ()) 6465return true; 6466 6467if (glslangIntermediate -> getStage ()== EShLangMesh ) { 6468if (member .getFieldName ()== "gl_PrimitiveShadingRateEXT" && 6469extensions .find ("GL_EXT_fragment_shading_rate" )== extensions .end ()) 6470return true; 6471 } 6472 6473if (glslangIntermediate -> getStage ()!= EShLangMesh ) { 6474if ((member .getFieldName ()== "gl_ViewportMask" || member .getFieldName ()== "gl_ViewportIndex" || 6475member .getFieldName ()== "gl_Layer" )&& 6476extensions .find ("GL_NV_viewport_array2" )== extensions .end ()) 6477return true; 6478if (member .getFieldName ()== "gl_PositionPerViewNV" && 6479extensions .find ("GL_NVX_multiview_per_view_attributes" )== extensions .end ()) 6480return true; 6481if (member .getFieldName ()== "gl_ViewportMaskPerViewNV" && 6482extensions .find ("GL_NVX_multiview_per_view_attributes" )== extensions .end ()) 6483return true; 6484// The front end hides these where it owns a copy of the block. One it never had to 6485// copy up, like the sized tessellation gl_in, still has the shared type. 6486if (member .getFieldName ()== "gl_ClipDistance" || member .getFieldName ()== "gl_CullDistance" ) { 6487if (glslangIntermediate -> getProfile ()== EEsProfile && 6488extensions .find ("GL_EXT_clip_cull_distance" )== extensions .end ()) 6489return true; 6490if (member .getFieldName ()== "gl_CullDistance" && 6491glslangIntermediate -> getProfile ()!= EEsProfile && glslangIntermediate -> getVersion ()< 450 && 6492extensions .find ("GL_ARB_cull_distance" )== extensions .end ()) 6493return true; 6494 } 6495 } 6496 6497return false; 6498} 6499 6500// Do full recursive conversion of a glslang structure (or block) type to a SPIR-V Id. 6501// explicitLayout can be kept the same throughout the hierarchical recursive walk. 6502// Mutually recursive with convertGlslangToSpvType(). 6503spv::Id TGlslangToSpvTraverser ::convertGlslangStructToSpvType (const glslang::TType & type , 6504const glslang::TTypeList * glslangMembers , 6505 glslang::TLayoutPacking explicitLayout , 6506const glslang::TQualifier & qualifier ) 6507{ 6508// Create a vector of struct types for SPIR-V to consume 6509 std::vector < spv::Id > spvMembers ; 6510int memberDelta = 0 ;// how much the member's index changes from glslang to SPIR-V, normally 0, 6511// except sometimes for blocks 6512 std::vector < std::pair < glslang::TType * , glslang::TQualifier > > deferredForwardPointers ; 6513 std::vector < spv::StructMemberDebugInfo > memberDebugInfo ; 6514for (int i = 0 ;i < (int )glslangMembers -> size ();i ++ ) { 6515auto & glslangMember = (* glslangMembers )[i ]; 6516if (glslangMember .type -> hiddenMember ()) { 6517++ memberDelta ; 6518if (type .getBasicType ()== glslang::EbtBlock ) 6519memberRemapper [glslangMembers ][i ]= -1 ; 6520 }else { 6521if (type .getBasicType ()== glslang::EbtBlock ) { 6522if (filterMember (* glslangMember .type )) { 6523memberDelta ++ ; 6524memberRemapper [glslangMembers ][i ]= -1 ; 6525continue ; 6526 } 6527memberRemapper [glslangMembers ][i ]= i - memberDelta ; 6528 } 6529// modify just this child's view of the qualifier 6530 glslang::TQualifier memberQualifier = glslangMember .type -> getQualifier (); 6531InheritQualifiers (memberQualifier ,qualifier ); 6532 6533// manually inherit location 6534if (!memberQualifier .hasLocation ()&& qualifier .hasLocation ()) 6535memberQualifier .layoutLocation = qualifier .layoutLocation ; 6536 6537// recurse 6538bool lastBufferBlockMember = qualifier .storage == glslang::EvqBuffer && 6539i == (int )glslangMembers -> size ()- 1 ; 6540 6541// Make forward pointers for any pointer members. 6542if (glslangMember .type -> isReference ()&& 6543forwardPointers .find (glslangMember .type -> getReferentType ())== forwardPointers .end ()) { 6544deferredForwardPointers .push_back (std::make_pair (glslangMember .type ,memberQualifier )); 6545 } 6546 6547// Create the member type. 6548auto const spvMember = convertGlslangToSpvType (* glslangMember .type ,explicitLayout ,memberQualifier ,lastBufferBlockMember , 6549glslangMember .type -> isReference ()); 6550spvMembers .push_back (spvMember ); 6551 6552// Update the builder with the type's location so that we can create debug types for the structure members. 6553// There doesn't exist a "clean" entry point for this information to be passed along to the builder so, for now, 6554// it is stored in the builder and consumed during the construction of composite debug types. 6555// TODO: This probably warrants further investigation. This approach was decided to be the least ugly of the 6556// quick and dirty approaches that were tried. 6557// Advantages of this approach: 6558// + Relatively clean. No direct calls into debug type system. 6559// + Handles nested recursive structures. 6560// Disadvantages of this approach: 6561// + Not as clean as desired. Traverser queries/sets persistent state. This is fragile. 6562// + Table lookup during creation of composite debug types. This really shouldn't be necessary. 6563if (options .emitNonSemanticShaderDebugInfo ) { 6564 spv::StructMemberDebugInfo debugInfo {}; 6565debugInfo .name = glslangMember .type -> getFieldName (); 6566debugInfo .line = glslangMember .loc .line ; 6567debugInfo .column = glslangMember .loc .column ; 6568 6569// Per the GLSL spec, bool variables inside of a uniform or buffer block are generated as uint. 6570// But for debug info, we want to represent them as bool because that is the original type in 6571// the source code. The bool type can be nested within a vector or a multidimensional array, 6572// so we must construct the chain of types up from the scalar bool. 6573if (glslangIntermediate -> getSource ()== glslang::EShSourceGlsl && explicitLayout != glslang::ElpNone && 6574glslangMember .type -> getBasicType ()== glslang::EbtBool ) { 6575auto typeId = builder .makeBoolType (); 6576if (glslangMember .type -> isVector ()) { 6577typeId = builder .makeVectorType (typeId ,glslangMember .type -> getVectorSize ()); 6578 } 6579if (glslangMember .type -> isArray ()) { 6580const auto * arraySizes = glslangMember .type -> getArraySizes (); 6581int dims = arraySizes -> getNumDims (); 6582for (int i = dims - 1 ;i >=0 ;-- i ) { 6583 spv::Id size = builder .makeIntConstant (arraySizes -> getDimSize (i )); 6584typeId = builder .makeArrayType (typeId ,size ,0 ); 6585 } 6586 } 6587debugInfo .debugTypeOverride = builder .getDebugType (typeId ); 6588 }else if (glslangMember .type -> getQualifier ().builtIn != glslang::EbvNone ) { 6589// TODO - The built-in currently are not provide the correct line/column and spirv-val will validate these when using shaderDebugInfo 6590// 6591// There is a larger issue because even defining the builtIn such as 6592// 6593// out gl_PerVertex { 6594// vec4 gl_Position; 6595// }; 6596// 6597// in the shader also doesn't produce the correct line/column 6598// So for now, provide zero, as that is a valid value here 6599debugInfo .line = 0 ; 6600debugInfo .column = 0 ; 6601 } 6602 6603memberDebugInfo .push_back (debugInfo ); 6604 } 6605 } 6606 } 6607 6608// OffsetIdEXT must only be applied to members of structs where the struct 6609// contains at least one <<Descriptor,descriptor>> type. 6610const bool useDescHeapIdDecorations = qualifier .layoutDescriptorHeap && 6611 !type .getQualifier ().descriptorHeapDescriptorNode && containsDescHeapDescriptorType (type ); 6612 6613// Prepare the layout ids for the descriptor heap struct. 6614 std::vector < spv::Id > descHeapMemberOffsets ; 6615if (useDescHeapIdDecorations ) 6616descHeapMemberOffsets = descHeapLayout .getOrCreateStructMemberOffsets (type ); 6617 6618// Make the SPIR-V type 6619 spv::Id spvType = builder .makeStructType (spvMembers ,memberDebugInfo ,type .getTypeName ().c_str (), false); 6620if (!HasNonLayoutQualifiers (type ,qualifier )) 6621structMap [explicitLayout ][qualifier .layoutMatrix ][glslangMembers ]= spvType ; 6622 6623// Decorate it 6624if (useDescHeapIdDecorations ) { 6625// Only the top-level heap layout struct represents a resourceheap/samplerheap block. 6626// If its last member is a runtime array, Vulkan still requires the struct type to 6627// carry Block/BufferBlock; nested heap member structs should not get this decoration. 6628const bool isTopLevelHeapStruct = 6629qualifier .storage == glslang::EvqResourceHeap || 6630qualifier .storage == glslang::EvqSamplerHeap ; 6631if (isTopLevelHeapStruct && glslangIntermediate -> getSpv ().vulkan > 0 && !spvMembers .empty ()&& 6632builder .getOpCode (spvMembers .back ())== spv::Op ::OpTypeRuntimeArray ) { 6633builder .addDecoration (spvType ,TranslateBlockDecoration (qualifier .storage , 6634glslangIntermediate -> usingStorageBuffer ())); 6635 } 6636 6637assert (descHeapMemberOffsets .size ()== glslangMembers -> size ()); 6638for (int member = 0 ;member < (int )glslangMembers -> size ()&& member < (int )spvMembers .size ();++ member ) { 6639 glslang::TType & glslangMember = * (* glslangMembers )[member ].type ; 6640 6641// Decorate offset. 6642builder .addMemberDecorationIdEXT (spvType ,member , spv::Decoration ::OffsetIdEXT , 6643 {descHeapMemberOffsets [member ]}); 6644 6645// Decorate matrix layout. 6646 glslang::TQualifier memberQualifier = glslangMember .getQualifier (); 6647InheritQualifiers (memberQualifier ,qualifier ); 6648if (!glslangMember .isMatrix ()|| memberQualifier .layoutMatrix == glslang::ElmNone ) 6649continue ; 6650 6651builder .addMemberDecoration (spvType ,member , 6652TranslateLayoutDecoration (glslangMember ,memberQualifier .layoutMatrix )); 6653builder .addMemberDecoration (spvType ,member , spv::Decoration ::MatrixStride , 6654getMatrixStride (glslangMember , glslang::ElpScalar ,memberQualifier .layoutMatrix )); 6655 } 6656 }else if (qualifier .layoutDescriptorHeap ) { 6657if (!type .getQualifier ().descriptorHeapDescriptorNode ) 6658decorateStructType (type ,glslangMembers , glslang::ElpScalar ,qualifier ,spvType ,spvMembers ); 6659 }else { 6660decorateStructType (type ,glslangMembers ,explicitLayout ,qualifier ,spvType ,spvMembers ); 6661 } 6662 6663for (int i = 0 ;i < (int )deferredForwardPointers .size ();++ i ) { 6664auto it = deferredForwardPointers [i ]; 6665convertGlslangToSpvType (* it .first ,explicitLayout ,it .second , false); 6666 } 6667 6668return spvType ; 6669} 6670 6671// Keep access to the traverser state needed to emit layout ids. 6672DescHeapLayoutEmitter ::DescHeapLayoutEmitter (TGlslangToSpvTraverser & traverser ) 6673 :traverser (traverser ) 6674{ 6675} 6676 6677// Return true when this type is a descriptor payload in a descriptor heap. 6678bool DescHeapLayoutEmitter ::isDescriptorPayload (const glslang::TType & type )const 6679{ 6680if (type .isArray ()) { 6681 glslang::TType elementTy (type ,0 ); 6682return isDescriptorPayload (elementTy ); 6683 } 6684 6685return type .getQualifier ().descriptorHeapDescriptorNode ; 6686} 6687 6688// Return true when this type or a nested member contains a descriptor payload. 6689bool DescHeapLayoutEmitter ::containsDescriptorPayload (const glslang::TType & type )const 6690{ 6691if (isDescriptorPayload (type )) 6692return true; 6693 6694if (type .isArray ()) { 6695// The element can be a struct containing descriptor payload members. 6696 glslang::TType elementTy (type ,0 ); 6697return containsDescriptorPayload (elementTy ); 6698 } 6699 6700if (type .isStruct ()) { 6701const glslang::TTypeList * structTyList = type .getStruct (); 6702for (const auto & member :* structTyList ) { 6703if (containsDescriptorPayload (* member .type )) 6704return true; 6705 } 6706 } 6707 6708return false; 6709} 6710 6711// Return the heap size id for one non-array value. 6712spv::Id DescHeapLayoutEmitter ::getOrCreateValueSize (const glslang::TType & type ) 6713{ 6714assert (!type .isArray ()); 6715if (type .isStruct ()&& !isDescriptorPayload (type )&& containsDescriptorPayload (type )) 6716return getOrCreateStructSize (type ); 6717 6718auto cachedSize = valueSizeCache .find (& type ); 6719if (cachedSize != valueSizeCache .end ()) 6720return cachedSize -> second ; 6721 6722 spv::Id size = computeValueSize (type ); 6723return valueSizeCache .emplace (& type ,size ).first -> second ; 6724} 6725 6726// Return the placement alignment id for one non-array value. 6727spv::Id DescHeapLayoutEmitter ::getOrCreateValueAlignment (const glslang::TType & type ) 6728{ 6729assert (!type .isArray ()); 6730if (type .isStruct ()&& !isDescriptorPayload (type )&& containsDescriptorPayload (type )) 6731return getOrCreateStructAlignment (type ); 6732 6733auto cachedAlignment = valueAlignmentCache .find (& type ); 6734if (cachedAlignment != valueAlignmentCache .end ()) 6735return cachedAlignment -> second ; 6736 6737 spv::Id alignment = computeValueAlignment (type ); 6738return valueAlignmentCache .emplace (& type ,alignment ).first -> second ; 6739} 6740 6741// Return the total heap size id for a sized array. 6742spv::Id DescHeapLayoutEmitter ::getOrCreateArraySize (const glslang::TType & arrayType ) 6743{ 6744assert (arrayType .isArray ()); 6745auto cachedSize = arraySizeCache .find (& arrayType ); 6746if (cachedSize != arraySizeCache .end ()) 6747return cachedSize -> second ; 6748 6749 spv::Id size = spv::NoResult ; 6750if (!containsDescriptorPayload (arrayType )) { 6751int scalarSize ; 6752int stride ; 6753traverser .glslangIntermediate -> getMemberAlignment ( 6754arrayType ,scalarSize ,stride , glslang::ElpScalar , 6755arrayType .getQualifier ().layoutMatrix == glslang::ElmRowMajor ); 6756size = makeUint (scalarSize ); 6757 }else if (!arrayType .isImplicitlySizedArray ()) { 6758 std::vector < spv::Id > strides = getOrCreateArrayStrides (arrayType ); 6759assert (!strides .empty ()); 6760size = makeSpecOp (spv::Op ::OpIMul , 6761 {strides .back (),traverser .makeArraySizeId (* arrayType .getArraySizes (),0 )}); 6762 } 6763// Runtime arrays do not have a finite total size. 6764 6765return arraySizeCache .emplace (& arrayType ,size ).first -> second ; 6766} 6767 6768// Return the placement alignment id for an array member. 6769spv::Id DescHeapLayoutEmitter ::getOrCreateArrayAlignment (const glslang::TType & arrayType ) 6770{ 6771assert (arrayType .isArray ()); 6772auto cachedAlignment = arrayAlignmentCache .find (& arrayType ); 6773if (cachedAlignment != arrayAlignmentCache .end ()) 6774return cachedAlignment -> second ; 6775 6776 spv::Id alignment = spv::NoResult ; 6777if (!containsDescriptorPayload (arrayType )) { 6778int size ; 6779int stride ; 6780int scalarAlignment = traverser .glslangIntermediate -> getMemberAlignment ( 6781arrayType ,size ,stride , glslang::ElpScalar , 6782arrayType .getQualifier ().layoutMatrix == glslang::ElmRowMajor ); 6783alignment = makeUint (scalarAlignment ); 6784 }else { 6785 glslang::TType elementTy ; 6786getInnermostArrayElementType (arrayType ,elementTy ); 6787alignment = computeValueAlignment (elementTy ); 6788 } 6789 6790return arrayAlignmentCache .emplace (& arrayType ,alignment ).first -> second ; 6791} 6792 6793// Return ArrayStrideIdEXT operand ids from inner dimension to outer dimension. 6794std::vector < spv::Id > DescHeapLayoutEmitter ::getOrCreateArrayStrides ( 6795const glslang::TType & arrayType ) 6796{ 6797assert (arrayType .isArray ()); 6798auto cachedStrides = arrayStridesCache .find (& arrayType ); 6799if (cachedStrides != arrayStridesCache .end ()) 6800return cachedStrides -> second ; 6801 6802 std::vector < spv::Id > strides ; 6803if (!containsDescriptorPayload (arrayType )) { 6804int size ; 6805int stride ; 6806traverser .glslangIntermediate -> getMemberAlignment ( 6807arrayType ,size ,stride , glslang::ElpScalar , 6808arrayType .getQualifier ().layoutMatrix == glslang::ElmRowMajor ); 6809if (stride > 0 ) 6810strides .push_back (makeUint (stride )); 6811 }else { 6812 glslang::TType elementTy ; 6813getInnermostArrayElementType (arrayType ,elementTy ); 6814 spv::Id stride = spv::NoResult ; 6815if (isDescriptorPayload (arrayType )&& 6816arrayType .getQualifier ().layoutDescriptorStride != glslang::TQualifier ::layoutDescriptorStrideEnd ) 6817stride = makeUint (arrayType .getQualifier ().layoutDescriptorStride ); 6818else if (isDescriptorPayload (arrayType )&& 6819arrayType .getQualifier ().layoutDescriptorSize != glslang::TQualifier ::layoutDescriptorSizeEnd ) 6820stride = makeUint (arrayType .getQualifier ().layoutDescriptorSize ); 6821else 6822stride = computeValueSize (elementTy ); 6823const glslang::TArraySizes * arraySizes = arrayType .getArraySizes (); 6824for (int dim = arraySizes -> getNumDims ()- 1 ;dim >=0 ;-- dim ) { 6825strides .push_back (stride ); 6826if (dim > 0 ) 6827stride = makeSpecOp (spv::Op ::OpIMul , {stride ,traverser .makeArraySizeId (* arraySizes ,dim )}); 6828 } 6829 } 6830 6831return arrayStridesCache .emplace (& arrayType ,strides ).first -> second ; 6832} 6833 6834// Create a 32-bit unsigned constant id. 6835spv::Id DescHeapLayoutEmitter ::makeUint (unsigned value ) 6836{ 6837return traverser .builder .makeUintConstant (value ); 6838} 6839 6840// Create a 32-bit unsigned OpSpecConstantOp id. 6841spv::Id DescHeapLayoutEmitter ::makeSpecOp (spv::Op op , 6842const std::vector < spv::Id >& operands ) 6843{ 6844return traverser .builder .createSpecConstantOp (op ,traverser .builder .makeUintType (32 ),operands , {}); 6845} 6846 6847// Return the byte footprint id for a struct member. 6848spv::Id DescHeapLayoutEmitter ::getMemberSize (const glslang::TType & memberType ) 6849{ 6850if (!memberType .isArray ()) 6851return getOrCreateValueSize (memberType ); 6852 6853 spv::Id arraySize = getOrCreateArraySize (memberType ); 6854if (arraySize != spv::NoResult ) 6855return arraySize ; 6856 6857// Runtime arrays have no finite footprint. The stride fallback is only 6858// valid for the legal last-member case. 6859assert (memberType .isImplicitlySizedArray ()); 6860 std::vector < spv::Id > strides = getOrCreateArrayStrides (memberType ); 6861assert (!strides .empty ()); 6862return strides .back (); 6863} 6864 6865// Return the placement alignment id for a struct member. 6866spv::Id DescHeapLayoutEmitter ::getMemberAlignment (const glslang::TType & memberType ) 6867{ 6868return memberType .isArray () ?getOrCreateArrayAlignment (memberType ) : 6869getOrCreateValueAlignment (memberType ); 6870} 6871 6872// Return member offset ids relative to the start of this struct. 6873std::vector < spv::Id > DescHeapLayoutEmitter ::getOrCreateStructMemberOffsets ( 6874const glslang::TType & structType ) 6875{ 6876assert (structType .isStruct ()); 6877 6878const glslang::TTypeList * structTyList = structType .getStruct (); 6879auto cachedOffsets = structMemberOffsetsCache .find (structTyList ); 6880if (cachedOffsets != structMemberOffsetsCache .end ()) 6881return cachedOffsets -> second ; 6882 6883 std::vector < spv::Id > memberOffsets ; 6884memberOffsets .reserve (structTyList -> size ()); 6885 6886const glslang::TType * previousMemberTy = nullptr ; 6887 spv::Id currentOffset = makeUint (0 ); 6888for (int i = 0 ;i < (int )structTyList -> size ();++ i ) { 6889const glslang::TType & memberTy = * (* structTyList )[i ].type ; 6890 6891if (memberTy .getQualifier ().hasOffset ()) { 6892currentOffset = makeUint (memberTy .getQualifier ().layoutOffset ); 6893 }else if (previousMemberTy != nullptr ) { 6894 spv::Id offsetNotAligned = makeSpecOp (spv::Op ::OpIAdd , {currentOffset ,getMemberSize (* previousMemberTy )}); 6895currentOffset = traverser .builder .createSpecConstantAlignTo (offsetNotAligned ,getMemberAlignment (memberTy )); 6896 } 6897 6898memberOffsets .push_back (currentOffset ); 6899 6900previousMemberTy = & memberTy ; 6901 } 6902 6903return structMemberOffsetsCache .emplace (structTyList ,memberOffsets ).first -> second ; 6904} 6905 6906// Return the max member alignment id for a descriptor-containing struct. 6907spv::Id DescHeapLayoutEmitter ::getOrCreateStructAlignment ( 6908const glslang::TType & structType ) 6909{ 6910assert (structType .isStruct ()); 6911 6912const glslang::TTypeList * structTyList = structType .getStruct (); 6913auto cachedAlignment = structAlignmentCache .find (structTyList ); 6914if (cachedAlignment != structAlignmentCache .end ()) 6915return cachedAlignment -> second ; 6916 6917 spv::Id alignment = spv::NoResult ; 6918for (int i = 0 ;i < (int )structTyList -> size ();++ i ) { 6919 spv::Id memberAlignment = getMemberAlignment (* (* structTyList )[i ].type ); 6920alignment = alignment == spv::NoResult ?memberAlignment : 6921traverser .builder .createSpecConstantSelectMax (alignment ,memberAlignment ); 6922 } 6923 6924if (alignment == spv::NoResult ) 6925alignment = makeUint (1 ); 6926 6927return structAlignmentCache .emplace (structTyList ,alignment ).first -> second ; 6928} 6929 6930// Return the padded heap size id for a descriptor-containing struct. 6931spv::Id DescHeapLayoutEmitter ::getOrCreateStructSize (const glslang::TType & structType ) 6932{ 6933assert (structType .isStruct ()); 6934 6935const glslang::TTypeList * structTyList = structType .getStruct (); 6936auto cachedSize = structSizeCache .find (structTyList ); 6937if (cachedSize != structSizeCache .end ()) 6938return cachedSize -> second ; 6939 6940 spv::Id size = spv::NoResult ; 6941if (structTyList -> empty ()) { 6942size = makeUint (0 ); 6943 }else { 6944 std::vector < spv::Id > memberOffsets = getOrCreateStructMemberOffsets (structType ); 6945const glslang::TType & lastMemberTy = * structTyList -> back ().type ; 6946 spv::Id rawSize = makeSpecOp (spv::Op ::OpIAdd , {memberOffsets .back (),getMemberSize (lastMemberTy )}); 6947size = traverser .builder .createSpecConstantAlignTo (rawSize ,getOrCreateStructAlignment (structType )); 6948 } 6949 6950return structSizeCache .emplace (structTyList ,size ).first -> second ; 6951} 6952 6953// Compute the heap size id without writing the TType* value-size cache. 6954spv::Id DescHeapLayoutEmitter ::computeValueSize (const glslang::TType & type ) 6955{ 6956assert (!type .isArray ()); 6957 6958if (isDescriptorPayload (type )) { 6959if (type .getQualifier ().layoutDescriptorSize != glslang::TQualifier ::layoutDescriptorSizeEnd ) 6960return makeUint (type .getQualifier ().layoutDescriptorSize ); 6961return traverser .builder .createConstantSizeOfEXT (traverser .convertGlslangToSpvType (type )); 6962 } 6963 6964if (type .isStruct ()&& containsDescriptorPayload (type )) 6965return getOrCreateStructSize (type ); 6966 6967int size ; 6968int stride ; 6969int alignment = traverser .glslangIntermediate -> getMemberAlignment ( 6970type ,size ,stride , glslang::ElpScalar , 6971type .getQualifier ().layoutMatrix == glslang::ElmRowMajor ); 6972 glslang::RoundToPow2 (size ,alignment ); 6973return makeUint (size ); 6974} 6975 6976// Compute the alignment id without writing the TType* value-alignment cache. 6977spv::Id DescHeapLayoutEmitter ::computeValueAlignment (const glslang::TType & type ) 6978{ 6979assert (!type .isArray ()); 6980 6981if (isDescriptorPayload (type )) 6982return computeValueSize (type ); 6983 6984if (type .isStruct ()&& containsDescriptorPayload (type )) 6985return getOrCreateStructAlignment (type ); 6986 6987int size ; 6988int stride ; 6989int alignment = traverser .glslangIntermediate -> getMemberAlignment ( 6990type ,size ,stride , glslang::ElpScalar , 6991type .getQualifier ().layoutMatrix == glslang::ElmRowMajor ); 6992return makeUint (alignment ); 6993} 6994 6995// Fill a local non-array element type for an array type. 6996void DescHeapLayoutEmitter ::getInnermostArrayElementType (const glslang::TType & arrayType , 6997 glslang::TType & elementType )const 6998{ 6999assert (arrayType .isArray ()); 7000 7001// Peel array dimensions on this local copy only. 7002 glslang::TType arrayElementTy (arrayType ,0 ); 7003elementType .shallowCopy (arrayElementTy ); 7004if (elementType .isArray ()) 7005elementType .clearArraySizes (); 7006} 7007 7008// Return true only when the type itself is a descriptor heap payload. Arrays are 7009// unwrapped so descriptor arrays are treated as descriptor payloads too. 7010bool TGlslangToSpvTraverser ::isDescHeapDescriptorType (const glslang::TType & type )const 7011{ 7012if (type .isArray ()) { 7013 glslang::TType elementTy (type ,0 ); 7014return isDescHeapDescriptorType (elementTy ); 7015 } 7016 7017return type .getQualifier ().descriptorHeapDescriptorNode ; 7018} 7019 7020// Return true when this type or any nested array/struct member contains a 7021// descriptor heap payload. This decides whether heap Id decorations are needed. 7022bool TGlslangToSpvTraverser ::containsDescHeapDescriptorType (const glslang::TType & type )const 7023{ 7024if (isDescHeapDescriptorType (type )) 7025return true; 7026 7027if (type .isArray ()) { 7028 glslang::TType elementTy (type ,0 ); 7029return containsDescHeapDescriptorType (elementTy ); 7030 } 7031 7032if (type .isStruct ()) { 7033const glslang::TTypeList * structTyList = type .getStruct (); 7034for (const auto & member :* structTyList ) { 7035if (containsDescHeapDescriptorType (* member .type )) 7036return true; 7037 } 7038 } 7039 7040return false; 7041} 7042 7043void TGlslangToSpvTraverser ::decorateStructType (const glslang::TType & type , 7044const glslang::TTypeList * glslangMembers , 7045 glslang::TLayoutPacking explicitLayout , 7046const glslang::TQualifier & qualifier , 7047 spv::Id spvType , 7048const std::vector < spv::Id >& spvMembers ) 7049{ 7050// Name and decorate the non-hidden members 7051int offset = -1 ; 7052bool memberLocationInvalid = type .isArrayOfArrays ()|| 7053 (type .isArray ()&& (type .getQualifier ().isArrayedIo (glslangIntermediate -> getStage ())== false)); 7054for (int i = 0 ;i < (int )glslangMembers -> size ();i ++ ) { 7055 glslang::TType & glslangMember = * (* glslangMembers )[i ].type ; 7056int member = i ; 7057if (type .getBasicType ()== glslang::EbtBlock ) { 7058member = memberRemapper [glslangMembers ][i ]; 7059if (filterMember (glslangMember )) 7060continue ; 7061 } 7062 7063// modify just this child's view of the qualifier 7064 glslang::TQualifier memberQualifier = glslangMember .getQualifier (); 7065InheritQualifiers (memberQualifier ,qualifier ); 7066 7067// using -1 above to indicate a hidden member 7068if (member < 0 ) 7069continue ; 7070 7071builder .addMemberName (spvType ,member ,glslangMember .getFieldName ().c_str ()); 7072builder .addMemberDecoration (spvType ,member , 7073TranslateLayoutDecoration (glslangMember ,memberQualifier .layoutMatrix )); 7074builder .addMemberDecoration (spvType ,member ,TranslatePrecisionDecoration (glslangMember )); 7075// Add interpolation and auxiliary storage decorations only to 7076// top-level members of Input and Output storage classes 7077if (type .getQualifier ().storage == glslang::EvqVaryingIn || 7078type .getQualifier ().storage == glslang::EvqVaryingOut ) { 7079if (type .getBasicType ()== glslang::EbtBlock || 7080glslangIntermediate -> getSource ()== glslang::EShSourceHlsl ) { 7081builder .addMemberDecoration (spvType ,member ,TranslateInterpolationDecoration (memberQualifier )); 7082builder .addMemberDecoration (spvType ,member ,TranslateAuxiliaryStorageDecoration (memberQualifier )); 7083addMeshNVDecoration (spvType ,member ,memberQualifier ); 7084 } 7085 } 7086builder .addMemberDecoration (spvType ,member ,TranslateInvariantDecoration (memberQualifier )); 7087 7088if (type .getBasicType ()== glslang::EbtBlock && 7089qualifier .storage == glslang::EvqBuffer ) { 7090// Add memory decorations only to top-level members of shader storage block 7091 std::vector < spv::Decoration > memory ; 7092TranslateMemoryDecoration (memberQualifier ,memory ,glslangIntermediate -> usingVulkanMemoryModel ()); 7093for (unsigned int i = 0 ;i < memory .size ();++ i ) 7094builder .addMemberDecoration (spvType ,member ,memory [i ]); 7095 } 7096 7097// Location assignment was already completed correctly by the front end, 7098// just track whether a member needs to be decorated. 7099// Ignore member locations if the container is an array, as that's 7100// ill-specified and decisions have been made to not allow this. 7101if (!memberLocationInvalid && memberQualifier .hasLocation ()) 7102builder .addMemberDecoration (spvType ,member , spv::Decoration ::Location ,memberQualifier .layoutLocation ); 7103 7104// component, XFB, others 7105if (glslangMember .getQualifier ().hasComponent ()) 7106builder .addMemberDecoration (spvType ,member , spv::Decoration ::Component , 7107glslangMember .getQualifier ().layoutComponent ); 7108if (glslangMember .getQualifier ().hasXfbOffset ()) 7109builder .addMemberDecoration (spvType ,member , spv::Decoration ::Offset , 7110glslangMember .getQualifier ().layoutXfbOffset ); 7111else if (glslangMember .getQualifier ().hasMemberOffset ()) { 7112builder .addExtension (spv::E_SPV_NV_push_constant_bank ); 7113builder .addCapability (spv::Capability ::PushConstantBanksNV ); 7114builder .addMemberDecoration (spvType ,member , spv::Decoration ::MemberOffsetNV , 7115glslangMember .getQualifier ().layoutMemberOffset ); 7116 }else if (explicitLayout != glslang::ElpNone ) { 7117// figure out what to do with offset, which is accumulating 7118int nextOffset ; 7119updateMemberOffset (type ,glslangMember ,offset ,nextOffset ,explicitLayout ,memberQualifier .layoutMatrix ); 7120if (offset >=0 ) 7121builder .addMemberDecoration (spvType ,member , spv::Decoration ::Offset ,offset ); 7122offset = nextOffset ; 7123 } 7124 7125if (glslangMember .isMatrix ()&& explicitLayout != glslang::ElpNone ) 7126builder .addMemberDecoration (spvType ,member , spv::Decoration ::MatrixStride , 7127getMatrixStride (glslangMember ,explicitLayout ,memberQualifier .layoutMatrix )); 7128 7129// built-in variable decorations 7130 spv::BuiltIn builtIn = TranslateBuiltInDecoration (glslangMember .getQualifier ().builtIn , true); 7131// built-in decoration is used to detect AST nodes, but won't be decorated on member variables. 7132if (builtIn != spv::BuiltIn ::Max && 7133builtIn != spv::BuiltIn ::ResourceHeapEXT && builtIn != spv::BuiltIn ::SamplerHeapEXT ) 7134builder .addMemberDecoration (spvType ,member , spv::Decoration ::BuiltIn , (int )builtIn ); 7135 7136// nonuniform 7137builder .addMemberDecoration (spvType ,member ,TranslateNonUniformDecoration (glslangMember .getQualifier ())); 7138 7139if (glslangIntermediate -> getHlslFunctionality1 ()&& memberQualifier .semanticName != nullptr ) { 7140builder .addExtension ("SPV_GOOGLE_hlsl_functionality1" ); 7141builder .addMemberDecoration (spvType ,member , spv::Decoration ::HlslSemanticGOOGLE , 7142memberQualifier .semanticName ); 7143 } 7144 7145if (builtIn == spv::BuiltIn ::Layer ) { 7146// SPV_NV_viewport_array2 extension 7147if (glslangMember .getQualifier ().layoutViewportRelative ){ 7148builder .addMemberDecoration (spvType ,member , spv::Decoration ::ViewportRelativeNV ); 7149builder .addCapability (spv::Capability ::ShaderViewportMaskNV ); 7150builder .addExtension (spv::E_SPV_NV_viewport_array2 ); 7151 } 7152if (glslangMember .getQualifier ().layoutSecondaryViewportRelativeOffset != -2048 ){ 7153builder .addMemberDecoration (spvType ,member , 7154 spv::Decoration ::SecondaryViewportRelativeNV , 7155glslangMember .getQualifier ().layoutSecondaryViewportRelativeOffset ); 7156builder .addCapability (spv::Capability ::ShaderStereoViewNV ); 7157builder .addExtension (spv::E_SPV_NV_stereo_view_rendering ); 7158 } 7159 } 7160if (glslangMember .getQualifier ().layoutPassthrough ) { 7161builder .addMemberDecoration (spvType ,member , spv::Decoration ::PassthroughNV ); 7162builder .addCapability (spv::Capability ::GeometryShaderPassthroughNV ); 7163builder .addExtension (spv::E_SPV_NV_geometry_shader_passthrough ); 7164 } 7165 7166// Add SPIR-V decorations (GL_EXT_spirv_intrinsics) 7167if (glslangMember .getQualifier ().hasSpirvDecorate ()) 7168applySpirvDecorate (glslangMember ,spvType ,member ); 7169 } 7170 7171// Decorate the structure 7172builder .addDecoration (spvType ,TranslateLayoutDecoration (type ,qualifier .layoutMatrix )); 7173const auto basicType = type .getBasicType (); 7174const auto typeStorageQualifier = type .getQualifier ().storage ; 7175if (basicType == glslang::EbtBlock || qualifier .isBufferType ()) { 7176builder .addDecoration (spvType ,TranslateBlockDecoration (typeStorageQualifier ,glslangIntermediate -> usingStorageBuffer ())); 7177 }else if (basicType == glslang::EbtStruct && glslangIntermediate -> getSpv ().vulkan > 0 ) { 7178const auto hasRuntimeArray = !spvMembers .empty ()&& builder .getOpCode (spvMembers .back ())== spv::Op ::OpTypeRuntimeArray ; 7179if (hasRuntimeArray ) { 7180builder .addDecoration (spvType ,TranslateBlockDecoration (typeStorageQualifier ,glslangIntermediate -> usingStorageBuffer ())); 7181 } 7182 } 7183 7184if (qualifier .hasHitObjectShaderRecordNV ()) 7185builder .addDecoration (spvType , spv::Decoration ::HitObjectShaderRecordBufferNV ); 7186 7187if (qualifier .hasBank ()) { 7188builder .addExtension (spv::E_SPV_NV_push_constant_bank ); 7189builder .addCapability (spv::Capability ::PushConstantBanksNV ); 7190builder .addDecoration (spvType , spv::Decoration ::BankNV ,qualifier .layoutBank ); 7191 } 7192 7193if (qualifier .hasHitObjectShaderRecordEXT ()) 7194builder .addDecoration (spvType , spv::Decoration ::HitObjectShaderRecordBufferEXT ); 7195} 7196 7197// Turn the expression forming the array size into an id. 7198// This is not quite trivial, because of specialization constants. 7199// Sometimes, a raw constant is turned into an Id, and sometimes 7200// a specialization constant expression is. 7201spv::Id TGlslangToSpvTraverser ::makeArraySizeId (const glslang::TArraySizes & arraySizes ,int dim ,bool allowZero ,bool boolType ) 7202{ 7203// First, see if this is sized with a node, meaning a specialization constant: 7204 glslang::TIntermTyped * specNode = arraySizes .getDimNode (dim ); 7205if (specNode != nullptr ) { 7206builder .clearAccessChain (); 7207SpecConstantOpModeGuard spec_constant_op_mode_setter (& builder ); 7208spec_constant_op_mode_setter .turnOnSpecConstantOpMode (); 7209specNode -> traverse (this ); 7210return accessChainLoad (specNode -> getAsTyped ()-> getType ()); 7211 } 7212 7213// Otherwise, need a compile-time (front end) size, get it: 7214int size = arraySizes .getDimSize (dim ); 7215 7216if (!allowZero ) 7217assert (size > 0 ); 7218 7219if (boolType ) { 7220return builder .makeBoolConstant (size ); 7221 }else { 7222return builder .makeUintConstant (size ); 7223 } 7224} 7225 7226// Turn a structured descriptor heap_offset into an id used to shift the heap base. 7227spv::Id TGlslangToSpvTraverser ::makeHeapOffsetId (const glslang::TType & type ) 7228{ 7229const glslang::TQualifier & qualifier = type .getQualifier (); 7230if (qualifier .layoutHeapOffsetNode != nullptr ) { 7231 spv::Builder ::AccessChain savedAccessChain = builder .getAccessChain (); 7232builder .clearAccessChain (); 7233 7234qualifier .layoutHeapOffsetNode -> traverse (this ); 7235 spv::Id heapOffset = accessChainLoad (qualifier .layoutHeapOffsetNode -> getType ()); 7236 7237builder .setAccessChain (savedAccessChain ); 7238return heapOffset ; 7239 } 7240 7241if (qualifier .layoutHeapOffset != 0 ) 7242return builder .makeUintConstant (qualifier .layoutHeapOffset ); 7243 7244return spv::NoResult ; 7245} 7246 7247// Wrap the builder's accessChainLoad to: 7248// - localize handling of RelaxedPrecision 7249// - use the SPIR-V inferred type instead of another conversion of the glslang type 7250// (avoids unnecessary work and possible type punning for structures) 7251// - do conversion of concrete to abstract type 7252spv::Id TGlslangToSpvTraverser ::accessChainLoad (const glslang::TType & type ) 7253{ 7254 spv::Id nominalTypeId = builder .accessChainGetInferredType (); 7255 7256 spv::Builder ::AccessChain ::CoherentFlags coherentFlags = builder .getAccessChain ().coherentFlags ; 7257coherentFlags |=TranslateCoherent (type ); 7258 7259 spv::MemoryAccessMask accessMask = spv::MemoryAccessMask (TranslateMemoryAccess (coherentFlags )& ~spv::MemoryAccessMask ::MakePointerAvailableKHR ); 7260// If the value being loaded is HelperInvocation, SPIR-V 1.6 is being generated (so that 7261// SPV_EXT_demote_to_helper_invocation is in core) and the memory model is in use, add 7262// the Volatile MemoryAccess semantic. 7263if (type .getQualifier ().builtIn == glslang::EbvHelperInvocation && 7264glslangIntermediate -> usingVulkanMemoryModel ()&& 7265glslangIntermediate -> getSpv ().spv >= glslang::EShTargetSpv_1_6 ) { 7266accessMask = spv::MemoryAccessMask (accessMask | spv::MemoryAccessMask ::Volatile ); 7267 } 7268 7269unsigned int alignment = builder .getAccessChain ().alignment ; 7270alignment |=type .getBufferReferenceAlignment (); 7271 7272 spv::Id loadedId = builder .accessChainLoad (TranslatePrecisionDecoration (type ), 7273TranslateNonUniformDecoration (builder .getAccessChain ().coherentFlags ), 7274TranslateNonUniformDecoration (type .getQualifier ()), 7275nominalTypeId , 7276accessMask , 7277TranslateMemoryScope (coherentFlags ), 7278alignment ); 7279 7280// Need to convert to abstract types when necessary 7281if (type .getBasicType ()== glslang::EbtBool ) { 7282loadedId = convertLoadedBoolInUniformToUint (type ,nominalTypeId ,loadedId ); 7283 } 7284 7285if (!builder .getAccessChain ().descHeapInfo .descHeapInstId .empty ()) { 7286for (auto heapInst :builder .getAccessChain ().descHeapInfo .descHeapInstId ) 7287heapInst -> setTypeId (convertGlslangToSpvType (type )); 7288builder .clearAccessChain (); 7289 } 7290 7291return loadedId ; 7292} 7293 7294// Wrap the builder's accessChainStore to: 7295// - do conversion of concrete to abstract type 7296// 7297// Implicitly uses the existing builder.accessChain as the storage target. 7298void TGlslangToSpvTraverser ::accessChainStore (const glslang::TType & type , spv::Id rvalue ) 7299{ 7300// Need to convert to abstract types when necessary 7301if (type .getBasicType ()== glslang::EbtBool ) { 7302 spv::Id nominalTypeId = builder .accessChainGetInferredType (); 7303 7304if (builder .isScalarType (nominalTypeId )) { 7305// Conversion for bool 7306 spv::Id boolType = builder .makeBoolType (); 7307if (nominalTypeId != boolType ) { 7308// keep these outside arguments, for determinant order-of-evaluation 7309 spv::Id one = builder .makeUintConstant (1 ); 7310 spv::Id zero = builder .makeUintConstant (0 ); 7311rvalue = builder .createTriOp (spv::Op ::OpSelect ,nominalTypeId ,rvalue ,one ,zero ); 7312 }else if (builder .getTypeId (rvalue )!= boolType ) 7313rvalue = builder .createBinOp (spv::Op ::OpINotEqual ,boolType ,rvalue ,builder .makeUintConstant (0 )); 7314 }else if (builder .isVectorType (nominalTypeId )) { 7315// Conversion for bvec 7316int vecSize = builder .getNumTypeComponents (nominalTypeId ); 7317 spv::Id bvecType = builder .makeVectorType (builder .makeBoolType (),vecSize ); 7318if (nominalTypeId != bvecType ) { 7319// keep these outside arguments, for determinant order-of-evaluation 7320 spv::Id one = makeSmearedConstant (builder .makeUintConstant (1 ),vecSize ); 7321 spv::Id zero = makeSmearedConstant (builder .makeUintConstant (0 ),vecSize ); 7322rvalue = builder .createTriOp (spv::Op ::OpSelect ,nominalTypeId ,rvalue ,one ,zero ); 7323 }else if (builder .getTypeId (rvalue )!= bvecType ) 7324rvalue = builder .createBinOp (spv::Op ::OpINotEqual ,bvecType ,rvalue , 7325makeSmearedConstant (builder .makeUintConstant (0 ),vecSize )); 7326 } 7327 } 7328 7329 spv::Builder ::AccessChain ::CoherentFlags coherentFlags = builder .getAccessChain ().coherentFlags ; 7330coherentFlags |=TranslateCoherent (type ); 7331 7332unsigned int alignment = builder .getAccessChain ().alignment ; 7333alignment |=type .getBufferReferenceAlignment (); 7334 7335builder .accessChainStore (rvalue ,TranslateNonUniformDecoration (builder .getAccessChain ().coherentFlags ), 7336 spv::MemoryAccessMask (TranslateMemoryAccess (coherentFlags )& 7337 ~spv::MemoryAccessMask ::MakePointerVisibleKHR ), 7338TranslateMemoryScope (coherentFlags ),alignment ); 7339} 7340 7341// For storing when types match at the glslang level, but not might match at the 7342// SPIR-V level. 7343// 7344// This especially happens when a single glslang type expands to multiple 7345// SPIR-V types, like a struct that is used in a member-undecorated way as well 7346// as in a member-decorated way. 7347// 7348// NOTE: This function can handle any store request; if it's not special it 7349// simplifies to a simple OpStore. 7350// 7351// Implicitly uses the existing builder.accessChain as the storage target. 7352void TGlslangToSpvTraverser ::multiTypeStore (const glslang::TType & type , spv::Id rValue ) 7353{ 7354// we only do the complex path here if it's an aggregate 7355if (!type .isStruct ()&& !type .isArray ()) { 7356accessChainStore (type ,rValue ); 7357return ; 7358 } 7359 7360// and, it has to be a case of type aliasing 7361 spv::Id rType = builder .getTypeId (rValue ); 7362 spv::Id lValue = builder .accessChainGetLValue (); 7363 spv::Id lType = builder .getContainedTypeId (builder .getTypeId (lValue )); 7364if (lType == rType ) { 7365accessChainStore (type ,rValue ); 7366return ; 7367 } 7368 7369// Recursively (as needed) copy an aggregate type to a different aggregate type, 7370// where the two types were the same type in GLSL. This requires member 7371// by member copy, recursively. 7372 7373// SPIR-V 1.4 added an instruction to do help do this. 7374if (glslangIntermediate -> getSpv ().spv >= glslang::EShTargetSpv_1_4 ) { 7375// However, bool in uniform space is changed to int, so 7376// OpCopyLogical does not work for that. 7377// TODO: It would be more robust to do a full recursive verification of the types satisfying SPIR-V rules. 7378bool rBool = builder .containsType (builder .getTypeId (rValue ), spv::Op ::OpTypeBool ,0 ); 7379bool lBool = builder .containsType (lType , spv::Op ::OpTypeBool ,0 ); 7380if (lBool == rBool ) { 7381 spv::Id logicalCopy = builder .createUnaryOp (spv::Op ::OpCopyLogical ,lType ,rValue ); 7382accessChainStore (type ,logicalCopy ); 7383return ; 7384 } 7385 } 7386 7387// If an array, copy element by element. 7388if (type .isArray ()) { 7389 glslang::TType glslangElementType (type ,0 ); 7390 spv::Id elementRType = builder .getContainedTypeId (rType ); 7391for (int index = 0 ;index < type .getOuterArraySize ();++ index ) { 7392// get the source member 7393 spv::Id elementRValue = builder .createCompositeExtract (rValue ,elementRType ,index ); 7394 7395// set up the target storage 7396builder .clearAccessChain (); 7397builder .setAccessChainLValue (lValue ); 7398builder .accessChainPush (builder .makeIntConstant (index ),TranslateCoherent (type ), 7399type .getBufferReferenceAlignment ()); 7400 7401// store the member 7402multiTypeStore (glslangElementType ,elementRValue ); 7403 } 7404 }else { 7405assert (type .isStruct ()); 7406 7407// loop over structure members 7408const glslang::TTypeList & members = * type .getStruct (); 7409for (int m = 0 ;m < (int )members .size ();++ m ) { 7410const glslang::TType & glslangMemberType = * members [m ].type ; 7411 7412// get the source member 7413 spv::Id memberRType = builder .getContainedTypeId (rType ,m ); 7414 spv::Id memberRValue = builder .createCompositeExtract (rValue ,memberRType ,m ); 7415 7416// set up the target storage 7417builder .clearAccessChain (); 7418builder .setAccessChainLValue (lValue ); 7419builder .accessChainPush (builder .makeIntConstant (m ),TranslateCoherent (type ), 7420type .getBufferReferenceAlignment ()); 7421 7422// store the member 7423multiTypeStore (glslangMemberType ,memberRValue ); 7424 } 7425 } 7426} 7427 7428// Decide whether or not this type should be 7429// decorated with offsets and strides, and if so 7430// whether std140 or std430 rules should be applied. 7431glslang::TLayoutPacking TGlslangToSpvTraverser ::getExplicitLayout (const glslang::TType & type )const 7432{ 7433// Has to be a block. buffer_type is represented as a struct use in the AST, 7434// but its payload still follows uniform/buffer block layout rules. 7435if (type .getBasicType ()!= glslang::EbtBlock && 7436 !type .getQualifier ().isBufferType ()) 7437return glslang::ElpNone ; 7438 7439// has to be a uniform or buffer block or task in/out blocks 7440if (type .getQualifier ().storage != glslang::EvqUniform && 7441type .getQualifier ().storage != glslang::EvqBuffer && 7442type .getQualifier ().storage != glslang::EvqShared && 7443 !type .getQualifier ().isTaskMemory ()) 7444return glslang::ElpNone ; 7445 7446// return the layout to use 7447switch (type .getQualifier ().layoutPacking ) { 7448case glslang::ElpStd140 : 7449case glslang::ElpStd430 : 7450case glslang::ElpScalar : 7451return type .getQualifier ().layoutPacking ; 7452default : 7453return glslang::ElpNone ; 7454 } 7455} 7456 7457// Given an array type, returns the integer stride required for that array 7458int TGlslangToSpvTraverser ::getArrayStride (const glslang::TType & arrayType , glslang::TLayoutPacking explicitLayout , 7459 glslang::TLayoutMatrix matrixLayout ) 7460{ 7461int size ; 7462int stride ; 7463glslangIntermediate -> getMemberAlignment (arrayType ,size ,stride ,explicitLayout , 7464matrixLayout == glslang::ElmRowMajor ); 7465 7466return stride ; 7467} 7468 7469// Given a matrix type, or array (of array) of matrixes type, returns the integer stride required for that matrix 7470// when used as a member of an interface block 7471int TGlslangToSpvTraverser ::getMatrixStride (const glslang::TType & matrixType , glslang::TLayoutPacking explicitLayout , 7472 glslang::TLayoutMatrix matrixLayout ) 7473{ 7474 glslang::TType elementType ; 7475elementType .shallowCopy (matrixType ); 7476elementType .clearArraySizes (); 7477 7478int size ; 7479int stride ; 7480glslangIntermediate -> getMemberAlignment (elementType ,size ,stride ,explicitLayout , 7481matrixLayout == glslang::ElmRowMajor ); 7482 7483return stride ; 7484} 7485 7486// Given a member type of a struct, realign the current offset for it, and compute 7487// the next (not yet aligned) offset for the next member, which will get aligned 7488// on the next call. 7489// 'currentOffset' should be passed in already initialized, ready to modify, and reflecting 7490// the migration of data from nextOffset -> currentOffset. It should be -1 on the first call. 7491// -1 means a non-forced member offset (no decoration needed). 7492void TGlslangToSpvTraverser ::updateMemberOffset (const glslang::TType & structType ,const glslang::TType & memberType , 7493int & currentOffset ,int & nextOffset , glslang::TLayoutPacking explicitLayout , glslang::TLayoutMatrix matrixLayout ) 7494{ 7495// this will get a positive value when deemed necessary 7496nextOffset = -1 ; 7497 7498// override anything in currentOffset with user-set offset 7499if (memberType .getQualifier ().hasOffset ()) 7500currentOffset = memberType .getQualifier ().layoutOffset ; 7501 7502// It could be that current linker usage in glslang updated all the layoutOffset, 7503// in which case the following code does not matter. But, that's not quite right 7504// once cross-compilation unit GLSL validation is done, as the original user 7505// settings are needed in layoutOffset, and then the following will come into play. 7506 7507if (explicitLayout == glslang::ElpNone ) { 7508if (!memberType .getQualifier ().hasOffset ()) 7509currentOffset = -1 ; 7510 7511return ; 7512 } 7513 7514// Getting this far means we need explicit offsets 7515if (currentOffset < 0 ) 7516currentOffset = 0 ; 7517 7518// Now, currentOffset is valid (either 0, or from a previous nextOffset), 7519// but possibly not yet correctly aligned. 7520 7521int memberSize ; 7522int dummyStride ; 7523int memberAlignment = glslangIntermediate -> getMemberAlignment (memberType ,memberSize ,dummyStride ,explicitLayout , 7524matrixLayout == glslang::ElmRowMajor ); 7525 7526bool isVectorLike = memberType .isVector (); 7527if (memberType .isMatrix ()) { 7528if (matrixLayout == glslang::ElmRowMajor ) 7529isVectorLike = memberType .getMatrixRows ()== 1 ; 7530else 7531isVectorLike = memberType .getMatrixCols ()== 1 ; 7532 } 7533 7534// Adjust alignment for HLSL rules 7535// TODO: make this consistent in early phases of code: 7536// adjusting this late means inconsistencies with earlier code, which for reflection is an issue 7537// Until reflection is brought in sync with these adjustments, don't apply to $Global, 7538// which is the most likely to rely on reflection, and least likely to rely implicit layouts 7539if (glslangIntermediate -> usingHlslOffsets ()&& 7540 !memberType .isStruct ()&& structType .getTypeName ().compare ("$Global" )!= 0 ) { 7541int componentSize ; 7542int componentAlignment = glslangIntermediate -> getBaseAlignmentScalar (memberType ,componentSize ); 7543if (!memberType .isArray ()&& isVectorLike && componentAlignment <=4 ) 7544memberAlignment = componentAlignment ; 7545 7546// Don't add unnecessary padding after this member 7547// (undo std140 bumping size to a mutliple of vec4) 7548if (explicitLayout == glslang::ElpStd140 ) { 7549if (memberType .isMatrix ()) { 7550if (matrixLayout == glslang::ElmRowMajor ) 7551memberSize -= componentSize * (4 - memberType .getMatrixCols ()); 7552else 7553memberSize -= componentSize * (4 - memberType .getMatrixRows ()); 7554 }else if (memberType .isArray ()) 7555memberSize -= componentSize * (4 - memberType .getVectorSize ()); 7556 } 7557 } 7558 7559// Bump up to member alignment 7560 glslang::RoundToPow2 (currentOffset ,memberAlignment ); 7561 7562// Bump up to vec4 if there is a bad straddle 7563if (explicitLayout != glslang::ElpScalar && glslangIntermediate -> improperStraddle (memberType ,memberSize , 7564currentOffset ,isVectorLike )) 7565 glslang::RoundToPow2 (currentOffset ,16 ); 7566 7567nextOffset = currentOffset + memberSize ; 7568} 7569 7570void TGlslangToSpvTraverser ::declareUseOfStructMember (const glslang::TTypeList & members ,int glslangMember ) 7571{ 7572const glslang::TBuiltInVariable glslangBuiltIn = members [glslangMember ].type -> getQualifier ().builtIn ; 7573switch (glslangBuiltIn ) 7574 { 7575case glslang::EbvPointSize : 7576case glslang::EbvClipDistance : 7577case glslang::EbvCullDistance : 7578case glslang::EbvViewportMaskNV : 7579case glslang::EbvSecondaryPositionNV : 7580case glslang::EbvSecondaryViewportMaskNV : 7581case glslang::EbvPositionPerViewNV : 7582case glslang::EbvViewportMaskPerViewNV : 7583case glslang::EbvTaskCountNV : 7584case glslang::EbvPrimitiveCountNV : 7585case glslang::EbvPrimitiveIndicesNV : 7586case glslang::EbvClipDistancePerViewNV : 7587case glslang::EbvCullDistancePerViewNV : 7588case glslang::EbvLayerPerViewNV : 7589case glslang::EbvMeshViewCountNV : 7590case glslang::EbvMeshViewIndicesNV : 7591// Generate the associated capability. Delegate to TranslateBuiltInDecoration. 7592// Alternately, we could just call this for any glslang built-in, since the 7593// capability already guards against duplicates. 7594TranslateBuiltInDecoration (glslangBuiltIn , false); 7595break ; 7596default : 7597// Capabilities were already generated when the struct was declared. 7598break ; 7599 } 7600} 7601 7602bool TGlslangToSpvTraverser ::isShaderEntryPoint (const glslang::TIntermAggregate * node ) 7603{ 7604return node -> getName ().compare (glslangIntermediate -> getEntryPointMangledName ().c_str ())== 0 ; 7605} 7606 7607// Does parameter need a place to keep writes, separate from the original? 7608// Assumes called after originalParam(), which filters out block/buffer/opaque-based 7609// qualifiers such that we should have only in/out/inout/constreadonly here. 7610bool TGlslangToSpvTraverser ::writableParam (glslang::TStorageQualifier qualifier )const 7611{ 7612assert (qualifier == glslang::EvqIn || 7613qualifier == glslang::EvqOut || 7614qualifier == glslang::EvqInOut || 7615qualifier == glslang::EvqUniform || 7616qualifier == glslang::EvqConstReadOnly ); 7617return qualifier != glslang::EvqConstReadOnly && 7618qualifier != glslang::EvqUniform ; 7619} 7620 7621// Is parameter pass-by-original? 7622bool TGlslangToSpvTraverser ::originalParam (glslang::TStorageQualifier qualifier ,const glslang::TType & paramType , 7623bool implicitThisParam ) 7624{ 7625if (implicitThisParam )// implicit this 7626return true; 7627if (glslangIntermediate -> getSource ()== glslang::EShSourceHlsl ) 7628return paramType .getBasicType ()== glslang::EbtBlock ; 7629return (paramType .containsOpaque ()&& !glslangIntermediate -> getBindlessMode ())|| // sampler, etc. 7630paramType .getQualifier ().isSpirvByReference ()|| // spirv_by_reference 7631 (paramType .getBasicType ()== glslang::EbtBlock && qualifier == glslang::EvqBuffer );// SSBO 7632} 7633 7634// Make all the functions, skeletally, without actually visiting their bodies. 7635void TGlslangToSpvTraverser ::makeFunctions (const glslang::TIntermSequence & glslFunctions ) 7636{ 7637const auto getParamDecorations = [& ](std::vector < spv::Decoration >& decorations ,const glslang::TType & type , 7638bool useVulkanMemoryModel ) { 7639 spv::Decoration paramPrecision = TranslatePrecisionDecoration (type ); 7640if (paramPrecision != spv::NoPrecision ) 7641decorations .push_back (paramPrecision ); 7642TranslateMemoryDecoration (type .getQualifier (),decorations ,useVulkanMemoryModel ); 7643if (type .isReference ()) { 7644// Original and non-writable params pass the pointer directly and 7645// use restrict/aliased, others are stored to a pointer in Function 7646// memory and use RestrictPointer/AliasedPointer. 7647if (originalParam (type .getQualifier ().storage ,type , false)|| 7648 !writableParam (type .getQualifier ().storage )) { 7649// TranslateMemoryDecoration added Restrict decoration already. 7650if (!type .getQualifier ().isRestrict ()) { 7651decorations .push_back (spv::Decoration ::Aliased ); 7652 } 7653 }else { 7654decorations .push_back (type .getQualifier ().isRestrict () ? spv::Decoration ::RestrictPointerEXT : 7655 spv::Decoration ::AliasedPointerEXT ); 7656 } 7657 } 7658 }; 7659 7660for (int f = 0 ;f < (int )glslFunctions .size ();++ f ) { 7661 glslang::TIntermAggregate * glslFunction = glslFunctions [f ]-> getAsAggregate (); 7662if (!glslFunction || glslFunction -> getOp ()!= glslang::EOpFunction ) 7663continue ; 7664 7665builder .setDebugSourceLocation (glslFunction -> getLoc ().line ,glslFunction -> getLoc ().getFilename ()); 7666 7667if (isShaderEntryPoint (glslFunction )) { 7668shaderEntry -> setFunctionControl (TranslateFunctionControl (glslFunction -> getFunctionControl ())); 7669// For HLSL, the entry function is actually a compiler generated function to resolve the difference of 7670// entry function signature between HLSL and SPIR-V. So we don't emit debug information for that. 7671if (glslangIntermediate -> getSource ()!= glslang::EShSourceHlsl ) { 7672builder .setupFunctionDebugInfo (shaderEntry ,glslangIntermediate -> getEntryPointMangledName ().c_str (), 7673 std::vector < spv::Id > (),// main function has no param 7674 std::vector < char const *> ()); 7675if (options .emitNonSemanticShaderDebugInfo && 7676options .compilerSignature != nullptr && options .commandLineArguments != nullptr ) { 7677builder .makeDebugEntryPoint (shaderEntry ,options .compilerSignature ,options .commandLineArguments , 7678options .currentWorkingDirectory ); 7679 } 7680 } 7681continue ; 7682 } 7683// We're on a user function. Set up the basic interface for the function now, 7684// so that it's available to call. Translating the body will happen later. 7685// 7686// Typically (except for a "const in" parameter), an address will be passed to the 7687// function. What it is an address of varies: 7688// 7689// - "in" parameters not marked as "const" can be written to without modifying the calling 7690// argument so that write needs to be to a copy, hence the address of a copy works. 7691// 7692// - "const in" parameters can just be the r-value, as no writes need occur. 7693// 7694// - "out" and "inout" arguments can't be done as pointers to the calling argument, because 7695// GLSL has copy-in/copy-out semantics. They can be handled though with a pointer to a copy. 7696 7697 std::vector < spv::Id > paramTypes ; 7698 std::vector < char const *> paramNames ; 7699 std::vector < std::vector < spv::Decoration >> paramDecorations ;// list of decorations per parameter 7700 glslang::TIntermSequence & parameters = glslFunction -> getSequence ()[0 ]-> getAsAggregate ()-> getSequence (); 7701 7702#ifdef ENABLE_HLSL 7703bool implicitThis = (int )parameters .size ()> 0 && parameters [0 ]-> getAsSymbolNode ()-> getName ()== 7704glslangIntermediate -> implicitThisName ; 7705#else 7706bool implicitThis = false; 7707#endif 7708 7709paramDecorations .resize (parameters .size ()); 7710for (int p = 0 ;p < (int )parameters .size ();++ p ) { 7711const glslang::TType & paramType = parameters [p ]-> getAsTyped ()-> getType (); 7712 spv::Id typeId = convertGlslangToSpvType (paramType ); 7713if (originalParam (paramType .getQualifier ().storage ,paramType ,implicitThis && p == 0 )) 7714typeId = builder .makePointer (TranslateStorageClass (paramType ),typeId ); 7715else if (writableParam (paramType .getQualifier ().storage )) 7716typeId = builder .makePointer (spv::StorageClass ::Function ,typeId ); 7717else 7718rValueParameters .insert (parameters [p ]-> getAsSymbolNode ()-> getId ()); 7719getParamDecorations (paramDecorations [p ],paramType ,glslangIntermediate -> usingVulkanMemoryModel ()); 7720paramTypes .push_back (typeId ); 7721 } 7722 7723for (auto const parameter :parameters ) { 7724paramNames .push_back (parameter -> getAsSymbolNode ()-> getName ().c_str ()); 7725 } 7726 7727 spv::Block * functionBlock ; 7728 spv::Function * function = builder .makeFunctionEntry ( 7729TranslatePrecisionDecoration (glslFunction -> getType ()),convertGlslangToSpvType (glslFunction -> getType ()), 7730glslFunction -> getName ().c_str (),convertGlslangLinkageToSpv (glslFunction -> getLinkType ()),paramTypes , 7731paramDecorations ,& functionBlock ); 7732function -> setFunctionControl (TranslateFunctionControl (glslFunction -> getFunctionControl ())); 7733builder .setupFunctionDebugInfo (function ,glslFunction -> getName ().c_str (),paramTypes ,paramNames ); 7734if (implicitThis ) 7735function -> setImplicitThis (); 7736 7737// Track function to emit/call later 7738functionMap [glslFunction -> getName ().c_str ()]= function ; 7739 7740// Set the parameter id's 7741for (int p = 0 ;p < (int )parameters .size ();++ p ) { 7742symbolValues [parameters [p ]-> getAsSymbolNode ()-> getId ()]= function -> getParamId (p ); 7743// give a name too 7744builder .addName (function -> getParamId (p ),parameters [p ]-> getAsSymbolNode ()-> getName ().c_str ()); 7745 7746const glslang::TType & paramType = parameters [p ]-> getAsTyped ()-> getType (); 7747if (paramType .contains8BitInt ()) 7748builder .addCapability (spv::Capability ::Int8 ); 7749if (paramType .contains16BitInt ()) 7750builder .addCapability (spv::Capability ::Int16 ); 7751if (paramType .contains16BitFloat ()) 7752builder .addCapability (spv::Capability ::Float16 ); 7753 } 7754 } 7755} 7756 7757// Process all the initializers, while skipping the functions and link objects 7758void TGlslangToSpvTraverser ::makeGlobalInitializers (const glslang::TIntermSequence & initializers ) 7759{ 7760builder .setBuildPoint (shaderEntry -> getLastBlock ()); 7761for (int i = 0 ;i < (int )initializers .size ();++ i ) { 7762 glslang::TIntermAggregate * initializer = initializers [i ]-> getAsAggregate (); 7763if (initializer && initializer -> getOp ()!= glslang::EOpFunction && initializer -> getOp ()!= 7764 glslang::EOpLinkerObjects ) { 7765 7766// We're on a top-level node that's not a function. Treat as an initializer, whose 7767// code goes into the beginning of the entry point. 7768initializer -> traverse (this ); 7769 } 7770 } 7771} 7772// Walk over all linker objects to create a map for payload and callable data linker objects 7773// and their location to be used during codegen for OpTraceKHR and OpExecuteCallableKHR 7774// This is done here since it is possible that these linker objects are not be referenced in the AST 7775void TGlslangToSpvTraverser ::collectRayTracingLinkerObjects () 7776{ 7777 glslang::TIntermAggregate * linkerObjects = glslangIntermediate -> findLinkerObjects (); 7778for (auto & objSeq :linkerObjects -> getSequence ()) { 7779auto objNode = objSeq -> getAsSymbolNode (); 7780if (objNode != nullptr ) { 7781if (objNode -> getQualifier ().hasLocation ()) { 7782unsigned int location = objNode -> getQualifier ().layoutLocation ; 7783auto st = objNode -> getQualifier ().storage ; 7784int set ; 7785switch (st ) 7786 { 7787case glslang::EvqPayload : 7788case glslang::EvqPayloadIn : 7789set = 0 ; 7790break ; 7791case glslang::EvqCallableData : 7792case glslang::EvqCallableDataIn : 7793set = 1 ; 7794break ; 7795 7796case glslang::EvqHitObjectAttrNV : 7797case glslang::EvqHitObjectAttrEXT : 7798set = 2 ; 7799break ; 7800 7801default : 7802set = -1 ; 7803 } 7804if (set != -1 ) 7805locationToSymbol [set ].insert (std::make_pair (location ,objNode )); 7806 } 7807 } 7808 } 7809} 7810// Process all the functions, while skipping initializers. 7811void TGlslangToSpvTraverser ::visitFunctions (const glslang::TIntermSequence & glslFunctions ) 7812{ 7813for (int f = 0 ;f < (int )glslFunctions .size ();++ f ) { 7814 glslang::TIntermAggregate * node = glslFunctions [f ]-> getAsAggregate (); 7815if (node && (node -> getOp ()== glslang::EOpFunction || node -> getOp ()== glslang::EOpLinkerObjects )) 7816node -> traverse (this ); 7817 } 7818} 7819 7820void TGlslangToSpvTraverser ::translateArguments (const glslang::TIntermAggregate & node , std::vector < spv::Id >& arguments , 7821 spv::Builder ::AccessChain ::CoherentFlags & lvalueCoherentFlags ) 7822{ 7823const glslang::TIntermSequence & glslangArguments = node .getSequence (); 7824 7825 glslang::TSampler sampler = {}; 7826bool cubeCompare = false; 7827bool f16ShadowCompare = false; 7828if (node .isTexture ()|| node .isImage ()) { 7829sampler = glslangArguments [0 ]-> getAsTyped ()-> getType ().getSampler (); 7830cubeCompare = sampler .dim == glslang::EsdCube && sampler .arrayed && sampler .shadow ; 7831f16ShadowCompare = sampler .shadow && 7832glslangArguments [1 ]-> getAsTyped ()-> getType ().getBasicType ()== glslang::EbtFloat16 ; 7833 } 7834 7835for (int i = 0 ;i < (int )glslangArguments .size ();++ i ) { 7836builder .clearAccessChain (); 7837glslangArguments [i ]-> traverse (this ); 7838 7839// Special case l-value operands 7840bool lvalue = false; 7841switch (node .getOp ()) { 7842case glslang::EOpImageAtomicAdd : 7843case glslang::EOpImageAtomicMin : 7844case glslang::EOpImageAtomicMax : 7845case glslang::EOpImageAtomicAnd : 7846case glslang::EOpImageAtomicOr : 7847case glslang::EOpImageAtomicXor : 7848case glslang::EOpImageAtomicExchange : 7849case glslang::EOpImageAtomicCompSwap : 7850case glslang::EOpImageAtomicLoad : 7851case glslang::EOpImageAtomicStore : 7852if (i == 0 ) 7853lvalue = true; 7854break ; 7855case glslang::EOpSparseImageLoad : 7856if ((sampler .ms && i == 3 )|| (!sampler .ms && i == 2 )) 7857lvalue = true; 7858break ; 7859case glslang::EOpSparseTexture : 7860if (((cubeCompare || f16ShadowCompare )&& i == 3 )|| (! (cubeCompare || f16ShadowCompare )&& i == 2 )) 7861lvalue = true; 7862break ; 7863case glslang::EOpSparseTextureClamp : 7864if (((cubeCompare || f16ShadowCompare )&& i == 4 )|| (! (cubeCompare || f16ShadowCompare )&& i == 3 )) 7865lvalue = true; 7866break ; 7867case glslang::EOpSparseTextureLod : 7868case glslang::EOpSparseTextureOffset : 7869if ((f16ShadowCompare && i == 4 )|| (!f16ShadowCompare && i == 3 )) 7870lvalue = true; 7871break ; 7872case glslang::EOpSparseTextureFetch : 7873if ((sampler .dim != glslang::EsdRect && i == 3 )|| (sampler .dim == glslang::EsdRect && i == 2 )) 7874lvalue = true; 7875break ; 7876case glslang::EOpSparseTextureFetchOffset : 7877if ((sampler .dim != glslang::EsdRect && i == 4 )|| (sampler .dim == glslang::EsdRect && i == 3 )) 7878lvalue = true; 7879break ; 7880case glslang::EOpSparseTextureLodOffset : 7881case glslang::EOpSparseTextureGrad : 7882case glslang::EOpSparseTextureOffsetClamp : 7883if ((f16ShadowCompare && i == 5 )|| (!f16ShadowCompare && i == 4 )) 7884lvalue = true; 7885break ; 7886case glslang::EOpSparseTextureGradOffset : 7887case glslang::EOpSparseTextureGradClamp : 7888if ((f16ShadowCompare && i == 6 )|| (!f16ShadowCompare && i == 5 )) 7889lvalue = true; 7890break ; 7891case glslang::EOpSparseTextureGradOffsetClamp : 7892if ((f16ShadowCompare && i == 7 )|| (!f16ShadowCompare && i == 6 )) 7893lvalue = true; 7894break ; 7895case glslang::EOpSparseTextureGather : 7896if ((sampler .shadow && i == 3 )|| (!sampler .shadow && i == 2 )) 7897lvalue = true; 7898break ; 7899case glslang::EOpSparseTextureGatherOffset : 7900case glslang::EOpSparseTextureGatherOffsets : 7901if ((sampler .shadow && i == 4 )|| (!sampler .shadow && i == 3 )) 7902lvalue = true; 7903break ; 7904case glslang::EOpSparseTextureGatherLod : 7905if (i == 3 ) 7906lvalue = true; 7907break ; 7908case glslang::EOpSparseTextureGatherLodOffset : 7909case glslang::EOpSparseTextureGatherLodOffsets : 7910if (i == 4 ) 7911lvalue = true; 7912break ; 7913case glslang::EOpSparseImageLoadLod : 7914if (i == 3 ) 7915lvalue = true; 7916break ; 7917case glslang::EOpImageSampleFootprintNV : 7918if (i == 4 ) 7919lvalue = true; 7920break ; 7921case glslang::EOpImageSampleFootprintClampNV : 7922case glslang::EOpImageSampleFootprintLodNV : 7923if (i == 5 ) 7924lvalue = true; 7925break ; 7926case glslang::EOpImageSampleFootprintGradNV : 7927if (i == 6 ) 7928lvalue = true; 7929break ; 7930case glslang::EOpImageSampleFootprintGradClampNV : 7931if (i == 7 ) 7932lvalue = true; 7933break ; 7934case glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT : 7935case glslang::EOpRayQueryGetIntersectionLSSPositionsNV : 7936case glslang::EOpRayQueryGetIntersectionLSSRadiiNV : 7937if (i == 2 ) 7938lvalue = true; 7939break ; 7940case glslang::EOpConstructSaturated : 7941if (i == 0 ) 7942lvalue = true; 7943break ; 7944default : 7945break ; 7946 } 7947 7948if (lvalue ) { 7949 spv::Id lvalue_id = builder .accessChainGetLValue (); 7950arguments .push_back (lvalue_id ); 7951lvalueCoherentFlags = builder .getAccessChain ().coherentFlags ; 7952builder .addDecoration (lvalue_id ,TranslateNonUniformDecoration (lvalueCoherentFlags )); 7953lvalueCoherentFlags |=TranslateCoherent (glslangArguments [i ]-> getAsTyped ()-> getType ()); 7954 }else { 7955if (i > 0 && 7956glslangArguments [i ]-> getAsSymbolNode ()&& glslangArguments [i - 1 ]-> getAsSymbolNode ()&& 7957glslangArguments [i ]-> getAsSymbolNode ()-> getId ()== glslangArguments [i - 1 ]-> getAsSymbolNode ()-> getId ()) { 7958// Reuse the id if possible 7959 spv::Id id = arguments [i - 1 ]; 7960arguments .push_back (id ); 7961 }else { 7962arguments .push_back (accessChainLoad (glslangArguments [i ]-> getAsTyped ()-> getType ())); 7963 } 7964 } 7965 } 7966} 7967 7968void TGlslangToSpvTraverser ::translateArguments (glslang::TIntermUnary & node , std::vector < spv::Id >& arguments ) 7969{ 7970builder .clearAccessChain (); 7971node .getOperand ()-> traverse (this ); 7972arguments .push_back (accessChainLoad (node .getOperand ()-> getType ())); 7973} 7974 7975spv::Id TGlslangToSpvTraverser ::createImageTextureFunctionCall (glslang::TIntermOperator * node ) 7976{ 7977if (!node -> isImage ()&& !node -> isTexture ()) 7978return spv::NoResult ; 7979 7980builder .setDebugSourceLocation (node -> getLoc ().line ,node -> getLoc ().getFilename ()); 7981 7982// Process a GLSL texturing op (will be SPV image) 7983 7984const glslang::TType & imageType = node -> getAsAggregate () 7985 ?node -> getAsAggregate ()-> getSequence ()[0 ]-> getAsTyped ()-> getType () 7986 :node -> getAsUnaryNode ()-> getOperand ()-> getAsTyped ()-> getType (); 7987const glslang::TSampler sampler = imageType .getSampler (); 7988bool f16ShadowCompare = (sampler .shadow && node -> getAsAggregate ()) 7989 ?node -> getAsAggregate ()-> getSequence ()[1 ]-> getAsTyped ()-> getType ().getBasicType ()== glslang::EbtFloat16 7990 : false; 7991 7992const auto signExtensionMask = [& ]() { 7993if (builder .getSpvVersion () >= spv::Spv_1_4 ) { 7994if (sampler .type == glslang::EbtUint ) 7995return spv::ImageOperandsMask ::ZeroExtend ; 7996else if (sampler .type == glslang::EbtInt ) 7997return spv::ImageOperandsMask ::SignExtend ; 7998 } 7999return spv::ImageOperandsMask ::MaskNone ; 8000 }; 8001 8002 spv::Builder ::AccessChain ::CoherentFlags lvalueCoherentFlags ; 8003 8004 std::vector < spv::Id > arguments ; 8005if (node -> getAsAggregate ()) 8006translateArguments (* node -> getAsAggregate (),arguments ,lvalueCoherentFlags ); 8007else 8008translateArguments (* node -> getAsUnaryNode (),arguments ); 8009 spv::Decoration precision = TranslatePrecisionDecoration (node -> getType ()); 8010 8011 spv::Builder ::TextureParameters params = { }; 8012params .sampler = arguments [0 ]; 8013 8014 glslang::TCrackedTextureOp cracked ; 8015node -> crackTexture (sampler ,cracked ); 8016 8017const bool isUnsignedResult = node -> getType ().getBasicType ()== glslang::EbtUint ; 8018 8019if (builder .isSampledImage (params .sampler )&& 8020 ((cracked .query && node -> getOp ()!= glslang::EOpTextureQueryLod )|| cracked .fragMask || cracked .fetch )) { 8021params .sampler = builder .createUnaryOp (spv::Op ::OpImage ,builder .getImageType (params .sampler ),params .sampler ); 8022if (imageType .getQualifier ().isNonUniform ()) { 8023auto & extensions = glslangIntermediate -> getRequestedExtensions (); 8024if (extensions .find ("GL_EXT_descriptor_heap" )== extensions .end ()) { 8025builder .addDecoration (params .sampler , spv::Decoration ::NonUniformEXT ); 8026 } 8027 } 8028 } 8029// Check for queries 8030if (cracked .query ) { 8031switch (node -> getOp ()) { 8032case glslang::EOpImageQuerySize : 8033case glslang::EOpTextureQuerySize : 8034if (arguments .size ()> 1 ) { 8035params .lod = arguments [1 ]; 8036return builder .createTextureQueryCall (spv::Op ::OpImageQuerySizeLod ,params ,isUnsignedResult ); 8037 }else 8038return builder .createTextureQueryCall (spv::Op ::OpImageQuerySize ,params ,isUnsignedResult ); 8039case glslang::EOpImageQuerySamples : 8040case glslang::EOpTextureQuerySamples : 8041return builder .createTextureQueryCall (spv::Op ::OpImageQuerySamples ,params ,isUnsignedResult ); 8042case glslang::EOpTextureQueryLod : 8043params .coords = arguments [1 ]; 8044return builder .createTextureQueryCall (spv::Op ::OpImageQueryLod ,params ,isUnsignedResult ); 8045case glslang::EOpTextureQueryLevels : 8046return builder .createTextureQueryCall (spv::Op ::OpImageQueryLevels ,params ,isUnsignedResult ); 8047case glslang::EOpSparseTexelsResident : 8048return builder .createUnaryOp (spv::Op ::OpImageSparseTexelsResident ,builder .makeBoolType (),arguments [0 ]); 8049default : 8050assert (0 ); 8051break ; 8052 } 8053 } 8054 8055int components = node -> getType ().getVectorSize (); 8056 8057if (node -> getOp ()== glslang::EOpImageLoad || 8058node -> getOp ()== glslang::EOpImageLoadLod || 8059node -> getOp ()== glslang::EOpTextureFetch || 8060node -> getOp ()== glslang::EOpTextureFetchOffset ) { 8061// These must produce 4 components, per SPIR-V spec. We'll add a conversion constructor if needed. 8062// This will only happen through the HLSL path for operator[], so we do not have to handle e.g. 8063// the EOpTexture/Proj/Lod/etc family. It would be harmless to do so, but would need more logic 8064// here around e.g. which ones return scalars or other types. 8065components = 4 ; 8066 } 8067 8068 glslang::TType returnType (node -> getType ().getBasicType (), glslang::EvqTemporary ,components ); 8069 8070auto resultType = [& returnType ,this ]{return convertGlslangToSpvType (returnType ); }; 8071 8072// Check for image functions other than queries 8073if (node -> isImage ()) { 8074 std::vector < spv::IdImmediate > operands ; 8075auto opIt = arguments .begin (); 8076 spv::IdImmediate image = { true,* (opIt ++ ) }; 8077operands .push_back (image ); 8078 8079// Handle subpass operations 8080// TODO: GLSL should change to have the "MS" only on the type rather than the 8081// built-in function. 8082if (cracked .subpass ) { 8083// add on the (0,0) coordinate 8084 spv::Id zero = builder .makeIntConstant (0 ); 8085 std::vector < spv::Id > comps ; 8086comps .push_back (zero ); 8087comps .push_back (zero ); 8088 spv::IdImmediate coord = { true, 8089builder .makeCompositeConstant (builder .makeVectorType (builder .makeIntType (32 ),2 ),comps ) }; 8090operands .push_back (coord ); 8091 spv::IdImmediate imageOperands = { false, spv::ImageOperandsMask ::MaskNone }; 8092imageOperands .word = imageOperands .word | (unsigned )signExtensionMask (); 8093if (sampler .isMultiSample ()) { 8094imageOperands .word = imageOperands .word | (unsigned )spv::ImageOperandsMask ::Sample ; 8095 } 8096if (imageOperands .word != (unsigned )spv::ImageOperandsMask ::MaskNone ) { 8097operands .push_back (imageOperands ); 8098if (sampler .isMultiSample ()) { 8099 spv::IdImmediate imageOperand = { true,* (opIt ++ ) }; 8100operands .push_back (imageOperand ); 8101 } 8102 } 8103 spv::Id result = builder .createOp (spv::Op ::OpImageRead ,resultType (),operands ); 8104builder .setPrecision (result ,precision ); 8105return result ; 8106 } 8107 8108if (cracked .attachmentEXT ) { 8109if (opIt != arguments .end ()) { 8110 spv::IdImmediate sample = { true,* opIt }; 8111operands .push_back (sample ); 8112 } 8113 spv::Id result = builder .createOp (spv::Op ::OpColorAttachmentReadEXT ,resultType (),operands ); 8114builder .addExtension (spv::E_SPV_EXT_shader_tile_image ); 8115builder .setPrecision (result ,precision ); 8116return result ; 8117 } 8118 8119 spv::IdImmediate coord = { true,* (opIt ++ ) }; 8120operands .push_back (coord ); 8121if (node -> getOp ()== glslang::EOpImageLoad || node -> getOp ()== glslang::EOpImageLoadLod ) { 8122 spv::ImageOperandsMask mask = spv::ImageOperandsMask ::MaskNone ; 8123if (sampler .isMultiSample ()) { 8124mask = mask | spv::ImageOperandsMask ::Sample ; 8125 } 8126if (cracked .lod ) { 8127builder .addExtension (spv::E_SPV_AMD_shader_image_load_store_lod ); 8128builder .addCapability (spv::Capability ::ImageReadWriteLodAMD ); 8129mask = mask | spv::ImageOperandsMask ::Lod ; 8130 } 8131mask = mask |TranslateImageOperands (TranslateCoherent (imageType )); 8132mask = (spv::ImageOperandsMask )(mask & ~spv::ImageOperandsMask ::MakeTexelAvailableKHR ); 8133mask = mask |signExtensionMask (); 8134if (mask != spv::ImageOperandsMask ::MaskNone ) { 8135 spv::IdImmediate imageOperands = { false, (unsigned int )mask }; 8136operands .push_back (imageOperands ); 8137 } 8138if (anySet (mask , spv::ImageOperandsMask ::Sample )) { 8139 spv::IdImmediate imageOperand = { true,* opIt ++ }; 8140operands .push_back (imageOperand ); 8141 } 8142if (anySet (mask , spv::ImageOperandsMask ::Lod )) { 8143 spv::IdImmediate imageOperand = { true,* opIt ++ }; 8144operands .push_back (imageOperand ); 8145 } 8146if (anySet (mask , spv::ImageOperandsMask ::MakeTexelVisibleKHR )) { 8147 spv::IdImmediate imageOperand = { true, 8148builder .makeUintConstant (TranslateMemoryScope (TranslateCoherent (imageType ))) }; 8149operands .push_back (imageOperand ); 8150 } 8151 8152if (builder .getImageTypeFormat (builder .getImageType (operands .front ().word ))== spv::ImageFormat ::Unknown ) 8153builder .addCapability (spv::Capability ::StorageImageReadWithoutFormat ); 8154 8155 std::vector < spv::Id > result (1 ,builder .createOp (spv::Op ::OpImageRead ,resultType (),operands )); 8156builder .setPrecision (result [0 ],precision ); 8157 8158// If needed, add a conversion constructor to the proper size. 8159if (components != node -> getType ().getVectorSize ()) 8160result [0 ]= builder .createConstructor (precision ,result ,convertGlslangToSpvType (node -> getType ())); 8161 8162return result [0 ]; 8163 }else if (node -> getOp ()== glslang::EOpImageStore || node -> getOp ()== glslang::EOpImageStoreLod ) { 8164 8165// Push the texel value before the operands 8166if (sampler .isMultiSample ()|| cracked .lod ) { 8167 spv::IdImmediate texel = { true,* (opIt + 1 ) }; 8168operands .push_back (texel ); 8169 }else { 8170 spv::IdImmediate texel = { true,* opIt }; 8171operands .push_back (texel ); 8172 } 8173 8174 spv::ImageOperandsMask mask = spv::ImageOperandsMask ::MaskNone ; 8175if (sampler .isMultiSample ()) { 8176mask = mask | spv::ImageOperandsMask ::Sample ; 8177 } 8178if (cracked .lod ) { 8179builder .addExtension (spv::E_SPV_AMD_shader_image_load_store_lod ); 8180builder .addCapability (spv::Capability ::ImageReadWriteLodAMD ); 8181mask = mask | spv::ImageOperandsMask ::Lod ; 8182 } 8183mask = mask |TranslateImageOperands (TranslateCoherent (imageType )); 8184mask = (spv::ImageOperandsMask )(mask & ~spv::ImageOperandsMask ::MakeTexelVisibleKHR ); 8185mask = mask |signExtensionMask (); 8186if (mask != spv::ImageOperandsMask ::MaskNone ) { 8187 spv::IdImmediate imageOperands = { false, (unsigned int )mask }; 8188operands .push_back (imageOperands ); 8189 } 8190if (anySet (mask , spv::ImageOperandsMask ::Sample )) { 8191 spv::IdImmediate imageOperand = { true,* opIt ++ }; 8192operands .push_back (imageOperand ); 8193 } 8194if (anySet (mask , spv::ImageOperandsMask ::Lod )) { 8195 spv::IdImmediate imageOperand = { true,* opIt ++ }; 8196operands .push_back (imageOperand ); 8197 } 8198if (anySet (mask , spv::ImageOperandsMask ::MakeTexelAvailableKHR )) { 8199 spv::IdImmediate imageOperand = { true, 8200builder .makeUintConstant (TranslateMemoryScope (TranslateCoherent (imageType ))) }; 8201operands .push_back (imageOperand ); 8202 } 8203 8204builder .createNoResultOp (spv::Op ::OpImageWrite ,operands ); 8205if (builder .getImageTypeFormat (builder .getImageType (operands .front ().word ))== spv::ImageFormat ::Unknown ) 8206builder .addCapability (spv::Capability ::StorageImageWriteWithoutFormat ); 8207return spv::NoResult ; 8208 }else if (node -> getOp ()== glslang::EOpSparseImageLoad || 8209node -> getOp ()== glslang::EOpSparseImageLoadLod ) { 8210builder .addCapability (spv::Capability ::SparseResidency ); 8211if (builder .getImageTypeFormat (builder .getImageType (operands .front ().word ))== spv::ImageFormat ::Unknown ) 8212builder .addCapability (spv::Capability ::StorageImageReadWithoutFormat ); 8213 8214 spv::ImageOperandsMask mask = spv::ImageOperandsMask ::MaskNone ; 8215if (sampler .isMultiSample ()) { 8216mask = mask | spv::ImageOperandsMask ::Sample ; 8217 } 8218if (cracked .lod ) { 8219builder .addExtension (spv::E_SPV_AMD_shader_image_load_store_lod ); 8220builder .addCapability (spv::Capability ::ImageReadWriteLodAMD ); 8221 8222mask = mask | spv::ImageOperandsMask ::Lod ; 8223 } 8224mask = mask |TranslateImageOperands (TranslateCoherent (imageType )); 8225mask = (spv::ImageOperandsMask )(mask & ~spv::ImageOperandsMask ::MakeTexelAvailableKHR ); 8226mask = mask |signExtensionMask (); 8227if (mask != spv::ImageOperandsMask ::MaskNone ) { 8228 spv::IdImmediate imageOperands = { false, (unsigned int )mask }; 8229operands .push_back (imageOperands ); 8230 } 8231if (anySet (mask , spv::ImageOperandsMask ::Sample )) { 8232 spv::IdImmediate imageOperand = { true,* opIt ++ }; 8233operands .push_back (imageOperand ); 8234 } 8235if (anySet (mask , spv::ImageOperandsMask ::Lod )) { 8236 spv::IdImmediate imageOperand = { true,* opIt ++ }; 8237operands .push_back (imageOperand ); 8238 } 8239if (anySet (mask , spv::ImageOperandsMask ::MakeTexelVisibleKHR )) { 8240 spv::IdImmediate imageOperand = { true,builder .makeUintConstant (TranslateMemoryScope ( 8241TranslateCoherent (imageType ))) }; 8242operands .push_back (imageOperand ); 8243 } 8244 8245// Create the return type that was a special structure 8246 spv::Id texelOut = * opIt ; 8247 spv::Id typeId0 = resultType (); 8248 spv::Id typeId1 = builder .getDerefTypeId (texelOut ); 8249 spv::Id resultTypeId = builder .makeStructResultType (typeId0 ,typeId1 ); 8250 8251 spv::Id resultId = builder .createOp (spv::Op ::OpImageSparseRead ,resultTypeId ,operands ); 8252 8253// Decode the return type 8254builder .createStore (builder .createCompositeExtract (resultId ,typeId1 ,1 ),texelOut ); 8255return builder .createCompositeExtract (resultId ,typeId0 ,0 ); 8256 }else { 8257// Process image atomic operations 8258 8259// GLSL "IMAGE_PARAMS" will involve in constructing an image texel pointer and this pointer, 8260// as the first source operand, is required by SPIR-V atomic operations. 8261// For non-MS, the sample value should be 0 8262 spv::IdImmediate sample = { true,sampler .isMultiSample () ?* (opIt ++ ) :builder .makeUintConstant (0 ) }; 8263operands .push_back (sample ); 8264 8265 spv::Id resultTypeId ; 8266 glslang::TBasicType typeProxy = node -> getBasicType (); 8267// imageAtomicStore has a void return type so base the pointer type on 8268// the type of the value operand. 8269if (node -> getOp ()== glslang::EOpImageAtomicStore ) { 8270resultTypeId = builder .makePointer (spv::StorageClass ::Image ,builder .getTypeId (* opIt )); 8271typeProxy = node -> getAsAggregate ()-> getSequence ()[0 ]-> getAsTyped ()-> getType ().getSampler ().type ; 8272 }else { 8273resultTypeId = builder .makePointer (spv::StorageClass ::Image ,resultType ()); 8274 } 8275 8276// EXT_descriptor_heap 8277// For image atomic parameter, using untyped image texel pointer to carry on type metadata. 8278 spv::Op imgTexelOp = spv::Op ::OpImageTexelPointer ; 8279if (node -> getQualifier ().isUsedByAtomic ()&& 8280imageType .getQualifier ().builtIn == glslang::EbvResourceHeapEXT ) { 8281operands .insert (operands .begin (), {true,convertGlslangToSpvType (imageType )}); 8282imgTexelOp = spv::Op ::OpUntypedImageTexelPointerEXT ; 8283resultTypeId = builder .makeUntypedPointer (spv::StorageClass ::Image ); 8284 } 8285 8286 spv::Id pointer = builder .createOp (imgTexelOp ,resultTypeId ,operands ); 8287if (imageType .getQualifier ().nonUniform ) { 8288auto & extensions = glslangIntermediate -> getRequestedExtensions (); 8289if (extensions .find ("GL_EXT_descriptor_heap" )== extensions .end ()) { 8290builder .addDecoration (pointer , spv::Decoration ::NonUniformEXT ); 8291 } 8292 } 8293 8294 std::vector < spv::Id > operands ; 8295operands .push_back (pointer ); 8296for (;opIt != arguments .end ();++ opIt ) 8297operands .push_back (* opIt ); 8298 8299return createAtomicOperation (node -> getOp (),precision ,resultType (),operands ,typeProxy , 8300lvalueCoherentFlags ,node -> getType ()); 8301 } 8302 } 8303 8304// Check for fragment mask functions other than queries 8305if (cracked .fragMask ) { 8306assert (sampler .ms ); 8307 8308auto opIt = arguments .begin (); 8309 std::vector < spv::Id > operands ; 8310 8311operands .push_back (params .sampler ); 8312++ opIt ; 8313 8314if (sampler .isSubpass ()) { 8315// add on the (0,0) coordinate 8316 spv::Id zero = builder .makeIntConstant (0 ); 8317 std::vector < spv::Id > comps ; 8318comps .push_back (zero ); 8319comps .push_back (zero ); 8320operands .push_back (builder .makeCompositeConstant ( 8321builder .makeVectorType (builder .makeIntType (32 ),2 ),comps )); 8322 } 8323 8324for (;opIt != arguments .end ();++ opIt ) 8325operands .push_back (* opIt ); 8326 8327 spv::Op fragMaskOp = spv::Op ::OpNop ; 8328if (node -> getOp ()== glslang::EOpFragmentMaskFetch ) 8329fragMaskOp = spv::Op ::OpFragmentMaskFetchAMD ; 8330else if (node -> getOp ()== glslang::EOpFragmentFetch ) 8331fragMaskOp = spv::Op ::OpFragmentFetchAMD ; 8332 8333builder .addExtension (spv::E_SPV_AMD_shader_fragment_mask ); 8334builder .addCapability (spv::Capability ::FragmentMaskAMD ); 8335return builder .createOp (fragMaskOp ,resultType (),operands ); 8336 } 8337 8338// Check for texture functions other than queries 8339bool sparse = node -> isSparseTexture (); 8340bool imageFootprint = node -> isImageFootprint (); 8341bool cubeCompare = sampler .dim == glslang::EsdCube && sampler .isArrayed ()&& sampler .isShadow (); 8342 8343// check for bias argument 8344bool bias = false; 8345if (!cracked .lod && !cracked .grad && !cracked .fetch && !cubeCompare ) { 8346int nonBiasArgCount = 2 ; 8347if (cracked .gather ) 8348++ nonBiasArgCount ;// comp argument should be present when bias argument is present 8349 8350if (f16ShadowCompare ) 8351++ nonBiasArgCount ; 8352if (cracked .offset ) 8353++ nonBiasArgCount ; 8354else if (cracked .offsets ) 8355++ nonBiasArgCount ; 8356if (cracked .grad ) 8357nonBiasArgCount += 2 ; 8358if (cracked .lodClamp ) 8359++ nonBiasArgCount ; 8360if (sparse ) 8361++ nonBiasArgCount ; 8362if (imageFootprint ) 8363//Following three extra arguments 8364// int granularity, bool coarse, out gl_TextureFootprint2DNV footprint 8365nonBiasArgCount += 3 ; 8366if ((int )arguments .size ()> nonBiasArgCount ) 8367bias = true; 8368 } 8369 8370if (cracked .gather ) { 8371const auto & sourceExtensions = glslangIntermediate -> getRequestedExtensions (); 8372if (bias || cracked .lod || 8373sourceExtensions .find (glslang::E_GL_AMD_texture_gather_bias_lod )!= sourceExtensions .end ()) { 8374builder .addExtension (spv::E_SPV_AMD_texture_gather_bias_lod ); 8375builder .addCapability (spv::Capability ::ImageGatherBiasLodAMD ); 8376 } 8377 } 8378 8379// set the rest of the arguments 8380 8381params .coords = arguments [1 ]; 8382int extraArgs = 0 ; 8383bool noImplicitLod = false; 8384 8385// sort out where Dref is coming from 8386if (cubeCompare || f16ShadowCompare ) { 8387params .Dref = arguments [2 ]; 8388++ extraArgs ; 8389 }else if (sampler .shadow && cracked .gather ) { 8390params .Dref = arguments [2 ]; 8391++ extraArgs ; 8392 }else if (sampler .shadow ) { 8393 std::vector < spv::Id > indexes ; 8394int dRefComp ; 8395if (cracked .proj ) 8396dRefComp = 2 ;// "The resulting 3rd component of P in the shadow forms is used as Dref" 8397else 8398dRefComp = builder .getNumComponents (params .coords )- 1 ; 8399indexes .push_back (dRefComp ); 8400params .Dref = builder .createCompositeExtract (params .coords , 8401builder .getScalarTypeId (builder .getTypeId (params .coords )),indexes ); 8402 } 8403 8404// lod 8405if (cracked .lod ) { 8406params .lod = arguments [2 + extraArgs ]; 8407++ extraArgs ; 8408 }else if (glslangIntermediate -> getStage ()!= EShLangFragment && 8409 !(glslangIntermediate -> getStage ()== EShLangCompute && 8410glslangIntermediate -> hasLayoutDerivativeModeNone ())) { 8411// we need to invent the default lod for an explicit lod instruction for a non-fragment stage 8412noImplicitLod = true; 8413 } 8414 8415// multisample 8416if (sampler .isMultiSample ()) { 8417params .sample = arguments [2 + extraArgs ];// For MS, "sample" should be specified 8418++ extraArgs ; 8419 } 8420 8421// gradient 8422if (cracked .grad ) { 8423params .gradX = arguments [2 + extraArgs ]; 8424params .gradY = arguments [3 + extraArgs ]; 8425extraArgs += 2 ; 8426 } 8427 8428// offset and offsets 8429if (cracked .offset ) { 8430params .offset = arguments [2 + extraArgs ]; 8431++ extraArgs ; 8432 }else if (cracked .offsets ) { 8433params .offsets = arguments [2 + extraArgs ]; 8434++ extraArgs ; 8435 } 8436 8437// lod clamp 8438if (cracked .lodClamp ) { 8439params .lodClamp = arguments [2 + extraArgs ]; 8440++ extraArgs ; 8441 } 8442// sparse 8443if (sparse ) { 8444params .texelOut = arguments [2 + extraArgs ]; 8445++ extraArgs ; 8446 } 8447// gather component 8448if (cracked .gather && !sampler .shadow ) { 8449// default component is 0, if missing, otherwise an argument 8450if (2 + extraArgs < (int )arguments .size ()) { 8451params .component = arguments [2 + extraArgs ]; 8452++ extraArgs ; 8453 }else 8454params .component = builder .makeIntConstant (0 ); 8455 } 8456 spv::Id resultStruct = spv::NoResult ; 8457if (imageFootprint ) { 8458//Following three extra arguments 8459// int granularity, bool coarse, out gl_TextureFootprint2DNV footprint 8460params .granularity = arguments [2 + extraArgs ]; 8461params .coarse = arguments [3 + extraArgs ]; 8462resultStruct = arguments [4 + extraArgs ]; 8463extraArgs += 3 ; 8464 } 8465 8466// bias 8467if (bias ) { 8468params .bias = arguments [2 + extraArgs ]; 8469++ extraArgs ; 8470 } 8471 8472if (imageFootprint ) { 8473builder .addExtension (spv::E_SPV_NV_shader_image_footprint ); 8474builder .addCapability (spv::Capability ::ImageFootprintNV ); 8475 8476 8477//resultStructType(OpenGL type) contains 5 elements: 8478//struct gl_TextureFootprint2DNV { 8479// uvec2 anchor; 8480// uvec2 offset; 8481// uvec2 mask; 8482// uint lod; 8483// uint granularity; 8484//}; 8485//or 8486//struct gl_TextureFootprint3DNV { 8487// uvec3 anchor; 8488// uvec3 offset; 8489// uvec2 mask; 8490// uint lod; 8491// uint granularity; 8492//}; 8493 spv::Id resultStructType = builder .getContainedTypeId (builder .getTypeId (resultStruct )); 8494assert (builder .isStructType (resultStructType )); 8495 8496//resType (SPIR-V type) contains 6 elements: 8497//Member 0 must be a Boolean type scalar(LOD), 8498//Member 1 must be a vector of integer type, whose Signedness operand is 0(anchor), 8499//Member 2 must be a vector of integer type, whose Signedness operand is 0(offset), 8500//Member 3 must be a vector of integer type, whose Signedness operand is 0(mask), 8501//Member 4 must be a scalar of integer type, whose Signedness operand is 0(lod), 8502//Member 5 must be a scalar of integer type, whose Signedness operand is 0(granularity). 8503 std::vector < spv::Id > members ; 8504members .push_back (resultType ()); 8505for (int i = 0 ;i < 5 ;i ++ ) { 8506members .push_back (builder .getContainedTypeId (resultStructType ,i )); 8507 } 8508 spv::Id resType = builder .makeStructType (members , {},"ResType" ); 8509 8510//call ImageFootprintNV 8511 spv::Id res = builder .createTextureCall (precision ,resType ,sparse ,cracked .fetch ,cracked .proj , 8512cracked .gather ,noImplicitLod ,params ,signExtensionMask ()); 8513 8514//copy resType (SPIR-V type) to resultStructType(OpenGL type) 8515for (int i = 0 ;i < 5 ;i ++ ) { 8516builder .clearAccessChain (); 8517builder .setAccessChainLValue (resultStruct ); 8518 8519//Accessing to a struct we created, no coherent flag is set 8520 spv::Builder ::AccessChain ::CoherentFlags flags ; 8521flags .clear (); 8522 8523builder .accessChainPush (builder .makeIntConstant (i ),flags ,0 ); 8524builder .accessChainStore (builder .createCompositeExtract (res ,builder .getContainedTypeId (resType ,i + 1 ), 8525i + 1 ),TranslateNonUniformDecoration (imageType .getQualifier ())); 8526 } 8527return builder .createCompositeExtract (res ,resultType (),0 ); 8528 } 8529 8530// projective component (might not to move) 8531// GLSL: "The texture coordinates consumed from P, not including the last component of P, 8532// are divided by the last component of P." 8533// SPIR-V: "... (u [, v] [, w], q)... It may be a vector larger than needed, but all 8534// unused components will appear after all used components." 8535if (cracked .proj ) { 8536int projSourceComp = builder .getNumComponents (params .coords )- 1 ; 8537int projTargetComp ; 8538switch (sampler .dim ) { 8539case glslang::Esd1D :projTargetComp = 1 ;break ; 8540case glslang::Esd2D :projTargetComp = 2 ;break ; 8541case glslang::EsdRect :projTargetComp = 2 ;break ; 8542default :projTargetComp = projSourceComp ;break ; 8543 } 8544// copy the projective coordinate if we have to 8545if (projTargetComp != projSourceComp ) { 8546 spv::Id projComp = builder .createCompositeExtract (params .coords , 8547builder .getScalarTypeId (builder .getTypeId (params .coords )),projSourceComp ); 8548params .coords = builder .createCompositeInsert (projComp ,params .coords , 8549builder .getTypeId (params .coords ),projTargetComp ); 8550 } 8551 } 8552 8553if (cracked .gather ) { 8554 spv::GatherModes mode = spv::GatherModes ::Max ; 8555switch (node -> getOp ()) { 8556case glslang::EOpTextureGather4x1QCOM : 8557case glslang::EOpTextureGather4x1OffsetQCOM : 8558mode = spv::GatherModes ::Gather4x1QCOM ; 8559break ; 8560case glslang::EOpTextureGatherDQCOM : 8561case glslang::EOpTextureGatherDOffsetQCOM : 8562mode = spv::GatherModes ::GatherDQCOM ; 8563break ; 8564case glslang::EOpTextureGatherH2QCOM : 8565case glslang::EOpTextureGatherH2OffsetQCOM : 8566mode = spv::GatherModes ::GatherH2QCOM ; 8567break ; 8568case glslang::EOpTextureGatherV2QCOM : 8569case glslang::EOpTextureGatherV2OffsetQCOM : 8570mode = spv::GatherModes ::GatherV2QCOM ; 8571break ; 8572default : 8573break ; 8574 } 8575 8576if (mode != spv::GatherModes ::Max ) { 8577if (mode == spv::GatherModes ::Gather4x1QCOM ) { 8578builder .addCapability (spv::Capability ::ImageGatherLinearQCOM ); 8579 }else { 8580builder .addCapability (spv::Capability ::ImageGatherExtendedModesQCOM ); 8581 } 8582builder .addExtension (spv::E_SPV_QCOM_image_processing3 ); 8583params .gatherMode = builder .makeIntConstant (unsigned (mode )); 8584 } 8585 } 8586 8587// nonprivate 8588if (imageType .getQualifier ().nonprivate ) { 8589params .nonprivate = true; 8590 } 8591 8592// volatile 8593if (imageType .getQualifier ().volatil ) { 8594params .volatil = true; 8595 } 8596 8597if (imageType .getQualifier ().nontemporal ) { 8598params .nontemporal = true; 8599 } 8600 8601 std::vector < spv::Id > result (1 , 8602builder .createTextureCall (precision ,resultType (),sparse ,cracked .fetch ,cracked .proj ,cracked .gather , 8603noImplicitLod ,params ,signExtensionMask ()) 8604 ); 8605 8606if (components != node -> getType ().getVectorSize ()) 8607result [0 ]= builder .createConstructor (precision ,result ,convertGlslangToSpvType (node -> getType ())); 8608 8609return result [0 ]; 8610} 8611 8612spv::Id TGlslangToSpvTraverser ::handleUserFunctionCall (const glslang::TIntermAggregate * node ) 8613{ 8614// Grab the function's pointer from the previously created function 8615 spv::Function * function = functionMap [node -> getName ().c_str ()]; 8616if (!function ) 8617return 0 ; 8618 8619const glslang::TIntermSequence & glslangArgs = node -> getSequence (); 8620const glslang::TQualifierList & qualifiers = node -> getQualifierList (); 8621 8622// See comments in makeFunctions() for details about the semantics for parameter passing. 8623// 8624// These imply we need a four step process: 8625// 1. Evaluate the arguments 8626// 2. Allocate and make copies of in, out, and inout arguments 8627// 3. Make the call 8628// 4. Copy back the results 8629 8630// 1. Evaluate the arguments and their types 8631 std::vector < spv::Builder ::AccessChain > lValues ; 8632 std::vector < spv::Id > rValues ; 8633 std::vector < const glslang::TType *> argTypes ; 8634for (int a = 0 ;a < (int )glslangArgs .size ();++ a ) { 8635argTypes .push_back (& glslangArgs [a ]-> getAsTyped ()-> getType ()); 8636// build l-value 8637builder .clearAccessChain (); 8638glslangArgs [a ]-> traverse (this ); 8639// keep outputs and pass-by-originals as l-values, evaluate others as r-values 8640if (originalParam (qualifiers [a ],* argTypes [a ],function -> hasImplicitThis ()&& a == 0 )|| 8641writableParam (qualifiers [a ])) { 8642// save l-value 8643lValues .push_back (builder .getAccessChain ()); 8644 }else { 8645// process r-value 8646rValues .push_back (accessChainLoad (* argTypes .back ())); 8647 } 8648 } 8649 8650// Reset source location to the function call location after argument evaluation 8651builder .setDebugSourceLocation (node -> getLoc ().line ,node -> getLoc ().getFilename ()); 8652 8653// 2. Allocate space for anything needing a copy, and if it's "in" or "inout" 8654// copy the original into that space. 8655// 8656// Also, build up the list of actual arguments to pass in for the call 8657int lValueCount = 0 ; 8658int rValueCount = 0 ; 8659 std::vector < spv::Id > spvArgs ; 8660for (int a = 0 ;a < (int )glslangArgs .size ();++ a ) { 8661 spv::Id arg ; 8662if (originalParam (qualifiers [a ],* argTypes [a ],function -> hasImplicitThis ()&& a == 0 )) { 8663builder .setAccessChain (lValues [lValueCount ]); 8664arg = builder .accessChainGetLValue (); 8665++ lValueCount ; 8666 }else if (writableParam (qualifiers [a ])) { 8667// need space to hold the copy 8668arg = builder .createVariable (function -> getParamPrecision (a ), spv::StorageClass ::Function , 8669builder .getContainedTypeId (function -> getParamType (a )),"param" ); 8670if (qualifiers [a ]== glslang::EvqIn || qualifiers [a ]== glslang::EvqInOut ) { 8671// need to copy the input into output space 8672builder .setAccessChain (lValues [lValueCount ]); 8673 spv::Id copy = accessChainLoad (* argTypes [a ]); 8674builder .clearAccessChain (); 8675builder .setAccessChainLValue (arg ); 8676multiTypeStore (* argTypes [a ],copy ); 8677 } 8678++ lValueCount ; 8679 }else { 8680// process r-value, which involves a copy for a type mismatch 8681if (function -> getParamType (a )!= builder .getTypeId (rValues [rValueCount ])|| 8682TranslatePrecisionDecoration (* argTypes [a ])!= function -> getParamPrecision (a )) 8683 { 8684 spv::Id argCopy = builder .createVariable (function -> getParamPrecision (a ), spv::StorageClass ::Function ,function -> getParamType (a ),"arg" ); 8685builder .clearAccessChain (); 8686builder .setAccessChainLValue (argCopy ); 8687multiTypeStore (* argTypes [a ],rValues [rValueCount ]); 8688arg = builder .createLoad (argCopy ,function -> getParamPrecision (a )); 8689 }else 8690arg = rValues [rValueCount ]; 8691++ rValueCount ; 8692 } 8693spvArgs .push_back (arg ); 8694 } 8695 8696// 3. Make the call. 8697 spv::Id result = builder .createFunctionCall (function ,spvArgs ); 8698builder .setPrecision (result ,TranslatePrecisionDecoration (node -> getType ())); 8699builder .addDecoration (result ,TranslateNonUniformDecoration (node -> getType ().getQualifier ())); 8700 8701// 4. Copy back out an "out" arguments. 8702lValueCount = 0 ; 8703for (int a = 0 ;a < (int )glslangArgs .size ();++ a ) { 8704if (originalParam (qualifiers [a ],* argTypes [a ],function -> hasImplicitThis ()&& a == 0 )) 8705++ lValueCount ; 8706else if (writableParam (qualifiers [a ])) { 8707if (qualifiers [a ]== glslang::EvqOut || qualifiers [a ]== glslang::EvqInOut ) { 8708 spv::Id copy = builder .createLoad (spvArgs [a ], spv::NoPrecision ); 8709builder .addDecoration (copy ,TranslateNonUniformDecoration (argTypes [a ]-> getQualifier ())); 8710builder .setAccessChain (lValues [lValueCount ]); 8711multiTypeStore (* argTypes [a ],copy ); 8712 } 8713++ lValueCount ; 8714 } 8715 } 8716 8717return result ; 8718} 8719 8720// Translate AST operation to SPV operation, already having SPV-based operands/types. 8721spv::Id TGlslangToSpvTraverser ::createBinaryOperation (glslang::TOperator op ,OpDecorations & decorations , 8722 spv::Id typeId , spv::Id left , spv::Id right , 8723 glslang::TBasicType typeProxy ,bool reduceComparison ) 8724{ 8725bool isUnsigned = isTypeUnsignedInt (typeProxy ); 8726bool isFloat = isTypeFloat (typeProxy ); 8727bool isBool = typeProxy == glslang::EbtBool ; 8728 8729 spv::Op binOp = spv::Op ::OpNop ; 8730bool needMatchingVectors = true;// for non-matrix ops, would a scalar need to smear to match a vector? 8731bool comparison = false; 8732 8733switch (op ) { 8734case glslang::EOpAdd : 8735case glslang::EOpAddAssign : 8736if (isFloat ) 8737binOp = spv::Op ::OpFAdd ; 8738else 8739binOp = spv::Op ::OpIAdd ; 8740break ; 8741case glslang::EOpSub : 8742case glslang::EOpSubAssign : 8743if (isFloat ) 8744binOp = spv::Op ::OpFSub ; 8745else 8746binOp = spv::Op ::OpISub ; 8747break ; 8748case glslang::EOpMul : 8749case glslang::EOpMulAssign : 8750if (isFloat ) 8751binOp = spv::Op ::OpFMul ; 8752else 8753binOp = spv::Op ::OpIMul ; 8754break ; 8755case glslang::EOpVectorTimesScalar : 8756case glslang::EOpVectorTimesScalarAssign : 8757if (isFloat && (builder .isVector (left )|| builder .isVector (right )|| builder .isCooperativeVector (left )|| builder .isCooperativeVector (right ))) { 8758if (builder .isVector (right )|| builder .isCooperativeVector (right )) 8759 std::swap (left ,right ); 8760assert (builder .isScalar (right )); 8761needMatchingVectors = false; 8762binOp = spv::Op ::OpVectorTimesScalar ; 8763 }else if (isFloat ) { 8764binOp = spv::Op ::OpFMul ; 8765 }else if (builder .isCooperativeVector (left )|| builder .isCooperativeVector (right )) { 8766if (builder .isCooperativeVector (right )) 8767 std::swap (left ,right ); 8768assert (builder .isScalar (right )); 8769// Construct a cooperative vector from the scalar 8770right = builder .createCompositeConstruct (builder .getTypeId (left ), {right }); 8771binOp = spv::Op ::OpIMul ; 8772 }else { 8773binOp = spv::Op ::OpIMul ; 8774 } 8775break ; 8776case glslang::EOpVectorTimesMatrix : 8777case glslang::EOpVectorTimesMatrixAssign : 8778binOp = spv::Op ::OpVectorTimesMatrix ; 8779break ; 8780case glslang::EOpMatrixTimesVector : 8781binOp = spv::Op ::OpMatrixTimesVector ; 8782break ; 8783case glslang::EOpMatrixTimesScalar : 8784case glslang::EOpMatrixTimesScalarAssign : 8785binOp = spv::Op ::OpMatrixTimesScalar ; 8786break ; 8787case glslang::EOpMatrixTimesMatrix : 8788case glslang::EOpMatrixTimesMatrixAssign : 8789binOp = spv::Op ::OpMatrixTimesMatrix ; 8790break ; 8791case glslang::EOpOuterProduct : 8792binOp = spv::Op ::OpOuterProduct ; 8793needMatchingVectors = false; 8794break ; 8795case glslang::EOpDot : 8796if (typeProxy == glslang::EbtBFloat16 ) { 8797builder .addExtension (spv::E_SPV_KHR_bfloat16 ); 8798builder .addCapability (spv::Capability ::BFloat16DotProductKHR ); 8799 } 8800binOp = spv::Op ::OpDot ; 8801break ; 8802 8803case glslang::EOpDiv : 8804case glslang::EOpDivAssign : 8805if (isFloat ) 8806binOp = spv::Op ::OpFDiv ; 8807else if (isUnsigned ) 8808binOp = spv::Op ::OpUDiv ; 8809else 8810binOp = spv::Op ::OpSDiv ; 8811break ; 8812case glslang::EOpMod : 8813case glslang::EOpModAssign : 8814if (isFloat ) 8815binOp = spv::Op ::OpFMod ; 8816else if (isUnsigned ) 8817binOp = spv::Op ::OpUMod ; 8818else 8819binOp = spv::Op ::OpSMod ; 8820break ; 8821case glslang::EOpRightShift : 8822case glslang::EOpRightShiftAssign : 8823if (isUnsigned ) 8824binOp = spv::Op ::OpShiftRightLogical ; 8825else 8826binOp = spv::Op ::OpShiftRightArithmetic ; 8827break ; 8828case glslang::EOpLeftShift : 8829case glslang::EOpLeftShiftAssign : 8830binOp = spv::Op ::OpShiftLeftLogical ; 8831break ; 8832case glslang::EOpAnd : 8833case glslang::EOpAndAssign : 8834binOp = spv::Op ::OpBitwiseAnd ; 8835break ; 8836case glslang::EOpLogicalAnd : 8837needMatchingVectors = false; 8838binOp = spv::Op ::OpLogicalAnd ; 8839break ; 8840case glslang::EOpInclusiveOr : 8841case glslang::EOpInclusiveOrAssign : 8842binOp = spv::Op ::OpBitwiseOr ; 8843break ; 8844case glslang::EOpLogicalOr : 8845needMatchingVectors = false; 8846binOp = spv::Op ::OpLogicalOr ; 8847break ; 8848case glslang::EOpExclusiveOr : 8849case glslang::EOpExclusiveOrAssign : 8850binOp = spv::Op ::OpBitwiseXor ; 8851break ; 8852case glslang::EOpLogicalXor : 8853needMatchingVectors = false; 8854binOp = spv::Op ::OpLogicalNotEqual ; 8855break ; 8856 8857case glslang::EOpAbsDifference : 8858binOp = isUnsigned ? spv::Op ::OpAbsUSubINTEL : spv::Op ::OpAbsISubINTEL ; 8859break ; 8860 8861case glslang::EOpAddSaturate : 8862binOp = isUnsigned ? spv::Op ::OpUAddSatINTEL : spv::Op ::OpIAddSatINTEL ; 8863break ; 8864 8865case glslang::EOpSubSaturate : 8866binOp = isUnsigned ? spv::Op ::OpUSubSatINTEL : spv::Op ::OpISubSatINTEL ; 8867break ; 8868 8869case glslang::EOpAverage : 8870binOp = isUnsigned ? spv::Op ::OpUAverageINTEL : spv::Op ::OpIAverageINTEL ; 8871break ; 8872 8873case glslang::EOpAverageRounded : 8874binOp = isUnsigned ? spv::Op ::OpUAverageRoundedINTEL : spv::Op ::OpIAverageRoundedINTEL ; 8875break ; 8876 8877case glslang::EOpMul32x16 : 8878binOp = isUnsigned ? spv::Op ::OpUMul32x16INTEL : spv::Op ::OpIMul32x16INTEL ; 8879break ; 8880 8881case glslang::EOpExpectEXT : 8882binOp = spv::Op ::OpExpectKHR ; 8883break ; 8884 8885case glslang::EOpLessThan : 8886case glslang::EOpGreaterThan : 8887case glslang::EOpLessThanEqual : 8888case glslang::EOpGreaterThanEqual : 8889case glslang::EOpEqual : 8890case glslang::EOpNotEqual : 8891case glslang::EOpVectorEqual : 8892case glslang::EOpVectorNotEqual : 8893comparison = true; 8894break ; 8895default : 8896break ; 8897 } 8898 8899// handle mapped binary operations (should be non-comparison) 8900if (binOp != spv::Op ::OpNop ) { 8901assert (comparison == false); 8902if (builder .isMatrix (left )|| builder .isMatrix (right )|| 8903builder .isCooperativeMatrix (left )|| builder .isCooperativeMatrix (right )) 8904return createBinaryMatrixOperation (binOp ,decorations ,typeId ,left ,right ); 8905 8906// No matrix involved; make both operands be the same number of components, if needed 8907if (needMatchingVectors ) 8908builder .promoteScalar (decorations .precision ,left ,right ); 8909 8910 spv::Id result = builder .createBinOp (binOp ,typeId ,left ,right ); 8911decorations .addNoContraction (builder ,result ); 8912decorations .addNonUniform (builder ,result ); 8913return builder .setPrecision (result ,decorations .precision ); 8914 } 8915 8916if (!comparison ) 8917return 0 ; 8918 8919// Handle comparison instructions 8920 8921if (reduceComparison && (op == glslang::EOpEqual || op == glslang::EOpNotEqual ) 8922&& (builder .isVector (left )|| builder .isMatrix (left )|| builder .isAggregate (left ))) { 8923 spv::Id result = builder .createCompositeCompare (decorations .precision ,left ,right ,op == glslang::EOpEqual ); 8924decorations .addNonUniform (builder ,result ); 8925return result ; 8926 } 8927 8928switch (op ) { 8929case glslang::EOpLessThan : 8930if (isFloat ) 8931binOp = spv::Op ::OpFOrdLessThan ; 8932else if (isUnsigned ) 8933binOp = spv::Op ::OpULessThan ; 8934else 8935binOp = spv::Op ::OpSLessThan ; 8936break ; 8937case glslang::EOpGreaterThan : 8938if (isFloat ) 8939binOp = spv::Op ::OpFOrdGreaterThan ; 8940else if (isUnsigned ) 8941binOp = spv::Op ::OpUGreaterThan ; 8942else 8943binOp = spv::Op ::OpSGreaterThan ; 8944break ; 8945case glslang::EOpLessThanEqual : 8946if (isFloat ) 8947binOp = spv::Op ::OpFOrdLessThanEqual ; 8948else if (isUnsigned ) 8949binOp = spv::Op ::OpULessThanEqual ; 8950else 8951binOp = spv::Op ::OpSLessThanEqual ; 8952break ; 8953case glslang::EOpGreaterThanEqual : 8954if (isFloat ) 8955binOp = spv::Op ::OpFOrdGreaterThanEqual ; 8956else if (isUnsigned ) 8957binOp = spv::Op ::OpUGreaterThanEqual ; 8958else 8959binOp = spv::Op ::OpSGreaterThanEqual ; 8960break ; 8961case glslang::EOpEqual : 8962case glslang::EOpVectorEqual : 8963if (isFloat ) 8964binOp = spv::Op ::OpFOrdEqual ; 8965else if (isBool ) 8966binOp = spv::Op ::OpLogicalEqual ; 8967else 8968binOp = spv::Op ::OpIEqual ; 8969break ; 8970case glslang::EOpNotEqual : 8971case glslang::EOpVectorNotEqual : 8972if (isFloat ) 8973binOp = spv::Op ::OpFUnordNotEqual ; 8974else if (isBool ) 8975binOp = spv::Op ::OpLogicalNotEqual ; 8976else 8977binOp = spv::Op ::OpINotEqual ; 8978break ; 8979default : 8980break ; 8981 } 8982 8983if (binOp != spv::Op ::OpNop ) { 8984 spv::Id result = builder .createBinOp (binOp ,typeId ,left ,right ); 8985decorations .addNoContraction (builder ,result ); 8986decorations .addNonUniform (builder ,result ); 8987return builder .setPrecision (result ,decorations .precision ); 8988 } 8989 8990return 0 ; 8991} 8992 8993// 8994// Translate AST matrix operation to SPV operation, already having SPV-based operands/types. 8995// These can be any of: 8996// 8997// matrix * scalar 8998// scalar * matrix 8999// matrix * matrix linear algebraic 9000// matrix * vector 9001// vector * matrix 9002// matrix * matrix componentwise 9003// matrix op matrix op in {+, -, /} 9004// matrix op scalar op in {+, -, /} 9005// scalar op matrix op in {+, -, /} 9006// 9007spv::Id TGlslangToSpvTraverser ::createBinaryMatrixOperation (spv::Op op ,OpDecorations & decorations , spv::Id typeId , 9008 spv::Id left , spv::Id right ) 9009{ 9010bool firstClass = true; 9011 9012// First, handle first-class matrix operations (* and matrix/scalar) 9013switch (op ) { 9014case spv::Op ::OpFDiv : 9015if (builder .isMatrix (left )&& builder .isScalar (right )) { 9016// turn matrix / scalar into a multiply... 9017 spv::Id resultType = builder .getTypeId (right ); 9018right = builder .createBinOp (spv::Op ::OpFDiv ,resultType ,builder .makeFpConstant (resultType ,1.0 ),right ); 9019op = spv::Op ::OpMatrixTimesScalar ; 9020 }else 9021firstClass = false; 9022break ; 9023case spv::Op ::OpMatrixTimesScalar : 9024if (builder .isMatrix (right )|| builder .isCooperativeMatrix (right )) 9025 std::swap (left ,right ); 9026assert (builder .isScalar (right )); 9027break ; 9028case spv::Op ::OpVectorTimesMatrix : 9029assert (builder .isVector (left )); 9030assert (builder .isMatrix (right )); 9031break ; 9032case spv::Op ::OpMatrixTimesVector : 9033assert (builder .isMatrix (left )); 9034assert (builder .isVector (right )); 9035break ; 9036case spv::Op ::OpMatrixTimesMatrix : 9037assert (builder .isMatrix (left )); 9038assert (builder .isMatrix (right )); 9039break ; 9040default : 9041firstClass = false; 9042break ; 9043 } 9044 9045if (builder .isCooperativeMatrix (left )|| builder .isCooperativeMatrix (right )) 9046firstClass = true; 9047 9048if (firstClass ) { 9049 spv::Id result = builder .createBinOp (op ,typeId ,left ,right ); 9050decorations .addNoContraction (builder ,result ); 9051decorations .addNonUniform (builder ,result ); 9052return builder .setPrecision (result ,decorations .precision ); 9053 } 9054 9055// Handle component-wise +, -, *, %, and / for all combinations of type. 9056// The result type of all of them is the same type as the (a) matrix operand. 9057// The algorithm is to: 9058// - break the matrix(es) into vectors 9059// - smear any scalar to a vector 9060// - do vector operations 9061// - make a matrix out the vector results 9062switch (op ) { 9063case spv::Op ::OpFAdd : 9064case spv::Op ::OpFSub : 9065case spv::Op ::OpFDiv : 9066case spv::Op ::OpFMod : 9067case spv::Op ::OpFMul : 9068 { 9069// one time set up... 9070bool leftMat = builder .isMatrix (left ); 9071bool rightMat = builder .isMatrix (right ); 9072unsigned int numCols = leftMat ?builder .getNumColumns (left ) :builder .getNumColumns (right ); 9073int numRows = leftMat ?builder .getNumRows (left ) :builder .getNumRows (right ); 9074 spv::Id scalarType = builder .getScalarTypeId (typeId ); 9075 spv::Id vecType = builder .makeVectorType (scalarType ,numRows ); 9076 std::vector < spv::Id > results ; 9077 spv::Id smearVec = spv::NoResult ; 9078if (builder .isScalar (left )) 9079smearVec = builder .smearScalar (decorations .precision ,left ,vecType ); 9080else if (builder .isScalar (right )) 9081smearVec = builder .smearScalar (decorations .precision ,right ,vecType ); 9082 9083// do each vector op 9084for (unsigned int c = 0 ;c < numCols ;++ c ) { 9085 std::vector < unsigned int > indexes ; 9086indexes .push_back (c ); 9087 spv::Id leftVec = leftMat ?builder .createCompositeExtract (left ,vecType ,indexes ) :smearVec ; 9088 spv::Id rightVec = rightMat ?builder .createCompositeExtract (right ,vecType ,indexes ) :smearVec ; 9089 spv::Id result = builder .createBinOp (op ,vecType ,leftVec ,rightVec ); 9090decorations .addNoContraction (builder ,result ); 9091decorations .addNonUniform (builder ,result ); 9092results .push_back (builder .setPrecision (result ,decorations .precision )); 9093 } 9094 9095// put the pieces together 9096 spv::Id result = builder .setPrecision (builder .createCompositeConstruct (typeId ,results ),decorations .precision ); 9097decorations .addNonUniform (builder ,result ); 9098return result ; 9099 } 9100default : 9101assert (0 ); 9102return spv::NoResult ; 9103 } 9104} 9105 9106spv::Id TGlslangToSpvTraverser ::createUnaryOperation (glslang::TOperator op ,OpDecorations & decorations , spv::Id typeId , 9107 spv::Id operand , glslang::TBasicType typeProxy ,const spv::Builder ::AccessChain ::CoherentFlags & lvalueCoherentFlags , 9108const glslang::TType & opType ) 9109{ 9110 spv::Op unaryOp = spv::Op ::OpNop ; 9111int extBuiltins = -1 ; 9112int libCall = -1 ; 9113bool isUnsigned = isTypeUnsignedInt (typeProxy ); 9114bool isFloat = isTypeFloat (typeProxy ); 9115 9116switch (op ) { 9117case glslang::EOpNegative : 9118if (isFloat ) { 9119unaryOp = spv::Op ::OpFNegate ; 9120if (builder .isMatrixType (typeId )) 9121return createUnaryMatrixOperation (unaryOp ,decorations ,typeId ,operand ,typeProxy ); 9122 }else 9123unaryOp = spv::Op ::OpSNegate ; 9124break ; 9125 9126case glslang::EOpLogicalNot : 9127case glslang::EOpVectorLogicalNot : 9128unaryOp = spv::Op ::OpLogicalNot ; 9129break ; 9130case glslang::EOpBitwiseNot : 9131unaryOp = spv::Op ::OpNot ; 9132break ; 9133 9134case glslang::EOpDeterminant : 9135libCall = spv::GLSLstd450Determinant ; 9136break ; 9137case glslang::EOpMatrixInverse : 9138libCall = spv::GLSLstd450MatrixInverse ; 9139break ; 9140case glslang::EOpTranspose : 9141unaryOp = spv::Op ::OpTranspose ; 9142break ; 9143 9144case glslang::EOpRadians : 9145libCall = spv::GLSLstd450Radians ; 9146break ; 9147case glslang::EOpDegrees : 9148libCall = spv::GLSLstd450Degrees ; 9149break ; 9150case glslang::EOpSin : 9151libCall = spv::GLSLstd450Sin ; 9152break ; 9153case glslang::EOpCos : 9154libCall = spv::GLSLstd450Cos ; 9155break ; 9156case glslang::EOpTan : 9157libCall = spv::GLSLstd450Tan ; 9158break ; 9159case glslang::EOpAcos : 9160libCall = spv::GLSLstd450Acos ; 9161break ; 9162case glslang::EOpAsin : 9163libCall = spv::GLSLstd450Asin ; 9164break ; 9165case glslang::EOpAtan : 9166libCall = spv::GLSLstd450Atan ; 9167break ; 9168 9169case glslang::EOpAcosh : 9170libCall = spv::GLSLstd450Acosh ; 9171break ; 9172case glslang::EOpAsinh : 9173libCall = spv::GLSLstd450Asinh ; 9174break ; 9175case glslang::EOpAtanh : 9176libCall = spv::GLSLstd450Atanh ; 9177break ; 9178case glslang::EOpTanh : 9179libCall = spv::GLSLstd450Tanh ; 9180break ; 9181case glslang::EOpCosh : 9182libCall = spv::GLSLstd450Cosh ; 9183break ; 9184case glslang::EOpSinh : 9185libCall = spv::GLSLstd450Sinh ; 9186break ; 9187 9188case glslang::EOpLength : 9189libCall = spv::GLSLstd450Length ; 9190break ; 9191case glslang::EOpNormalize : 9192libCall = spv::GLSLstd450Normalize ; 9193break ; 9194 9195case glslang::EOpExp : 9196libCall = spv::GLSLstd450Exp ; 9197break ; 9198case glslang::EOpLog : 9199libCall = spv::GLSLstd450Log ; 9200break ; 9201case glslang::EOpExp2 : 9202libCall = spv::GLSLstd450Exp2 ; 9203break ; 9204case glslang::EOpLog2 : 9205libCall = spv::GLSLstd450Log2 ; 9206break ; 9207case glslang::EOpSqrt : 9208libCall = spv::GLSLstd450Sqrt ; 9209break ; 9210case glslang::EOpInverseSqrt : 9211libCall = spv::GLSLstd450InverseSqrt ; 9212break ; 9213 9214case glslang::EOpFloor : 9215libCall = spv::GLSLstd450Floor ; 9216break ; 9217case glslang::EOpTrunc : 9218libCall = spv::GLSLstd450Trunc ; 9219break ; 9220case glslang::EOpRound : 9221libCall = spv::GLSLstd450Round ; 9222break ; 9223case glslang::EOpRoundEven : 9224libCall = spv::GLSLstd450RoundEven ; 9225break ; 9226case glslang::EOpCeil : 9227libCall = spv::GLSLstd450Ceil ; 9228break ; 9229case glslang::EOpFract : 9230libCall = spv::GLSLstd450Fract ; 9231break ; 9232 9233case glslang::EOpIsNan : 9234unaryOp = spv::Op ::OpIsNan ; 9235break ; 9236case glslang::EOpIsInf : 9237unaryOp = spv::Op ::OpIsInf ; 9238break ; 9239case glslang::EOpIsFinite : 9240unaryOp = spv::Op ::OpIsFinite ; 9241break ; 9242 9243case glslang::EOpFloatBitsToInt : 9244case glslang::EOpFloatBitsToUint : 9245case glslang::EOpIntBitsToFloat : 9246case glslang::EOpUintBitsToFloat : 9247case glslang::EOpDoubleBitsToInt64 : 9248case glslang::EOpDoubleBitsToUint64 : 9249case glslang::EOpInt64BitsToDouble : 9250case glslang::EOpUint64BitsToDouble : 9251case glslang::EOpFloat16BitsToInt16 : 9252case glslang::EOpFloat16BitsToUint16 : 9253case glslang::EOpInt16BitsToFloat16 : 9254case glslang::EOpUint16BitsToFloat16 : 9255unaryOp = spv::Op ::OpBitcast ; 9256break ; 9257 9258case glslang::EOpPackSnorm2x16 : 9259libCall = spv::GLSLstd450PackSnorm2x16 ; 9260break ; 9261case glslang::EOpUnpackSnorm2x16 : 9262libCall = spv::GLSLstd450UnpackSnorm2x16 ; 9263break ; 9264case glslang::EOpPackUnorm2x16 : 9265libCall = spv::GLSLstd450PackUnorm2x16 ; 9266break ; 9267case glslang::EOpUnpackUnorm2x16 : 9268libCall = spv::GLSLstd450UnpackUnorm2x16 ; 9269break ; 9270case glslang::EOpPackHalf2x16 : 9271libCall = spv::GLSLstd450PackHalf2x16 ; 9272break ; 9273case glslang::EOpUnpackHalf2x16 : 9274libCall = spv::GLSLstd450UnpackHalf2x16 ; 9275break ; 9276case glslang::EOpPackSnorm4x8 : 9277libCall = spv::GLSLstd450PackSnorm4x8 ; 9278break ; 9279case glslang::EOpUnpackSnorm4x8 : 9280libCall = spv::GLSLstd450UnpackSnorm4x8 ; 9281break ; 9282case glslang::EOpPackUnorm4x8 : 9283libCall = spv::GLSLstd450PackUnorm4x8 ; 9284break ; 9285case glslang::EOpUnpackUnorm4x8 : 9286libCall = spv::GLSLstd450UnpackUnorm4x8 ; 9287break ; 9288case glslang::EOpPackDouble2x32 : 9289libCall = spv::GLSLstd450PackDouble2x32 ; 9290break ; 9291case glslang::EOpUnpackDouble2x32 : 9292libCall = spv::GLSLstd450UnpackDouble2x32 ; 9293break ; 9294 9295case glslang::EOpPackInt2x32 : 9296case glslang::EOpUnpackInt2x32 : 9297case glslang::EOpPackUint2x32 : 9298case glslang::EOpUnpackUint2x32 : 9299case glslang::EOpPack16 : 9300case glslang::EOpPack32 : 9301case glslang::EOpPack64 : 9302case glslang::EOpUnpack32 : 9303case glslang::EOpUnpack16 : 9304case glslang::EOpUnpack8 : 9305case glslang::EOpPackInt2x16 : 9306case glslang::EOpUnpackInt2x16 : 9307case glslang::EOpPackUint2x16 : 9308case glslang::EOpUnpackUint2x16 : 9309case glslang::EOpPackInt4x16 : 9310case glslang::EOpUnpackInt4x16 : 9311case glslang::EOpPackUint4x16 : 9312case glslang::EOpUnpackUint4x16 : 9313case glslang::EOpPackFloat2x16 : 9314case glslang::EOpUnpackFloat2x16 : 9315case glslang::EOpUnpackFloat2xE2M1 : 9316case glslang::EOpUnpackFloat4xE2M1 : 9317case glslang::EOpUnpackFloat8xE2M1 : 9318case glslang::EOpUnpackFloat16xE2M1 : 9319case glslang::EOpPackFloat2xE2M1 : 9320case glslang::EOpPackFloat4xE2M1 : 9321case glslang::EOpPackFloat8xE2M1 : 9322case glslang::EOpPackFloat16xE2M1 : 9323case glslang::EOpUnpackFloat4xE3M2 : 9324case glslang::EOpUnpackFloat8xE3M2 : 9325case glslang::EOpUnpackFloat16xE3M2 : 9326case glslang::EOpPackFloat4xE3M2 : 9327case glslang::EOpPackFloat8xE3M2 : 9328case glslang::EOpPackFloat16xE3M2 : 9329case glslang::EOpUnpackFloat4xE2M3 : 9330case glslang::EOpUnpackFloat8xE2M3 : 9331case glslang::EOpUnpackFloat16xE2M3 : 9332case glslang::EOpPackFloat4xE2M3 : 9333case glslang::EOpPackFloat8xE2M3 : 9334case glslang::EOpPackFloat16xE2M3 : 9335 9336unaryOp = spv::Op ::OpBitcast ; 9337break ; 9338 9339case glslang::EOpDPdx : 9340if (typeProxy == glslang::EbtFloat16 ) 9341builder .addExtension (spv::E_SPV_AMD_gpu_shader_half_float ); 9342unaryOp = spv::Op ::OpDPdx ; 9343break ; 9344case glslang::EOpDPdy : 9345if (typeProxy == glslang::EbtFloat16 ) 9346builder .addExtension (spv::E_SPV_AMD_gpu_shader_half_float ); 9347unaryOp = spv::Op ::OpDPdy ; 9348break ; 9349case glslang::EOpFwidth : 9350if (typeProxy == glslang::EbtFloat16 ) 9351builder .addExtension (spv::E_SPV_AMD_gpu_shader_half_float ); 9352unaryOp = spv::Op ::OpFwidth ; 9353break ; 9354 9355case glslang::EOpAny : 9356unaryOp = spv::Op ::OpAny ; 9357break ; 9358case glslang::EOpAll : 9359unaryOp = spv::Op ::OpAll ; 9360break ; 9361 9362case glslang::EOpAbs : 9363if (isFloat ) 9364libCall = spv::GLSLstd450FAbs ; 9365else 9366libCall = spv::GLSLstd450SAbs ; 9367break ; 9368case glslang::EOpSign : 9369if (isFloat ) 9370libCall = spv::GLSLstd450FSign ; 9371else 9372libCall = spv::GLSLstd450SSign ; 9373break ; 9374 9375case glslang::EOpDPdxFine : 9376if (typeProxy == glslang::EbtFloat16 ) 9377builder .addExtension (spv::E_SPV_AMD_gpu_shader_half_float ); 9378unaryOp = spv::Op ::OpDPdxFine ; 9379break ; 9380case glslang::EOpDPdyFine : 9381if (typeProxy == glslang::EbtFloat16 ) 9382builder .addExtension (spv::E_SPV_AMD_gpu_shader_half_float ); 9383unaryOp = spv::Op ::OpDPdyFine ; 9384break ; 9385case glslang::EOpFwidthFine : 9386if (typeProxy == glslang::EbtFloat16 ) 9387builder .addExtension (spv::E_SPV_AMD_gpu_shader_half_float ); 9388unaryOp = spv::Op ::OpFwidthFine ; 9389break ; 9390case glslang::EOpDPdxCoarse : 9391if (typeProxy == glslang::EbtFloat16 ) 9392builder .addExtension (spv::E_SPV_AMD_gpu_shader_half_float ); 9393unaryOp = spv::Op ::OpDPdxCoarse ; 9394break ; 9395case glslang::EOpDPdyCoarse : 9396if (typeProxy == glslang::EbtFloat16 ) 9397builder .addExtension (spv::E_SPV_AMD_gpu_shader_half_float ); 9398unaryOp = spv::Op ::OpDPdyCoarse ; 9399break ; 9400case glslang::EOpFwidthCoarse : 9401if (typeProxy == glslang::EbtFloat16 ) 9402builder .addExtension (spv::E_SPV_AMD_gpu_shader_half_float ); 9403unaryOp = spv::Op ::OpFwidthCoarse ; 9404break ; 9405case glslang::EOpRayQueryProceed : 9406unaryOp = spv::Op ::OpRayQueryProceedKHR ; 9407break ; 9408case glslang::EOpRayQueryGetRayTMin : 9409unaryOp = spv::Op ::OpRayQueryGetRayTMinKHR ; 9410break ; 9411case glslang::EOpRayQueryGetRayFlags : 9412unaryOp = spv::Op ::OpRayQueryGetRayFlagsKHR ; 9413break ; 9414case glslang::EOpRayQueryGetWorldRayOrigin : 9415unaryOp = spv::Op ::OpRayQueryGetWorldRayOriginKHR ; 9416break ; 9417case glslang::EOpRayQueryGetWorldRayDirection : 9418unaryOp = spv::Op ::OpRayQueryGetWorldRayDirectionKHR ; 9419break ; 9420case glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque : 9421unaryOp = spv::Op ::OpRayQueryGetIntersectionCandidateAABBOpaqueKHR ; 9422break ; 9423case glslang::EOpInterpolateAtCentroid : 9424if (typeProxy == glslang::EbtFloat16 ) 9425builder .addExtension (spv::E_SPV_AMD_gpu_shader_half_float ); 9426libCall = spv::GLSLstd450InterpolateAtCentroid ; 9427break ; 9428case glslang::EOpAtomicCounterIncrement : 9429case glslang::EOpAtomicCounterDecrement : 9430case glslang::EOpAtomicCounter : 9431 { 9432// Handle all of the atomics in one place, in createAtomicOperation() 9433 std::vector < spv::Id > operands ; 9434operands .push_back (operand ); 9435return createAtomicOperation (op ,decorations .precision ,typeId ,operands ,typeProxy ,lvalueCoherentFlags ,opType ); 9436 } 9437 9438case glslang::EOpBitFieldReverse : 9439unaryOp = spv::Op ::OpBitReverse ; 9440break ; 9441case glslang::EOpBitCount : 9442unaryOp = spv::Op ::OpBitCount ; 9443break ; 9444case glslang::EOpFindLSB : 9445libCall = spv::GLSLstd450FindILsb ; 9446break ; 9447case glslang::EOpFindMSB : 9448if (isUnsigned ) 9449libCall = spv::GLSLstd450FindUMsb ; 9450else 9451libCall = spv::GLSLstd450FindSMsb ; 9452break ; 9453 9454case glslang::EOpCountLeadingZeros : 9455builder .addCapability (spv::Capability ::IntegerFunctions2INTEL ); 9456builder .addExtension ("SPV_INTEL_shader_integer_functions2" ); 9457unaryOp = spv::Op ::OpUCountLeadingZerosINTEL ; 9458break ; 9459 9460case glslang::EOpCountTrailingZeros : 9461builder .addCapability (spv::Capability ::IntegerFunctions2INTEL ); 9462builder .addExtension ("SPV_INTEL_shader_integer_functions2" ); 9463unaryOp = spv::Op ::OpUCountTrailingZerosINTEL ; 9464break ; 9465 9466case glslang::EOpBallot : 9467case glslang::EOpReadFirstInvocation : 9468case glslang::EOpAnyInvocation : 9469case glslang::EOpAllInvocations : 9470case glslang::EOpAllInvocationsEqual : 9471case glslang::EOpMinInvocations : 9472case glslang::EOpMaxInvocations : 9473case glslang::EOpAddInvocations : 9474case glslang::EOpMinInvocationsNonUniform : 9475case glslang::EOpMaxInvocationsNonUniform : 9476case glslang::EOpAddInvocationsNonUniform : 9477case glslang::EOpMinInvocationsInclusiveScan : 9478case glslang::EOpMaxInvocationsInclusiveScan : 9479case glslang::EOpAddInvocationsInclusiveScan : 9480case glslang::EOpMinInvocationsInclusiveScanNonUniform : 9481case glslang::EOpMaxInvocationsInclusiveScanNonUniform : 9482case glslang::EOpAddInvocationsInclusiveScanNonUniform : 9483case glslang::EOpMinInvocationsExclusiveScan : 9484case glslang::EOpMaxInvocationsExclusiveScan : 9485case glslang::EOpAddInvocationsExclusiveScan : 9486case glslang::EOpMinInvocationsExclusiveScanNonUniform : 9487case glslang::EOpMaxInvocationsExclusiveScanNonUniform : 9488case glslang::EOpAddInvocationsExclusiveScanNonUniform : 9489 { 9490 std::vector < spv::Id > operands ; 9491operands .push_back (operand ); 9492return createInvocationsOperation (op ,typeId ,operands ,typeProxy ); 9493 } 9494case glslang::EOpSubgroupAll : 9495case glslang::EOpSubgroupAny : 9496case glslang::EOpSubgroupAllEqual : 9497case glslang::EOpSubgroupBroadcastFirst : 9498case glslang::EOpSubgroupBallot : 9499case glslang::EOpSubgroupInverseBallot : 9500case glslang::EOpSubgroupBallotBitCount : 9501case glslang::EOpSubgroupBallotInclusiveBitCount : 9502case glslang::EOpSubgroupBallotExclusiveBitCount : 9503case glslang::EOpSubgroupBallotFindLSB : 9504case glslang::EOpSubgroupBallotFindMSB : 9505case glslang::EOpSubgroupAdd : 9506case glslang::EOpSubgroupMul : 9507case glslang::EOpSubgroupMin : 9508case glslang::EOpSubgroupMax : 9509case glslang::EOpSubgroupAnd : 9510case glslang::EOpSubgroupOr : 9511case glslang::EOpSubgroupXor : 9512case glslang::EOpSubgroupInclusiveAdd : 9513case glslang::EOpSubgroupInclusiveMul : 9514case glslang::EOpSubgroupInclusiveMin : 9515case glslang::EOpSubgroupInclusiveMax : 9516case glslang::EOpSubgroupInclusiveAnd : 9517case glslang::EOpSubgroupInclusiveOr : 9518case glslang::EOpSubgroupInclusiveXor : 9519case glslang::EOpSubgroupExclusiveAdd : 9520case glslang::EOpSubgroupExclusiveMul : 9521case glslang::EOpSubgroupExclusiveMin : 9522case glslang::EOpSubgroupExclusiveMax : 9523case glslang::EOpSubgroupExclusiveAnd : 9524case glslang::EOpSubgroupExclusiveOr : 9525case glslang::EOpSubgroupExclusiveXor : 9526case glslang::EOpSubgroupQuadSwapHorizontal : 9527case glslang::EOpSubgroupQuadSwapVertical : 9528case glslang::EOpSubgroupQuadSwapDiagonal : 9529case glslang::EOpSubgroupQuadAll : 9530case glslang::EOpSubgroupQuadAny : { 9531 std::vector < spv::Id > operands ; 9532operands .push_back (operand ); 9533return createSubgroupOperation (op ,typeId ,operands ,typeProxy ); 9534 } 9535case glslang::EOpMbcnt : 9536extBuiltins = getExtBuiltins (spv::E_SPV_AMD_shader_ballot ); 9537libCall = spv::MbcntAMD ; 9538break ; 9539 9540case glslang::EOpCubeFaceIndex : 9541extBuiltins = getExtBuiltins (spv::E_SPV_AMD_gcn_shader ); 9542libCall = spv::CubeFaceIndexAMD ; 9543break ; 9544 9545case glslang::EOpCubeFaceCoord : 9546extBuiltins = getExtBuiltins (spv::E_SPV_AMD_gcn_shader ); 9547libCall = spv::CubeFaceCoordAMD ; 9548break ; 9549case glslang::EOpSubgroupPartition : 9550unaryOp = spv::Op ::OpGroupNonUniformPartitionNV ; 9551break ; 9552case glslang::EOpConstructReference : 9553unaryOp = spv::Op ::OpBitcast ; 9554break ; 9555 9556case glslang::EOpConvUint64ToAccStruct : 9557case glslang::EOpConvUvec2ToAccStruct : 9558unaryOp = spv::Op ::OpConvertUToAccelerationStructureKHR ; 9559break ; 9560 9561case glslang::EOpHitObjectIsEmptyNV : 9562unaryOp = spv::Op ::OpHitObjectIsEmptyNV ; 9563break ; 9564 9565case glslang::EOpHitObjectIsEmptyEXT : 9566unaryOp = spv::Op ::OpHitObjectIsEmptyEXT ; 9567break ; 9568 9569case glslang::EOpHitObjectIsMissNV : 9570unaryOp = spv::Op ::OpHitObjectIsMissNV ; 9571break ; 9572 9573case glslang::EOpHitObjectIsMissEXT : 9574unaryOp = spv::Op ::OpHitObjectIsMissEXT ; 9575break ; 9576 9577case glslang::EOpHitObjectIsHitNV : 9578unaryOp = spv::Op ::OpHitObjectIsHitNV ; 9579break ; 9580 9581case glslang::EOpHitObjectIsHitEXT : 9582unaryOp = spv::Op ::OpHitObjectIsHitEXT ; 9583break ; 9584 9585case glslang::EOpHitObjectGetObjectRayOriginNV : 9586unaryOp = spv::Op ::OpHitObjectGetObjectRayOriginNV ; 9587break ; 9588 9589case glslang::EOpHitObjectGetObjectRayOriginEXT : 9590unaryOp = spv::Op ::OpHitObjectGetObjectRayOriginEXT ; 9591break ; 9592 9593case glslang::EOpHitObjectGetObjectRayDirectionNV : 9594unaryOp = spv::Op ::OpHitObjectGetObjectRayDirectionNV ; 9595break ; 9596 9597case glslang::EOpHitObjectGetObjectRayDirectionEXT : 9598unaryOp = spv::Op ::OpHitObjectGetObjectRayDirectionEXT ; 9599break ; 9600 9601case glslang::EOpHitObjectGetWorldRayOriginNV : 9602unaryOp = spv::Op ::OpHitObjectGetWorldRayOriginNV ; 9603break ; 9604 9605case glslang::EOpHitObjectGetWorldRayOriginEXT : 9606unaryOp = spv::Op ::OpHitObjectGetWorldRayOriginEXT ; 9607break ; 9608 9609case glslang::EOpHitObjectGetWorldRayDirectionNV : 9610unaryOp = spv::Op ::OpHitObjectGetWorldRayDirectionNV ; 9611break ; 9612 9613case glslang::EOpHitObjectGetWorldRayDirectionEXT : 9614unaryOp = spv::Op ::OpHitObjectGetWorldRayDirectionEXT ; 9615break ; 9616 9617case glslang::EOpHitObjectGetObjectToWorldNV : 9618unaryOp = spv::Op ::OpHitObjectGetObjectToWorldNV ; 9619break ; 9620 9621case glslang::EOpHitObjectGetObjectToWorldEXT : 9622unaryOp = spv::Op ::OpHitObjectGetObjectToWorldEXT ; 9623break ; 9624 9625case glslang::EOpHitObjectGetWorldToObjectNV : 9626unaryOp = spv::Op ::OpHitObjectGetWorldToObjectNV ; 9627break ; 9628 9629case glslang::EOpHitObjectGetWorldToObjectEXT : 9630unaryOp = spv::Op ::OpHitObjectGetWorldToObjectEXT ; 9631break ; 9632 9633case glslang::EOpHitObjectGetRayTMinNV : 9634unaryOp = spv::Op ::OpHitObjectGetRayTMinNV ; 9635break ; 9636 9637case glslang::EOpHitObjectGetRayTMinEXT : 9638unaryOp = spv::Op ::OpHitObjectGetRayTMinEXT ; 9639break ; 9640 9641case glslang::EOpHitObjectGetRayTMaxNV : 9642unaryOp = spv::Op ::OpHitObjectGetRayTMaxNV ; 9643break ; 9644 9645case glslang::EOpHitObjectGetRayTMaxEXT : 9646unaryOp = spv::Op ::OpHitObjectGetRayTMaxEXT ; 9647break ; 9648 9649case glslang::EOpHitObjectGetRayFlagsEXT : 9650unaryOp = spv::Op ::OpHitObjectGetRayFlagsEXT ; 9651break ; 9652 9653case glslang::EOpHitObjectGetPrimitiveIndexNV : 9654unaryOp = spv::Op ::OpHitObjectGetPrimitiveIndexNV ; 9655break ; 9656 9657case glslang::EOpHitObjectGetPrimitiveIndexEXT : 9658unaryOp = spv::Op ::OpHitObjectGetPrimitiveIndexEXT ; 9659break ; 9660 9661case glslang::EOpHitObjectGetInstanceIdNV : 9662unaryOp = spv::Op ::OpHitObjectGetInstanceIdNV ; 9663break ; 9664 9665case glslang::EOpHitObjectGetInstanceIdEXT : 9666unaryOp = spv::Op ::OpHitObjectGetInstanceIdEXT ; 9667break ; 9668 9669case glslang::EOpHitObjectGetInstanceCustomIndexNV : 9670unaryOp = spv::Op ::OpHitObjectGetInstanceCustomIndexNV ; 9671break ; 9672 9673case glslang::EOpHitObjectGetInstanceCustomIndexEXT : 9674unaryOp = spv::Op ::OpHitObjectGetInstanceCustomIndexEXT ; 9675break ; 9676 9677case glslang::EOpHitObjectGetGeometryIndexNV : 9678unaryOp = spv::Op ::OpHitObjectGetGeometryIndexNV ; 9679break ; 9680 9681case glslang::EOpHitObjectGetGeometryIndexEXT : 9682unaryOp = spv::Op ::OpHitObjectGetGeometryIndexEXT ; 9683break ; 9684 9685case glslang::EOpHitObjectGetHitKindNV : 9686unaryOp = spv::Op ::OpHitObjectGetHitKindNV ; 9687break ; 9688 9689case glslang::EOpHitObjectGetHitKindEXT : 9690unaryOp = spv::Op ::OpHitObjectGetHitKindEXT ; 9691break ; 9692 9693case glslang::EOpHitObjectGetCurrentTimeNV : 9694unaryOp = spv::Op ::OpHitObjectGetCurrentTimeNV ; 9695break ; 9696 9697case glslang::EOpHitObjectGetCurrentTimeEXT : 9698unaryOp = spv::Op ::OpHitObjectGetCurrentTimeEXT ; 9699break ; 9700 9701case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV : 9702unaryOp = spv::Op ::OpHitObjectGetShaderBindingTableRecordIndexNV ; 9703break ; 9704 9705case glslang::EOpHitObjectGetShaderBindingTableRecordIndexEXT : 9706unaryOp = spv::Op ::OpHitObjectGetShaderBindingTableRecordIndexEXT ; 9707break ; 9708 9709case glslang::EOpHitObjectGetShaderRecordBufferHandleNV : 9710unaryOp = spv::Op ::OpHitObjectGetShaderRecordBufferHandleNV ; 9711break ; 9712 9713case glslang::EOpHitObjectGetClusterIdNV : 9714unaryOp = spv::Op ::OpHitObjectGetClusterIdNV ; 9715builder .addExtension (spv::E_SPV_NV_cluster_acceleration_structure ); 9716builder .addCapability (spv::Capability ::ShaderInvocationReorderNV ); 9717builder .addCapability (spv::Capability ::RayTracingClusterAccelerationStructureNV ); 9718break ; 9719 9720case glslang::EOpHitObjectGetSpherePositionNV : 9721unaryOp = spv::Op ::OpHitObjectGetSpherePositionNV ; 9722builder .addExtension (spv::E_SPV_NV_linear_swept_spheres ); 9723builder .addCapability (spv::Capability ::ShaderInvocationReorderNV ); 9724builder .addCapability (spv::Capability ::RayTracingSpheresGeometryNV ); 9725break ; 9726 9727case glslang::EOpHitObjectGetSphereRadiusNV : 9728unaryOp = spv::Op ::OpHitObjectGetSphereRadiusNV ; 9729builder .addExtension (spv::E_SPV_NV_linear_swept_spheres ); 9730builder .addCapability (spv::Capability ::ShaderInvocationReorderNV ); 9731builder .addCapability (spv::Capability ::RayTracingSpheresGeometryNV ); 9732break ; 9733 9734case glslang::EOpHitObjectIsSphereHitNV : 9735unaryOp = spv::Op ::OpHitObjectIsSphereHitNV ; 9736builder .addExtension (spv::E_SPV_NV_linear_swept_spheres ); 9737builder .addCapability (spv::Capability ::ShaderInvocationReorderNV ); 9738builder .addCapability (spv::Capability ::RayTracingSpheresGeometryNV ); 9739break ; 9740 9741case glslang::EOpHitObjectIsLSSHitNV : 9742unaryOp = spv::Op ::OpHitObjectIsLSSHitNV ; 9743builder .addExtension (spv::E_SPV_NV_linear_swept_spheres ); 9744builder .addCapability (spv::Capability ::ShaderInvocationReorderNV ); 9745builder .addCapability (spv::Capability ::RayTracingLinearSweptSpheresGeometryNV ); 9746break ; 9747 9748case glslang::EOpHitObjectGetShaderRecordBufferHandleEXT : 9749unaryOp = spv::Op ::OpHitObjectGetShaderRecordBufferHandleEXT ; 9750break ; 9751 9752case glslang::EOpFetchMicroTriangleVertexPositionNV : 9753unaryOp = spv::Op ::OpFetchMicroTriangleVertexPositionNV ; 9754break ; 9755 9756case glslang::EOpFetchMicroTriangleVertexBarycentricNV : 9757unaryOp = spv::Op ::OpFetchMicroTriangleVertexBarycentricNV ; 9758break ; 9759 9760case glslang::EOpCopyObject : 9761unaryOp = spv::Op ::OpCopyObject ; 9762break ; 9763 9764case glslang::EOpDepthAttachmentReadEXT : 9765builder .addExtension (spv::E_SPV_EXT_shader_tile_image ); 9766builder .addCapability (spv::Capability ::TileImageDepthReadAccessEXT ); 9767unaryOp = spv::Op ::OpDepthAttachmentReadEXT ; 9768decorations .precision = spv::NoPrecision ; 9769break ; 9770case glslang::EOpStencilAttachmentReadEXT : 9771builder .addExtension (spv::E_SPV_EXT_shader_tile_image ); 9772builder .addCapability (spv::Capability ::TileImageStencilReadAccessEXT ); 9773unaryOp = spv::Op ::OpStencilAttachmentReadEXT ; 9774decorations .precision = spv::Decoration ::RelaxedPrecision ; 9775break ; 9776 9777default : 9778return 0 ; 9779 } 9780 9781 spv::Id id ; 9782if (libCall >=0 ) { 9783 std::vector < spv::Id > args ; 9784args .push_back (operand ); 9785id = builder .createBuiltinCall (typeId ,extBuiltins >=0 ?extBuiltins :stdBuiltins ,libCall ,args ); 9786 }else { 9787id = builder .createUnaryOp (unaryOp ,typeId ,operand ); 9788 } 9789 9790decorations .addNoContraction (builder ,id ); 9791decorations .addNonUniform (builder ,id ); 9792return builder .setPrecision (id ,decorations .precision ); 9793} 9794 9795// Create a unary operation on a matrix 9796spv::Id TGlslangToSpvTraverser ::createUnaryMatrixOperation (spv::Op op ,OpDecorations & decorations , spv::Id typeId , 9797 spv::Id operand , glslang::TBasicType /* typeProxy */ ) 9798{ 9799// Handle unary operations vector by vector. 9800// The result type is the same type as the original type. 9801// The algorithm is to: 9802// - break the matrix into vectors 9803// - apply the operation to each vector 9804// - make a matrix out the vector results 9805 9806// get the types sorted out 9807int numCols = builder .getNumColumns (operand ); 9808int numRows = builder .getNumRows (operand ); 9809 spv::Id srcVecType = builder .makeVectorType (builder .getScalarTypeId (builder .getTypeId (operand )),numRows ); 9810 spv::Id destVecType = builder .makeVectorType (builder .getScalarTypeId (typeId ),numRows ); 9811 std::vector < spv::Id > results ; 9812 9813// do each vector op 9814for (int c = 0 ;c < numCols ;++ c ) { 9815 std::vector < unsigned int > indexes ; 9816indexes .push_back (c ); 9817 spv::Id srcVec = builder .createCompositeExtract (operand ,srcVecType ,indexes ); 9818 spv::Id destVec = builder .createUnaryOp (op ,destVecType ,srcVec ); 9819decorations .addNoContraction (builder ,destVec ); 9820decorations .addNonUniform (builder ,destVec ); 9821results .push_back (builder .setPrecision (destVec ,decorations .precision )); 9822 } 9823 9824// put the pieces together 9825 spv::Id result = builder .setPrecision (builder .createCompositeConstruct (typeId ,results ),decorations .precision ); 9826decorations .addNonUniform (builder ,result ); 9827return result ; 9828} 9829 9830// For converting integers where both the bitwidth and the signedness could 9831// change, but only do the width change here. The caller is still responsible 9832// for the signedness conversion. 9833// destType is the final type that will be converted to, but this function 9834// may only be doing part of that conversion. 9835spv::Id TGlslangToSpvTraverser ::createIntWidthConversion (spv::Id operand ,int vectorSize , spv::Id destType , 9836 glslang::TBasicType resultBasicType , glslang::TBasicType operandBasicType ) 9837{ 9838// Get the result type width, based on the type to convert to. 9839int width = GetNumBits (resultBasicType ); 9840 9841// Get the conversion operation and result type, 9842// based on the target width, but the source type. 9843 spv::Id type = spv::NoType ; 9844 spv::Op convOp = spv::Op ::OpNop ; 9845if (isTypeSignedInt (operandBasicType )) { 9846convOp = spv::Op ::OpSConvert ; 9847type = builder .makeIntType (width ); 9848 }else { 9849convOp = spv::Op ::OpUConvert ; 9850type = builder .makeUintType (width ); 9851 } 9852 9853if (builder .getOpCode (destType )== spv::Op ::OpTypeCooperativeVectorNV ) { 9854type = builder .makeCooperativeVectorTypeNV (type ,builder .getCooperativeVectorNumComponents (destType )); 9855 }else if (vectorSize > 0 ) 9856type = builder .makeVectorType (type ,vectorSize ); 9857else if (builder .getOpCode (destType )== spv::Op ::OpTypeCooperativeMatrixKHR || 9858builder .getOpCode (destType )== spv::Op ::OpTypeCooperativeMatrixNV ) { 9859 9860type = builder .makeCooperativeMatrixTypeWithSameShape (type ,destType ); 9861 } 9862 9863if (convOp == spv::Op ::OpUConvert && specConstUConvertNeedsWorkaround ()) { 9864return createSpecConstUConvert (type ,operand ,vectorSize ,GetNumBits (operandBasicType ),width ); 9865 } 9866 9867return builder .createUnaryOp (convOp ,type ,operand ); 9868} 9869 9870// OpUConvert only became a valid specialization constant operation in SPIR-V 1.4. 9871bool TGlslangToSpvTraverser ::specConstUConvertNeedsWorkaround () 9872{ 9873return builder .isInSpecConstCodeGenMode ()&& 9874glslangIntermediate -> getSpv ().spv < glslang::EShTargetSpv_1_4 ; 9875} 9876 9877// OpSConvert is valid in every version, and only differs from OpUConvert when widening, 9878// where it brings in copies of the sign bit that have to be masked off. 9879spv::Id TGlslangToSpvTraverser ::createSpecConstUConvert (spv::Id typeId , spv::Id operand ,int vectorSize , 9880int operandWidth ,int resultWidth ) 9881{ 9882 spv::Id result = builder .createUnaryOp (spv::Op ::OpSConvert ,typeId ,operand ); 9883if (resultWidth <=operandWidth ) 9884return result ; 9885 9886const spv::Id maskType = builder .makeUintType (resultWidth ); 9887const unsigned long long maskValue = (1ull <<operandWidth )- 1 ; 9888 spv::Id mask = resultWidth == 64 ?builder .makeInt64Constant (maskType ,maskValue , false) 9889 :builder .makeIntConstant (maskType ,static_cast < unsigned > (maskValue ), false); 9890mask = makeSmearedConstant (mask ,vectorSize ); 9891return builder .createBinOp (spv::Op ::OpBitwiseAnd ,typeId ,result ,mask ); 9892} 9893 9894spv::Id TGlslangToSpvTraverser ::createConversion (glslang::TOperator op ,OpDecorations & decorations , spv::Id destType , 9895 spv::Id operand , glslang::TBasicType resultBasicType , glslang::TBasicType operandBasicType , 9896bool sameCoopMatUse ) 9897{ 9898 spv::Op convOp = spv::Op ::OpNop ; 9899 spv::Id zero = 0 ; 9900 spv::Id one = 0 ; 9901 9902int vectorSize = builder .isVectorType (destType ) ?builder .getNumTypeComponents (destType ) :0 ; 9903 9904if (IsOpNumericConv (op )|| op == glslang::EOpConstructSaturated ) { 9905if (builder .isCooperativeMatrixType (destType )) { 9906if (!sameCoopMatUse ) { 9907enableCoopMatConversions (); 9908 } 9909auto result = createCoopMatConversion (destType ,operand ,resultBasicType ,operandBasicType ,sameCoopMatUse , false); 9910return result ; 9911 } 9912 9913if (isTypeSignedInt (operandBasicType )&& isTypeFloat (resultBasicType )) { 9914convOp = spv::Op ::OpConvertSToF ; 9915 } 9916if (isTypeUnsignedInt (operandBasicType )&& isTypeFloat (resultBasicType )) { 9917convOp = spv::Op ::OpConvertUToF ; 9918 } 9919if (isTypeFloat (operandBasicType )&& isTypeSignedInt (resultBasicType )) { 9920convOp = spv::Op ::OpConvertFToS ; 9921 } 9922if (isTypeFloat (operandBasicType )&& isTypeUnsignedInt (resultBasicType )) { 9923convOp = spv::Op ::OpConvertFToU ; 9924 } 9925if (isTypeSignedInt (operandBasicType )&& isTypeSignedInt (resultBasicType )) { 9926convOp = spv::Op ::OpSConvert ; 9927 } 9928if (isTypeUnsignedInt (operandBasicType )&& isTypeUnsignedInt (resultBasicType )) { 9929convOp = spv::Op ::OpUConvert ; 9930 } 9931if (isTypeFloat (operandBasicType )&& isTypeFloat (resultBasicType )) { 9932convOp = spv::Op ::OpFConvert ; 9933if (builder .isMatrixType (destType )) 9934return createUnaryMatrixOperation (convOp ,decorations ,destType ,operand ,operandBasicType ); 9935 } 9936if (isTypeInt (operandBasicType )&& isTypeInt (resultBasicType )&& 9937isTypeUnsignedInt (operandBasicType )!= isTypeUnsignedInt (resultBasicType )) { 9938 9939if (GetNumBits (operandBasicType )!= GetNumBits (resultBasicType )) { 9940// OpSConvert/OpUConvert + OpBitCast 9941operand = createIntWidthConversion (operand ,vectorSize ,destType ,resultBasicType ,operandBasicType ); 9942 } 9943 9944if (builder .isInSpecConstCodeGenMode ()) { 9945uint32_t bits = GetNumBits (resultBasicType ); 9946 spv::Id zeroType = builder .makeUintType (bits ); 9947if (bits == 64 ) { 9948zero = builder .makeInt64Constant (zeroType ,0 , false); 9949 }else { 9950zero = builder .makeIntConstant (zeroType ,0 , false); 9951 } 9952zero = makeSmearedConstant (zero ,vectorSize ); 9953// Use OpIAdd, instead of OpBitcast to do the conversion when 9954// generating for OpSpecConstantOp instruction. 9955return builder .createBinOp (spv::Op ::OpIAdd ,destType ,operand ,zero ); 9956 } 9957// For normal run-time conversion instruction, use OpBitcast. 9958convOp = spv::Op ::OpBitcast ; 9959 } 9960if (resultBasicType == glslang::EbtBool ) { 9961uint32_t bits = GetNumBits (operandBasicType ); 9962if (isTypeInt (operandBasicType )) { 9963 spv::Id zeroType = builder .makeUintType (bits ); 9964if (bits == 64 ) { 9965zero = builder .makeInt64Constant (zeroType ,0 , false); 9966 }else { 9967zero = builder .makeIntConstant (zeroType ,0 , false); 9968 } 9969zero = makeSmearedConstant (zero ,vectorSize ); 9970return builder .createBinOp (spv::Op ::OpINotEqual ,destType ,operand ,zero ); 9971 }else { 9972assert (isTypeFloat (operandBasicType )); 9973if (bits == 64 ) { 9974zero = builder .makeDoubleConstant (0.0 ); 9975 }else if (bits == 32 ) { 9976zero = builder .makeFloatConstant (0.0 ); 9977 }else { 9978assert (bits == 16 ); 9979zero = builder .makeFloat16Constant (0.0 ); 9980 } 9981zero = makeSmearedConstant (zero ,vectorSize ); 9982return builder .createBinOp (spv::Op ::OpFUnordNotEqual ,destType ,operand ,zero ); 9983 } 9984 } 9985if (operandBasicType == glslang::EbtBool ) { 9986uint32_t bits = GetNumBits (resultBasicType ); 9987convOp = spv::Op ::OpSelect ; 9988if (isTypeInt (resultBasicType )) { 9989 spv::Id zeroType = isTypeSignedInt (resultBasicType ) ?builder .makeIntType (bits ) :builder .makeUintType (bits ); 9990if (bits == 64 ) { 9991zero = builder .makeInt64Constant (zeroType ,0 , false); 9992one = builder .makeInt64Constant (zeroType ,1 , false); 9993 }else { 9994zero = builder .makeIntConstant (zeroType ,0 , false); 9995one = builder .makeIntConstant (zeroType ,1 , false); 9996 } 9997 }else { 9998assert (isTypeFloat (resultBasicType )); 9999if (bits == 64 ) { 10000zero = builder .makeDoubleConstant (0.0 ); 10001one = builder .makeDoubleConstant (1.0 ); 10002 }else if (bits == 32 ) { 10003zero = builder .makeFloatConstant (0.0 ); 10004one = builder .makeFloatConstant (1.0 ); 10005 }else { 10006assert (bits == 16 ); 10007zero = builder .makeFloat16Constant (0.0 ); 10008one = builder .makeFloat16Constant (1.0 ); 10009 } 10010 } 10011 } 10012 } 10013 10014if (convOp == spv::Op ::OpNop ) { 10015switch (op ) { 10016case glslang::EOpConvUint64ToPtr : 10017convOp = spv::Op ::OpConvertUToPtr ; 10018break ; 10019case glslang::EOpConvPtrToUint64 : 10020convOp = spv::Op ::OpConvertPtrToU ; 10021break ; 10022case glslang::EOpConvPtrToUvec2 : 10023case glslang::EOpConvUvec2ToPtr : 10024convOp = spv::Op ::OpBitcast ; 10025break ; 10026 10027default : 10028break ; 10029 } 10030 } 10031 10032 spv::Id result = 0 ; 10033if (convOp == spv::Op ::OpNop ) 10034return result ; 10035 10036if (convOp == spv::Op ::OpSelect ) { 10037zero = makeSmearedConstant (zero ,vectorSize ); 10038one = makeSmearedConstant (one ,vectorSize ); 10039result = builder .createTriOp (convOp ,destType ,operand ,one ,zero ); 10040 }else if (convOp == spv::Op ::OpUConvert && specConstUConvertNeedsWorkaround ()) { 10041result = createSpecConstUConvert (destType ,operand ,vectorSize ,GetNumBits (operandBasicType ), 10042GetNumBits (resultBasicType )); 10043 }else 10044result = builder .createUnaryOp (convOp ,destType ,operand ); 10045 10046result = builder .setPrecision (result ,decorations .precision ); 10047decorations .addNonUniform (builder ,result ); 10048return result ; 10049} 10050 10051spv::Id TGlslangToSpvTraverser ::makeSmearedConstant (spv::Id constant ,int vectorSize ) 10052{ 10053if (vectorSize == 0 ) 10054return constant ; 10055 10056 spv::Id vectorTypeId = builder .makeVectorType (builder .getTypeId (constant ),vectorSize ); 10057 std::vector < spv::Id > components ; 10058for (int c = 0 ;c < vectorSize ;++ c ) 10059components .push_back (constant ); 10060return builder .makeCompositeConstant (vectorTypeId ,components ); 10061} 10062 10063// For glslang ops that map to SPV atomic opCodes 10064spv::Id TGlslangToSpvTraverser ::createAtomicOperation (glslang::TOperator op , spv::Decoration /*precision*/ , 10065 spv::Id typeId , std::vector < spv::Id >& operands , glslang::TBasicType typeProxy , 10066const spv::Builder ::AccessChain ::CoherentFlags & lvalueCoherentFlags ,const glslang::TType & opType ) 10067{ 10068 spv::Op opCode = spv::Op ::OpNop ; 10069 10070switch (op ) { 10071case glslang::EOpAtomicAdd : 10072case glslang::EOpImageAtomicAdd : 10073case glslang::EOpAtomicCounterAdd : 10074opCode = spv::Op ::OpAtomicIAdd ; 10075if (typeProxy == glslang::EbtFloat16 || typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble ) { 10076opCode = spv::Op ::OpAtomicFAddEXT ; 10077if (typeProxy == glslang::EbtFloat16 && 10078 (opType .getVectorSize ()== 2 || opType .getVectorSize ()== 4 )) { 10079builder .addExtension (spv::E_SPV_NV_shader_atomic_fp16_vector ); 10080builder .addCapability (spv::Capability ::AtomicFloat16VectorNV ); 10081 }else { 10082builder .addExtension (spv::E_SPV_EXT_shader_atomic_float_add ); 10083if (typeProxy == glslang::EbtFloat16 ) { 10084builder .addExtension (spv::E_SPV_EXT_shader_atomic_float16_add ); 10085builder .addCapability (spv::Capability ::AtomicFloat16AddEXT ); 10086 }else if (typeProxy == glslang::EbtFloat ) { 10087builder .addCapability (spv::Capability ::AtomicFloat32AddEXT ); 10088 }else { 10089builder .addCapability (spv::Capability ::AtomicFloat64AddEXT ); 10090 } 10091 } 10092 } 10093break ; 10094case glslang::EOpAtomicSubtract : 10095case glslang::EOpAtomicCounterSubtract : 10096opCode = spv::Op ::OpAtomicISub ; 10097break ; 10098case glslang::EOpAtomicMin : 10099case glslang::EOpImageAtomicMin : 10100case glslang::EOpAtomicCounterMin : 10101if (typeProxy == glslang::EbtFloat16 || typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble ) { 10102opCode = spv::Op ::OpAtomicFMinEXT ; 10103if (typeProxy == glslang::EbtFloat16 && 10104 (opType .getVectorSize ()== 2 || opType .getVectorSize ()== 4 )) { 10105builder .addExtension (spv::E_SPV_NV_shader_atomic_fp16_vector ); 10106builder .addCapability (spv::Capability ::AtomicFloat16VectorNV ); 10107 }else { 10108builder .addExtension (spv::E_SPV_EXT_shader_atomic_float_min_max ); 10109if (typeProxy == glslang::EbtFloat16 ) 10110builder .addCapability (spv::Capability ::AtomicFloat16MinMaxEXT ); 10111else if (typeProxy == glslang::EbtFloat ) 10112builder .addCapability (spv::Capability ::AtomicFloat32MinMaxEXT ); 10113else 10114builder .addCapability (spv::Capability ::AtomicFloat64MinMaxEXT ); 10115 } 10116 }else if (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64 ) { 10117opCode = spv::Op ::OpAtomicUMin ; 10118 }else { 10119opCode = spv::Op ::OpAtomicSMin ; 10120 } 10121break ; 10122case glslang::EOpAtomicMax : 10123case glslang::EOpImageAtomicMax : 10124case glslang::EOpAtomicCounterMax : 10125if (typeProxy == glslang::EbtFloat16 || typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble ) { 10126opCode = spv::Op ::OpAtomicFMaxEXT ; 10127if (typeProxy == glslang::EbtFloat16 && 10128 (opType .getVectorSize ()== 2 || opType .getVectorSize ()== 4 )) { 10129builder .addExtension (spv::E_SPV_NV_shader_atomic_fp16_vector ); 10130builder .addCapability (spv::Capability ::AtomicFloat16VectorNV ); 10131 }else { 10132builder .addExtension (spv::E_SPV_EXT_shader_atomic_float_min_max ); 10133if (typeProxy == glslang::EbtFloat16 ) 10134builder .addCapability (spv::Capability ::AtomicFloat16MinMaxEXT ); 10135else if (typeProxy == glslang::EbtFloat ) 10136builder .addCapability (spv::Capability ::AtomicFloat32MinMaxEXT ); 10137else 10138builder .addCapability (spv::Capability ::AtomicFloat64MinMaxEXT ); 10139 } 10140 }else if (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64 ) { 10141opCode = spv::Op ::OpAtomicUMax ; 10142 }else { 10143opCode = spv::Op ::OpAtomicSMax ; 10144 } 10145break ; 10146case glslang::EOpAtomicAnd : 10147case glslang::EOpImageAtomicAnd : 10148case glslang::EOpAtomicCounterAnd : 10149opCode = spv::Op ::OpAtomicAnd ; 10150break ; 10151case glslang::EOpAtomicOr : 10152case glslang::EOpImageAtomicOr : 10153case glslang::EOpAtomicCounterOr : 10154opCode = spv::Op ::OpAtomicOr ; 10155break ; 10156case glslang::EOpAtomicXor : 10157case glslang::EOpImageAtomicXor : 10158case glslang::EOpAtomicCounterXor : 10159opCode = spv::Op ::OpAtomicXor ; 10160break ; 10161case glslang::EOpAtomicExchange : 10162case glslang::EOpImageAtomicExchange : 10163case glslang::EOpAtomicCounterExchange : 10164if ((typeProxy == glslang::EbtFloat16 )&& 10165 (opType .getVectorSize ()== 2 || opType .getVectorSize ()== 4 )) { 10166builder .addExtension (spv::E_SPV_NV_shader_atomic_fp16_vector ); 10167builder .addCapability (spv::Capability ::AtomicFloat16VectorNV ); 10168 } 10169 10170opCode = spv::Op ::OpAtomicExchange ; 10171break ; 10172case glslang::EOpAtomicCompSwap : 10173case glslang::EOpImageAtomicCompSwap : 10174case glslang::EOpAtomicCounterCompSwap : 10175opCode = spv::Op ::OpAtomicCompareExchange ; 10176break ; 10177case glslang::EOpAtomicCounterIncrement : 10178opCode = spv::Op ::OpAtomicIIncrement ; 10179break ; 10180case glslang::EOpAtomicCounterDecrement : 10181opCode = spv::Op ::OpAtomicIDecrement ; 10182break ; 10183case glslang::EOpAtomicCounter : 10184case glslang::EOpImageAtomicLoad : 10185case glslang::EOpAtomicLoad : 10186opCode = spv::Op ::OpAtomicLoad ; 10187break ; 10188case glslang::EOpAtomicStore : 10189case glslang::EOpImageAtomicStore : 10190opCode = spv::Op ::OpAtomicStore ; 10191break ; 10192default : 10193assert (0 ); 10194break ; 10195 } 10196 10197if (typeProxy == glslang::EbtInt64 || typeProxy == glslang::EbtUint64 ) 10198builder .addCapability (spv::Capability ::Int64Atomics ); 10199 10200// Sort out the operands 10201// - mapping from glslang -> SPV 10202// - there are extra SPV operands that are optional in glslang 10203// - compare-exchange swaps the value and comparator 10204// - compare-exchange has an extra memory semantics 10205// - EOpAtomicCounterDecrement needs a post decrement 10206 spv::Id pointerId = 0 ,compareId = 0 ,valueId = 0 ; 10207// scope defaults to Device in the old model, QueueFamilyKHR in the new model 10208 spv::Id scopeId ; 10209if (glslangIntermediate -> usingVulkanMemoryModel ()) { 10210scopeId = builder .makeUintConstant (spv::Scope ::QueueFamilyKHR ); 10211 }else { 10212scopeId = builder .makeUintConstant (spv::Scope ::Device ); 10213 } 10214// semantics default to relaxed 10215 spv::Id semanticsId = builder .makeUintConstant (lvalueCoherentFlags .isVolatile ()&& 10216glslangIntermediate -> usingVulkanMemoryModel () ? 10217 spv::MemorySemanticsMask ::Volatile : 10218 spv::MemorySemanticsMask ::MaskNone ); 10219 spv::Id semanticsId2 = semanticsId ; 10220 10221pointerId = operands [0 ]; 10222if (opCode == spv::Op ::OpAtomicIIncrement || opCode == spv::Op ::OpAtomicIDecrement ) { 10223// no additional operands 10224 }else if (opCode == spv::Op ::OpAtomicCompareExchange ) { 10225compareId = operands [1 ]; 10226valueId = operands [2 ]; 10227if (operands .size ()> 3 ) { 10228scopeId = operands [3 ]; 10229semanticsId = builder .makeUintConstant ( 10230builder .getConstantScalar (operands [4 ]) |builder .getConstantScalar (operands [5 ])); 10231semanticsId2 = builder .makeUintConstant ( 10232builder .getConstantScalar (operands [6 ]) |builder .getConstantScalar (operands [7 ])); 10233 } 10234 }else if (opCode == spv::Op ::OpAtomicLoad ) { 10235if (operands .size ()> 1 ) { 10236scopeId = operands [1 ]; 10237semanticsId = builder .makeUintConstant ( 10238builder .getConstantScalar (operands [2 ]) |builder .getConstantScalar (operands [3 ])); 10239 } 10240 }else { 10241// atomic store or RMW 10242valueId = operands [1 ]; 10243if (operands .size ()> 2 ) { 10244scopeId = operands [2 ]; 10245semanticsId = builder .makeUintConstant 10246 (builder .getConstantScalar (operands [3 ]) |builder .getConstantScalar (operands [4 ])); 10247 } 10248 } 10249 10250// Check for capabilities 10251auto const semanticsImmediate = (spv::MemorySemanticsMask )(builder .getConstantScalar (semanticsId ) |builder .getConstantScalar (semanticsId2 )); 10252if (anySet (semanticsImmediate , spv::MemorySemanticsMask ::MakeAvailableKHR | 10253 spv::MemorySemanticsMask ::MakeVisibleKHR | 10254 spv::MemorySemanticsMask ::OutputMemoryKHR | 10255 spv::MemorySemanticsMask ::Volatile )) { 10256builder .addCapability (spv::Capability ::VulkanMemoryModelKHR ); 10257 } 10258 10259auto const scope = (spv::Scope )builder .getConstantScalar (scopeId ); 10260if (scope == spv::Scope ::QueueFamily ) { 10261builder .addCapability (spv::Capability ::VulkanMemoryModelKHR ); 10262 } 10263 10264if (glslangIntermediate -> usingVulkanMemoryModel ()&& scope == spv::Scope ::Device ) { 10265builder .addCapability (spv::Capability ::VulkanMemoryModelDeviceScopeKHR ); 10266 } 10267 10268 std::vector < spv::Id > spvAtomicOperands ;// hold the spv operands 10269spvAtomicOperands .reserve (6 ); 10270spvAtomicOperands .push_back (pointerId ); 10271spvAtomicOperands .push_back (scopeId ); 10272spvAtomicOperands .push_back (semanticsId ); 10273if (opCode == spv::Op ::OpAtomicCompareExchange ) { 10274spvAtomicOperands .push_back (semanticsId2 ); 10275spvAtomicOperands .push_back (valueId ); 10276spvAtomicOperands .push_back (compareId ); 10277 }else if (opCode != spv::Op ::OpAtomicLoad && opCode != spv::Op ::OpAtomicIIncrement && opCode != spv::Op ::OpAtomicIDecrement ) { 10278spvAtomicOperands .push_back (valueId ); 10279 } 10280 10281if (opCode == spv::Op ::OpAtomicStore ) { 10282builder .createNoResultOp (opCode ,spvAtomicOperands ); 10283return 0 ; 10284 }else { 10285 spv::Id resultId = builder .createOp (opCode ,typeId ,spvAtomicOperands ); 10286 10287// GLSL and HLSL atomic-counter decrement return post-decrement value, 10288// while SPIR-V returns pre-decrement value. Translate between these semantics. 10289if (op == glslang::EOpAtomicCounterDecrement ) 10290resultId = builder .createBinOp (spv::Op ::OpISub ,typeId ,resultId ,builder .makeIntConstant (1 )); 10291 10292return resultId ; 10293 } 10294} 10295 10296// Create group invocation operations. 10297spv::Id TGlslangToSpvTraverser ::createInvocationsOperation (glslang::TOperator op , spv::Id typeId , 10298 std::vector < spv::Id >& operands , glslang::TBasicType typeProxy ) 10299{ 10300bool isUnsigned = isTypeUnsignedInt (typeProxy ); 10301bool isFloat = isTypeFloat (typeProxy ); 10302 10303 spv::Op opCode = spv::Op ::OpNop ; 10304 std::vector < spv::IdImmediate > spvGroupOperands ; 10305 spv::GroupOperation groupOperation = spv::GroupOperation ::Max ; 10306 10307if (op == glslang::EOpBallot || op == glslang::EOpReadFirstInvocation || 10308op == glslang::EOpReadInvocation ) { 10309builder .addExtension (spv::E_SPV_KHR_shader_ballot ); 10310builder .addCapability (spv::Capability ::SubgroupBallotKHR ); 10311 }else if (op == glslang::EOpAnyInvocation || 10312op == glslang::EOpAllInvocations || 10313op == glslang::EOpAllInvocationsEqual ) { 10314builder .addExtension (spv::E_SPV_KHR_subgroup_vote ); 10315builder .addCapability (spv::Capability ::SubgroupVoteKHR ); 10316 }else { 10317builder .addCapability (spv::Capability ::Groups ); 10318if (op == glslang::EOpMinInvocationsNonUniform || 10319op == glslang::EOpMaxInvocationsNonUniform || 10320op == glslang::EOpAddInvocationsNonUniform || 10321op == glslang::EOpMinInvocationsInclusiveScanNonUniform || 10322op == glslang::EOpMaxInvocationsInclusiveScanNonUniform || 10323op == glslang::EOpAddInvocationsInclusiveScanNonUniform || 10324op == glslang::EOpMinInvocationsExclusiveScanNonUniform || 10325op == glslang::EOpMaxInvocationsExclusiveScanNonUniform || 10326op == glslang::EOpAddInvocationsExclusiveScanNonUniform ) 10327builder .addExtension (spv::E_SPV_AMD_shader_ballot ); 10328 10329switch (op ) { 10330case glslang::EOpMinInvocations : 10331case glslang::EOpMaxInvocations : 10332case glslang::EOpAddInvocations : 10333case glslang::EOpMinInvocationsNonUniform : 10334case glslang::EOpMaxInvocationsNonUniform : 10335case glslang::EOpAddInvocationsNonUniform : 10336groupOperation = spv::GroupOperation ::Reduce ; 10337break ; 10338case glslang::EOpMinInvocationsInclusiveScan : 10339case glslang::EOpMaxInvocationsInclusiveScan : 10340case glslang::EOpAddInvocationsInclusiveScan : 10341case glslang::EOpMinInvocationsInclusiveScanNonUniform : 10342case glslang::EOpMaxInvocationsInclusiveScanNonUniform : 10343case glslang::EOpAddInvocationsInclusiveScanNonUniform : 10344groupOperation = spv::GroupOperation ::InclusiveScan ; 10345break ; 10346case glslang::EOpMinInvocationsExclusiveScan : 10347case glslang::EOpMaxInvocationsExclusiveScan : 10348case glslang::EOpAddInvocationsExclusiveScan : 10349case glslang::EOpMinInvocationsExclusiveScanNonUniform : 10350case glslang::EOpMaxInvocationsExclusiveScanNonUniform : 10351case glslang::EOpAddInvocationsExclusiveScanNonUniform : 10352groupOperation = spv::GroupOperation ::ExclusiveScan ; 10353break ; 10354default : 10355break ; 10356 } 10357 spv::IdImmediate scope = { true,builder .makeUintConstant (spv::Scope ::Subgroup ) }; 10358spvGroupOperands .push_back (scope ); 10359if (groupOperation != spv::GroupOperation ::Max ) { 10360 spv::IdImmediate groupOp = { false, (unsigned )groupOperation }; 10361spvGroupOperands .push_back (groupOp ); 10362 } 10363 } 10364 10365for (auto opIt = operands .begin ();opIt != operands .end ();++ opIt ) { 10366 spv::IdImmediate op = { true,* opIt }; 10367spvGroupOperands .push_back (op ); 10368 } 10369 10370switch (op ) { 10371case glslang::EOpAnyInvocation : 10372opCode = spv::Op ::OpSubgroupAnyKHR ; 10373break ; 10374case glslang::EOpAllInvocations : 10375opCode = spv::Op ::OpSubgroupAllKHR ; 10376break ; 10377case glslang::EOpAllInvocationsEqual : 10378opCode = spv::Op ::OpSubgroupAllEqualKHR ; 10379break ; 10380case glslang::EOpReadInvocation : 10381opCode = spv::Op ::OpSubgroupReadInvocationKHR ; 10382if (builder .isVectorType (typeId )) 10383return CreateInvocationsVectorOperation (opCode ,groupOperation ,typeId ,operands ); 10384break ; 10385case glslang::EOpReadFirstInvocation : 10386opCode = spv::Op ::OpSubgroupFirstInvocationKHR ; 10387if (builder .isVectorType (typeId )) 10388return CreateInvocationsVectorOperation (opCode ,groupOperation ,typeId ,operands ); 10389break ; 10390case glslang::EOpBallot : 10391 { 10392// NOTE: According to the spec, the result type of "OpSubgroupBallotKHR" must be a 4 component vector of 32 10393// bit integer types. The GLSL built-in function "ballotARB()" assumes the maximum number of invocations in 10394// a subgroup is 64. Thus, we have to convert uvec4.xy to uint64_t as follow: 10395// 10396// result = Bitcast(SubgroupBallotKHR(Predicate).xy) 10397// 10398 spv::Id uintType = builder .makeUintType (32 ); 10399 spv::Id uvec4Type = builder .makeVectorType (uintType ,4 ); 10400 spv::Id result = builder .createOp (spv::Op ::OpSubgroupBallotKHR ,uvec4Type ,spvGroupOperands ); 10401 10402 std::vector < spv::Id > components ; 10403components .push_back (builder .createCompositeExtract (result ,uintType ,0 )); 10404components .push_back (builder .createCompositeExtract (result ,uintType ,1 )); 10405 10406 spv::Id uvec2Type = builder .makeVectorType (uintType ,2 ); 10407return builder .createUnaryOp (spv::Op ::OpBitcast ,typeId , 10408builder .createCompositeConstruct (uvec2Type ,components )); 10409 } 10410 10411case glslang::EOpMinInvocations : 10412case glslang::EOpMaxInvocations : 10413case glslang::EOpAddInvocations : 10414case glslang::EOpMinInvocationsInclusiveScan : 10415case glslang::EOpMaxInvocationsInclusiveScan : 10416case glslang::EOpAddInvocationsInclusiveScan : 10417case glslang::EOpMinInvocationsExclusiveScan : 10418case glslang::EOpMaxInvocationsExclusiveScan : 10419case glslang::EOpAddInvocationsExclusiveScan : 10420if (op == glslang::EOpMinInvocations || 10421op == glslang::EOpMinInvocationsInclusiveScan || 10422op == glslang::EOpMinInvocationsExclusiveScan ) { 10423if (isFloat ) 10424opCode = spv::Op ::OpGroupFMin ; 10425else { 10426if (isUnsigned ) 10427opCode = spv::Op ::OpGroupUMin ; 10428else 10429opCode = spv::Op ::OpGroupSMin ; 10430 } 10431 }else if (op == glslang::EOpMaxInvocations || 10432op == glslang::EOpMaxInvocationsInclusiveScan || 10433op == glslang::EOpMaxInvocationsExclusiveScan ) { 10434if (isFloat ) 10435opCode = spv::Op ::OpGroupFMax ; 10436else { 10437if (isUnsigned ) 10438opCode = spv::Op ::OpGroupUMax ; 10439else 10440opCode = spv::Op ::OpGroupSMax ; 10441 } 10442 }else { 10443if (isFloat ) 10444opCode = spv::Op ::OpGroupFAdd ; 10445else 10446opCode = spv::Op ::OpGroupIAdd ; 10447 } 10448 10449if (builder .isVectorType (typeId )) 10450return CreateInvocationsVectorOperation (opCode ,groupOperation ,typeId ,operands ); 10451 10452break ; 10453case glslang::EOpMinInvocationsNonUniform : 10454case glslang::EOpMaxInvocationsNonUniform : 10455case glslang::EOpAddInvocationsNonUniform : 10456case glslang::EOpMinInvocationsInclusiveScanNonUniform : 10457case glslang::EOpMaxInvocationsInclusiveScanNonUniform : 10458case glslang::EOpAddInvocationsInclusiveScanNonUniform : 10459case glslang::EOpMinInvocationsExclusiveScanNonUniform : 10460case glslang::EOpMaxInvocationsExclusiveScanNonUniform : 10461case glslang::EOpAddInvocationsExclusiveScanNonUniform : 10462if (op == glslang::EOpMinInvocationsNonUniform || 10463op == glslang::EOpMinInvocationsInclusiveScanNonUniform || 10464op == glslang::EOpMinInvocationsExclusiveScanNonUniform ) { 10465if (isFloat ) 10466opCode = spv::Op ::OpGroupFMinNonUniformAMD ; 10467else { 10468if (isUnsigned ) 10469opCode = spv::Op ::OpGroupUMinNonUniformAMD ; 10470else 10471opCode = spv::Op ::OpGroupSMinNonUniformAMD ; 10472 } 10473 } 10474else if (op == glslang::EOpMaxInvocationsNonUniform || 10475op == glslang::EOpMaxInvocationsInclusiveScanNonUniform || 10476op == glslang::EOpMaxInvocationsExclusiveScanNonUniform ) { 10477if (isFloat ) 10478opCode = spv::Op ::OpGroupFMaxNonUniformAMD ; 10479else { 10480if (isUnsigned ) 10481opCode = spv::Op ::OpGroupUMaxNonUniformAMD ; 10482else 10483opCode = spv::Op ::OpGroupSMaxNonUniformAMD ; 10484 } 10485 } 10486else { 10487if (isFloat ) 10488opCode = spv::Op ::OpGroupFAddNonUniformAMD ; 10489else 10490opCode = spv::Op ::OpGroupIAddNonUniformAMD ; 10491 } 10492 10493if (builder .isVectorType (typeId )) 10494return CreateInvocationsVectorOperation (opCode ,groupOperation ,typeId ,operands ); 10495 10496break ; 10497default : 10498logger -> missingFunctionality ("invocation operation" ); 10499return spv::NoResult ; 10500 } 10501 10502assert (opCode != spv::Op ::OpNop ); 10503return builder .createOp (opCode ,typeId ,spvGroupOperands ); 10504} 10505 10506// Create group invocation operations on a vector 10507spv::Id TGlslangToSpvTraverser ::CreateInvocationsVectorOperation (spv::Op op , spv::GroupOperation groupOperation , 10508 spv::Id typeId , std::vector < spv::Id >& operands ) 10509{ 10510assert (op == spv::Op ::OpGroupFMin || op == spv::Op ::OpGroupUMin || op == spv::Op ::OpGroupSMin || 10511op == spv::Op ::OpGroupFMax || op == spv::Op ::OpGroupUMax || op == spv::Op ::OpGroupSMax || 10512op == spv::Op ::OpGroupFAdd || op == spv::Op ::OpGroupIAdd || op == spv::Op ::OpGroupBroadcast || 10513op == spv::Op ::OpSubgroupReadInvocationKHR || op == spv::Op ::OpSubgroupFirstInvocationKHR || 10514op == spv::Op ::OpGroupFMinNonUniformAMD || op == spv::Op ::OpGroupUMinNonUniformAMD || 10515op == spv::Op ::OpGroupSMinNonUniformAMD || 10516op == spv::Op ::OpGroupFMaxNonUniformAMD || op == spv::Op ::OpGroupUMaxNonUniformAMD || 10517op == spv::Op ::OpGroupSMaxNonUniformAMD || 10518op == spv::Op ::OpGroupFAddNonUniformAMD || op == spv::Op ::OpGroupIAddNonUniformAMD ); 10519 10520// Handle group invocation operations scalar by scalar. 10521// The result type is the same type as the original type. 10522// The algorithm is to: 10523// - break the vector into scalars 10524// - apply the operation to each scalar 10525// - make a vector out the scalar results 10526 10527// get the types sorted out 10528int numComponents = builder .getNumComponents (operands [0 ]); 10529 spv::Id scalarType = builder .getScalarTypeId (builder .getTypeId (operands [0 ])); 10530 std::vector < spv::Id > results ; 10531 10532// do each scalar op 10533for (int comp = 0 ;comp < numComponents ;++ comp ) { 10534 std::vector < unsigned int > indexes ; 10535indexes .push_back (comp ); 10536 spv::IdImmediate scalar = { true,builder .createCompositeExtract (operands [0 ],scalarType ,indexes ) }; 10537 std::vector < spv::IdImmediate > spvGroupOperands ; 10538if (op == spv::Op ::OpSubgroupReadInvocationKHR ) { 10539spvGroupOperands .push_back (scalar ); 10540 spv::IdImmediate operand = { true,operands [1 ] }; 10541spvGroupOperands .push_back (operand ); 10542 }else if (op == spv::Op ::OpSubgroupFirstInvocationKHR ) { 10543spvGroupOperands .push_back (scalar ); 10544 }else if (op == spv::Op ::OpGroupBroadcast ) { 10545 spv::IdImmediate scope = { true,builder .makeUintConstant (spv::Scope ::Subgroup ) }; 10546spvGroupOperands .push_back (scope ); 10547spvGroupOperands .push_back (scalar ); 10548 spv::IdImmediate operand = { true,operands [1 ] }; 10549spvGroupOperands .push_back (operand ); 10550 }else { 10551 spv::IdImmediate scope = { true,builder .makeUintConstant (spv::Scope ::Subgroup ) }; 10552spvGroupOperands .push_back (scope ); 10553 spv::IdImmediate groupOp = { false, (unsigned )groupOperation }; 10554spvGroupOperands .push_back (groupOp ); 10555spvGroupOperands .push_back (scalar ); 10556 } 10557 10558results .push_back (builder .createOp (op ,scalarType ,spvGroupOperands )); 10559 } 10560 10561// put the pieces together 10562return builder .createCompositeConstruct (typeId ,results ); 10563} 10564 10565// Create subgroup invocation operations. 10566spv::Id TGlslangToSpvTraverser ::createSubgroupOperation (glslang::TOperator op , spv::Id typeId , 10567 std::vector < spv::Id >& operands , glslang::TBasicType typeProxy ) 10568{ 10569// Add the required capabilities. 10570switch (op ) { 10571case glslang::EOpSubgroupElect : 10572builder .addCapability (spv::Capability ::GroupNonUniform ); 10573break ; 10574case glslang::EOpSubgroupQuadAll : 10575case glslang::EOpSubgroupQuadAny : 10576builder .addExtension (spv::E_SPV_KHR_quad_control ); 10577builder .addCapability (spv::Capability ::QuadControlKHR ); 10578 [[fallthrough ]]; 10579case glslang::EOpSubgroupAll : 10580case glslang::EOpSubgroupAny : 10581case glslang::EOpSubgroupAllEqual : 10582builder .addCapability (spv::Capability ::GroupNonUniform ); 10583builder .addCapability (spv::Capability ::GroupNonUniformVote ); 10584break ; 10585case glslang::EOpSubgroupBroadcast : 10586case glslang::EOpSubgroupBroadcastFirst : 10587case glslang::EOpSubgroupBallot : 10588case glslang::EOpSubgroupInverseBallot : 10589case glslang::EOpSubgroupBallotBitExtract : 10590case glslang::EOpSubgroupBallotBitCount : 10591case glslang::EOpSubgroupBallotInclusiveBitCount : 10592case glslang::EOpSubgroupBallotExclusiveBitCount : 10593case glslang::EOpSubgroupBallotFindLSB : 10594case glslang::EOpSubgroupBallotFindMSB : 10595builder .addCapability (spv::Capability ::GroupNonUniform ); 10596builder .addCapability (spv::Capability ::GroupNonUniformBallot ); 10597break ; 10598case glslang::EOpSubgroupRotate : 10599case glslang::EOpSubgroupClusteredRotate : 10600builder .addExtension (spv::E_SPV_KHR_subgroup_rotate ); 10601builder .addCapability (spv::Capability ::GroupNonUniformRotateKHR ); 10602break ; 10603case glslang::EOpSubgroupShuffle : 10604case glslang::EOpSubgroupShuffleXor : 10605builder .addCapability (spv::Capability ::GroupNonUniform ); 10606builder .addCapability (spv::Capability ::GroupNonUniformShuffle ); 10607break ; 10608case glslang::EOpSubgroupShuffleUp : 10609case glslang::EOpSubgroupShuffleDown : 10610builder .addCapability (spv::Capability ::GroupNonUniform ); 10611builder .addCapability (spv::Capability ::GroupNonUniformShuffleRelative ); 10612break ; 10613case glslang::EOpSubgroupAdd : 10614case glslang::EOpSubgroupMul : 10615case glslang::EOpSubgroupMin : 10616case glslang::EOpSubgroupMax : 10617case glslang::EOpSubgroupAnd : 10618case glslang::EOpSubgroupOr : 10619case glslang::EOpSubgroupXor : 10620case glslang::EOpSubgroupInclusiveAdd : 10621case glslang::EOpSubgroupInclusiveMul : 10622case glslang::EOpSubgroupInclusiveMin : 10623case glslang::EOpSubgroupInclusiveMax : 10624case glslang::EOpSubgroupInclusiveAnd : 10625case glslang::EOpSubgroupInclusiveOr : 10626case glslang::EOpSubgroupInclusiveXor : 10627case glslang::EOpSubgroupExclusiveAdd : 10628case glslang::EOpSubgroupExclusiveMul : 10629case glslang::EOpSubgroupExclusiveMin : 10630case glslang::EOpSubgroupExclusiveMax : 10631case glslang::EOpSubgroupExclusiveAnd : 10632case glslang::EOpSubgroupExclusiveOr : 10633case glslang::EOpSubgroupExclusiveXor : 10634builder .addCapability (spv::Capability ::GroupNonUniform ); 10635builder .addCapability (spv::Capability ::GroupNonUniformArithmetic ); 10636break ; 10637case glslang::EOpSubgroupClusteredAdd : 10638case glslang::EOpSubgroupClusteredMul : 10639case glslang::EOpSubgroupClusteredMin : 10640case glslang::EOpSubgroupClusteredMax : 10641case glslang::EOpSubgroupClusteredAnd : 10642case glslang::EOpSubgroupClusteredOr : 10643case glslang::EOpSubgroupClusteredXor : 10644builder .addCapability (spv::Capability ::GroupNonUniform ); 10645builder .addCapability (spv::Capability ::GroupNonUniformClustered ); 10646break ; 10647case glslang::EOpSubgroupQuadBroadcast : 10648case glslang::EOpSubgroupQuadSwapHorizontal : 10649case glslang::EOpSubgroupQuadSwapVertical : 10650case glslang::EOpSubgroupQuadSwapDiagonal : 10651builder .addCapability (spv::Capability ::GroupNonUniform ); 10652builder .addCapability (spv::Capability ::GroupNonUniformQuad ); 10653break ; 10654case glslang::EOpSubgroupPartitionedAdd : 10655case glslang::EOpSubgroupPartitionedMul : 10656case glslang::EOpSubgroupPartitionedMin : 10657case glslang::EOpSubgroupPartitionedMax : 10658case glslang::EOpSubgroupPartitionedAnd : 10659case glslang::EOpSubgroupPartitionedOr : 10660case glslang::EOpSubgroupPartitionedXor : 10661case glslang::EOpSubgroupPartitionedInclusiveAdd : 10662case glslang::EOpSubgroupPartitionedInclusiveMul : 10663case glslang::EOpSubgroupPartitionedInclusiveMin : 10664case glslang::EOpSubgroupPartitionedInclusiveMax : 10665case glslang::EOpSubgroupPartitionedInclusiveAnd : 10666case glslang::EOpSubgroupPartitionedInclusiveOr : 10667case glslang::EOpSubgroupPartitionedInclusiveXor : 10668case glslang::EOpSubgroupPartitionedExclusiveAdd : 10669case glslang::EOpSubgroupPartitionedExclusiveMul : 10670case glslang::EOpSubgroupPartitionedExclusiveMin : 10671case glslang::EOpSubgroupPartitionedExclusiveMax : 10672case glslang::EOpSubgroupPartitionedExclusiveAnd : 10673case glslang::EOpSubgroupPartitionedExclusiveOr : 10674case glslang::EOpSubgroupPartitionedExclusiveXor : 10675builder .addExtension (spv::E_SPV_NV_shader_subgroup_partitioned ); 10676builder .addCapability (spv::Capability ::GroupNonUniformPartitionedNV ); 10677break ; 10678default :assert (0 && "Unhandled subgroup operation!" ); 10679 } 10680 10681 10682const bool isUnsigned = isTypeUnsignedInt (typeProxy ); 10683const bool isFloat = isTypeFloat (typeProxy ); 10684const bool isBool = typeProxy == glslang::EbtBool ; 10685 10686 spv::Op opCode = spv::Op ::OpNop ; 10687 10688// Figure out which opcode to use. 10689switch (op ) { 10690case glslang::EOpSubgroupElect :opCode = spv::Op ::OpGroupNonUniformElect ;break ; 10691case glslang::EOpSubgroupQuadAll :opCode = spv::Op ::OpGroupNonUniformQuadAllKHR ;break ; 10692case glslang::EOpSubgroupAll :opCode = spv::Op ::OpGroupNonUniformAll ;break ; 10693case glslang::EOpSubgroupQuadAny :opCode = spv::Op ::OpGroupNonUniformQuadAnyKHR ;break ; 10694case glslang::EOpSubgroupAny :opCode = spv::Op ::OpGroupNonUniformAny ;break ; 10695case glslang::EOpSubgroupAllEqual :opCode = spv::Op ::OpGroupNonUniformAllEqual ;break ; 10696case glslang::EOpSubgroupBroadcast :opCode = spv::Op ::OpGroupNonUniformBroadcast ;break ; 10697case glslang::EOpSubgroupBroadcastFirst :opCode = spv::Op ::OpGroupNonUniformBroadcastFirst ;break ; 10698case glslang::EOpSubgroupBallot :opCode = spv::Op ::OpGroupNonUniformBallot ;break ; 10699case glslang::EOpSubgroupInverseBallot :opCode = spv::Op ::OpGroupNonUniformInverseBallot ;break ; 10700case glslang::EOpSubgroupBallotBitExtract :opCode = spv::Op ::OpGroupNonUniformBallotBitExtract ;break ; 10701case glslang::EOpSubgroupBallotBitCount : 10702case glslang::EOpSubgroupBallotInclusiveBitCount : 10703case glslang::EOpSubgroupBallotExclusiveBitCount :opCode = spv::Op ::OpGroupNonUniformBallotBitCount ;break ; 10704case glslang::EOpSubgroupBallotFindLSB :opCode = spv::Op ::OpGroupNonUniformBallotFindLSB ;break ; 10705case glslang::EOpSubgroupBallotFindMSB :opCode = spv::Op ::OpGroupNonUniformBallotFindMSB ;break ; 10706case glslang::EOpSubgroupShuffle :opCode = spv::Op ::OpGroupNonUniformShuffle ;break ; 10707case glslang::EOpSubgroupShuffleXor :opCode = spv::Op ::OpGroupNonUniformShuffleXor ;break ; 10708case glslang::EOpSubgroupShuffleUp :opCode = spv::Op ::OpGroupNonUniformShuffleUp ;break ; 10709case glslang::EOpSubgroupShuffleDown :opCode = spv::Op ::OpGroupNonUniformShuffleDown ;break ; 10710case glslang::EOpSubgroupRotate : 10711case glslang::EOpSubgroupClusteredRotate :opCode = spv::Op ::OpGroupNonUniformRotateKHR ;break ; 10712case glslang::EOpSubgroupAdd : 10713case glslang::EOpSubgroupInclusiveAdd : 10714case glslang::EOpSubgroupExclusiveAdd : 10715case glslang::EOpSubgroupClusteredAdd : 10716case glslang::EOpSubgroupPartitionedAdd : 10717case glslang::EOpSubgroupPartitionedInclusiveAdd : 10718case glslang::EOpSubgroupPartitionedExclusiveAdd : 10719if (isFloat ) { 10720opCode = spv::Op ::OpGroupNonUniformFAdd ; 10721 }else { 10722opCode = spv::Op ::OpGroupNonUniformIAdd ; 10723 } 10724break ; 10725case glslang::EOpSubgroupMul : 10726case glslang::EOpSubgroupInclusiveMul : 10727case glslang::EOpSubgroupExclusiveMul : 10728case glslang::EOpSubgroupClusteredMul : 10729case glslang::EOpSubgroupPartitionedMul : 10730case glslang::EOpSubgroupPartitionedInclusiveMul : 10731case glslang::EOpSubgroupPartitionedExclusiveMul : 10732if (isFloat ) { 10733opCode = spv::Op ::OpGroupNonUniformFMul ; 10734 }else { 10735opCode = spv::Op ::OpGroupNonUniformIMul ; 10736 } 10737break ; 10738case glslang::EOpSubgroupMin : 10739case glslang::EOpSubgroupInclusiveMin : 10740case glslang::EOpSubgroupExclusiveMin : 10741case glslang::EOpSubgroupClusteredMin : 10742case glslang::EOpSubgroupPartitionedMin : 10743case glslang::EOpSubgroupPartitionedInclusiveMin : 10744case glslang::EOpSubgroupPartitionedExclusiveMin : 10745if (isFloat ) { 10746opCode = spv::Op ::OpGroupNonUniformFMin ; 10747 }else if (isUnsigned ) { 10748opCode = spv::Op ::OpGroupNonUniformUMin ; 10749 }else { 10750opCode = spv::Op ::OpGroupNonUniformSMin ; 10751 } 10752break ; 10753case glslang::EOpSubgroupMax : 10754case glslang::EOpSubgroupInclusiveMax : 10755case glslang::EOpSubgroupExclusiveMax : 10756case glslang::EOpSubgroupClusteredMax : 10757case glslang::EOpSubgroupPartitionedMax : 10758case glslang::EOpSubgroupPartitionedInclusiveMax : 10759case glslang::EOpSubgroupPartitionedExclusiveMax : 10760if (isFloat ) { 10761opCode = spv::Op ::OpGroupNonUniformFMax ; 10762 }else if (isUnsigned ) { 10763opCode = spv::Op ::OpGroupNonUniformUMax ; 10764 }else { 10765opCode = spv::Op ::OpGroupNonUniformSMax ; 10766 } 10767break ; 10768case glslang::EOpSubgroupAnd : 10769case glslang::EOpSubgroupInclusiveAnd : 10770case glslang::EOpSubgroupExclusiveAnd : 10771case glslang::EOpSubgroupClusteredAnd : 10772case glslang::EOpSubgroupPartitionedAnd : 10773case glslang::EOpSubgroupPartitionedInclusiveAnd : 10774case glslang::EOpSubgroupPartitionedExclusiveAnd : 10775if (isBool ) { 10776opCode = spv::Op ::OpGroupNonUniformLogicalAnd ; 10777 }else { 10778opCode = spv::Op ::OpGroupNonUniformBitwiseAnd ; 10779 } 10780break ; 10781case glslang::EOpSubgroupOr : 10782case glslang::EOpSubgroupInclusiveOr : 10783case glslang::EOpSubgroupExclusiveOr : 10784case glslang::EOpSubgroupClusteredOr : 10785case glslang::EOpSubgroupPartitionedOr : 10786case glslang::EOpSubgroupPartitionedInclusiveOr : 10787case glslang::EOpSubgroupPartitionedExclusiveOr : 10788if (isBool ) { 10789opCode = spv::Op ::OpGroupNonUniformLogicalOr ; 10790 }else { 10791opCode = spv::Op ::OpGroupNonUniformBitwiseOr ; 10792 } 10793break ; 10794case glslang::EOpSubgroupXor : 10795case glslang::EOpSubgroupInclusiveXor : 10796case glslang::EOpSubgroupExclusiveXor : 10797case glslang::EOpSubgroupClusteredXor : 10798case glslang::EOpSubgroupPartitionedXor : 10799case glslang::EOpSubgroupPartitionedInclusiveXor : 10800case glslang::EOpSubgroupPartitionedExclusiveXor : 10801if (isBool ) { 10802opCode = spv::Op ::OpGroupNonUniformLogicalXor ; 10803 }else { 10804opCode = spv::Op ::OpGroupNonUniformBitwiseXor ; 10805 } 10806break ; 10807case glslang::EOpSubgroupQuadBroadcast :opCode = spv::Op ::OpGroupNonUniformQuadBroadcast ;break ; 10808case glslang::EOpSubgroupQuadSwapHorizontal : 10809case glslang::EOpSubgroupQuadSwapVertical : 10810case glslang::EOpSubgroupQuadSwapDiagonal :opCode = spv::Op ::OpGroupNonUniformQuadSwap ;break ; 10811default :assert (0 && "Unhandled subgroup operation!" ); 10812 } 10813 10814// get the right Group Operation 10815 spv::GroupOperation groupOperation = spv::GroupOperation ::Max ; 10816switch (op ) { 10817default : 10818break ; 10819case glslang::EOpSubgroupBallotBitCount : 10820case glslang::EOpSubgroupAdd : 10821case glslang::EOpSubgroupMul : 10822case glslang::EOpSubgroupMin : 10823case glslang::EOpSubgroupMax : 10824case glslang::EOpSubgroupAnd : 10825case glslang::EOpSubgroupOr : 10826case glslang::EOpSubgroupXor : 10827groupOperation = spv::GroupOperation ::Reduce ; 10828break ; 10829case glslang::EOpSubgroupBallotInclusiveBitCount : 10830case glslang::EOpSubgroupInclusiveAdd : 10831case glslang::EOpSubgroupInclusiveMul : 10832case glslang::EOpSubgroupInclusiveMin : 10833case glslang::EOpSubgroupInclusiveMax : 10834case glslang::EOpSubgroupInclusiveAnd : 10835case glslang::EOpSubgroupInclusiveOr : 10836case glslang::EOpSubgroupInclusiveXor : 10837groupOperation = spv::GroupOperation ::InclusiveScan ; 10838break ; 10839case glslang::EOpSubgroupBallotExclusiveBitCount : 10840case glslang::EOpSubgroupExclusiveAdd : 10841case glslang::EOpSubgroupExclusiveMul : 10842case glslang::EOpSubgroupExclusiveMin : 10843case glslang::EOpSubgroupExclusiveMax : 10844case glslang::EOpSubgroupExclusiveAnd : 10845case glslang::EOpSubgroupExclusiveOr : 10846case glslang::EOpSubgroupExclusiveXor : 10847groupOperation = spv::GroupOperation ::ExclusiveScan ; 10848break ; 10849case glslang::EOpSubgroupClusteredAdd : 10850case glslang::EOpSubgroupClusteredMul : 10851case glslang::EOpSubgroupClusteredMin : 10852case glslang::EOpSubgroupClusteredMax : 10853case glslang::EOpSubgroupClusteredAnd : 10854case glslang::EOpSubgroupClusteredOr : 10855case glslang::EOpSubgroupClusteredXor : 10856groupOperation = spv::GroupOperation ::ClusteredReduce ; 10857break ; 10858case glslang::EOpSubgroupPartitionedAdd : 10859case glslang::EOpSubgroupPartitionedMul : 10860case glslang::EOpSubgroupPartitionedMin : 10861case glslang::EOpSubgroupPartitionedMax : 10862case glslang::EOpSubgroupPartitionedAnd : 10863case glslang::EOpSubgroupPartitionedOr : 10864case glslang::EOpSubgroupPartitionedXor : 10865groupOperation = spv::GroupOperation ::PartitionedReduceNV ; 10866break ; 10867case glslang::EOpSubgroupPartitionedInclusiveAdd : 10868case glslang::EOpSubgroupPartitionedInclusiveMul : 10869case glslang::EOpSubgroupPartitionedInclusiveMin : 10870case glslang::EOpSubgroupPartitionedInclusiveMax : 10871case glslang::EOpSubgroupPartitionedInclusiveAnd : 10872case glslang::EOpSubgroupPartitionedInclusiveOr : 10873case glslang::EOpSubgroupPartitionedInclusiveXor : 10874groupOperation = spv::GroupOperation ::PartitionedInclusiveScanNV ; 10875break ; 10876case glslang::EOpSubgroupPartitionedExclusiveAdd : 10877case glslang::EOpSubgroupPartitionedExclusiveMul : 10878case glslang::EOpSubgroupPartitionedExclusiveMin : 10879case glslang::EOpSubgroupPartitionedExclusiveMax : 10880case glslang::EOpSubgroupPartitionedExclusiveAnd : 10881case glslang::EOpSubgroupPartitionedExclusiveOr : 10882case glslang::EOpSubgroupPartitionedExclusiveXor : 10883groupOperation = spv::GroupOperation ::PartitionedExclusiveScanNV ; 10884break ; 10885 } 10886 10887// build the instruction 10888 std::vector < spv::IdImmediate > spvGroupOperands ; 10889 10890// Every operation begins with the Execution Scope operand. 10891 spv::IdImmediate executionScope = { true,builder .makeUintConstant (spv::Scope ::Subgroup ) }; 10892// All other ops need the execution scope. Quad Control Ops don't need scope, it's always Quad. 10893if (opCode != spv::Op ::OpGroupNonUniformQuadAllKHR && opCode != spv::Op ::OpGroupNonUniformQuadAnyKHR ) { 10894spvGroupOperands .push_back (executionScope ); 10895 } 10896 10897// Next, for all operations that use a Group Operation, push that as an operand. 10898if (groupOperation != spv::GroupOperation ::Max ) { 10899 spv::IdImmediate groupOperand = { false, (unsigned )groupOperation }; 10900spvGroupOperands .push_back (groupOperand ); 10901 } 10902 10903// Push back the operands next. 10904for (auto opIt = operands .cbegin ();opIt != operands .cend ();++ opIt ) { 10905 spv::IdImmediate operand = { true,* opIt }; 10906spvGroupOperands .push_back (operand ); 10907 } 10908 10909// Some opcodes have additional operands. 10910 spv::Id directionId = spv::NoResult ; 10911switch (op ) { 10912default :break ; 10913case glslang::EOpSubgroupQuadSwapHorizontal :directionId = builder .makeUintConstant (0 );break ; 10914case glslang::EOpSubgroupQuadSwapVertical :directionId = builder .makeUintConstant (1 );break ; 10915case glslang::EOpSubgroupQuadSwapDiagonal :directionId = builder .makeUintConstant (2 );break ; 10916 } 10917if (directionId != spv::NoResult ) { 10918 spv::IdImmediate direction = { true,directionId }; 10919spvGroupOperands .push_back (direction ); 10920 } 10921 10922return builder .createOp (opCode ,typeId ,spvGroupOperands ); 10923} 10924 10925spv::Id TGlslangToSpvTraverser ::createMiscOperation (glslang::TOperator op , spv::Decoration precision , 10926 spv::Id typeId , std::vector < spv::Id >& operands , glslang::TBasicType typeProxy ) 10927{ 10928bool isUnsigned = isTypeUnsignedInt (typeProxy ); 10929bool isFloat = isTypeFloat (typeProxy ); 10930 10931 spv::Op opCode = spv::Op ::OpNop ; 10932int extBuiltins = -1 ; 10933int libCall = -1 ; 10934size_t consumedOperands = operands .size (); 10935 spv::Id typeId0 = 0 ; 10936if (consumedOperands > 0 ) 10937typeId0 = builder .getTypeId (operands [0 ]); 10938 spv::Id typeId1 = 0 ; 10939if (consumedOperands > 1 ) 10940typeId1 = builder .getTypeId (operands [1 ]); 10941 spv::Id frexpIntType = 0 ; 10942 10943switch (op ) { 10944case glslang::EOpMin : 10945if (isFloat ) 10946libCall = nanMinMaxClamp ? spv::GLSLstd450NMin : spv::GLSLstd450FMin ; 10947else if (isUnsigned ) 10948libCall = spv::GLSLstd450UMin ; 10949else 10950libCall = spv::GLSLstd450SMin ; 10951builder .promoteScalar (precision ,operands .front (),operands .back ()); 10952break ; 10953case glslang::EOpModf : 10954 { 10955libCall = spv::GLSLstd450ModfStruct ; 10956assert (builder .isFloatType (builder .getScalarTypeId (typeId0 ))); 10957// The returned struct has two members of the same type as the first argument 10958typeId = builder .makeStructResultType (typeId0 ,typeId0 ); 10959consumedOperands = 1 ; 10960 } 10961break ; 10962case glslang::EOpMax : 10963if (isFloat ) 10964libCall = nanMinMaxClamp ? spv::GLSLstd450NMax : spv::GLSLstd450FMax ; 10965else if (isUnsigned ) 10966libCall = spv::GLSLstd450UMax ; 10967else 10968libCall = spv::GLSLstd450SMax ; 10969builder .promoteScalar (precision ,operands .front (),operands .back ()); 10970break ; 10971case glslang::EOpPow : 10972libCall = spv::GLSLstd450Pow ; 10973break ; 10974case glslang::EOpDot : 10975case glslang::EOpDotPackedEXT : 10976case glslang::EOpDotAccSatEXT : 10977case glslang::EOpDotPackedAccSatEXT : 10978 { 10979if (builder .isFloatType (builder .getScalarTypeId (typeId0 ))|| 10980// HLSL supports dot(int,int) which is just a multiply 10981glslangIntermediate -> getSource ()== glslang::EShSourceHlsl ) { 10982if (typeProxy == glslang::EbtBFloat16 ) { 10983builder .addExtension (spv::E_SPV_KHR_bfloat16 ); 10984builder .addCapability (spv::Capability ::BFloat16DotProductKHR ); 10985 } 10986opCode = spv::Op ::OpDot ; 10987 }else { 10988builder .addExtension (spv::E_SPV_KHR_integer_dot_product ); 10989builder .addCapability (spv::Capability ::DotProductKHR ); 10990const unsigned int vectorSize = builder .getNumComponents (operands [0 ]); 10991if (op == glslang::EOpDotPackedEXT || op == glslang::EOpDotPackedAccSatEXT ) { 10992builder .addCapability (spv::Capability ::DotProductInput4x8BitPackedKHR ); 10993 }else if (vectorSize == 4 && builder .getScalarTypeWidth (typeId0 )== 8 ) { 10994builder .addCapability (spv::Capability ::DotProductInput4x8BitKHR ); 10995 }else { 10996builder .addCapability (spv::Capability ::DotProductInputAllKHR ); 10997 } 10998const bool type0isSigned = builder .isIntType (builder .getScalarTypeId (typeId0 )); 10999const bool type1isSigned = builder .isIntType (builder .getScalarTypeId (typeId1 )); 11000const bool accSat = (op == glslang::EOpDotAccSatEXT || op == glslang::EOpDotPackedAccSatEXT ); 11001if (!type0isSigned && !type1isSigned ) { 11002opCode = accSat ? spv::Op ::OpUDotAccSatKHR : spv::Op ::OpUDotKHR ; 11003 }else if (type0isSigned && type1isSigned ) { 11004opCode = accSat ? spv::Op ::OpSDotAccSatKHR : spv::Op ::OpSDotKHR ; 11005 }else { 11006opCode = accSat ? spv::Op ::OpSUDotAccSatKHR : spv::Op ::OpSUDotKHR ; 11007// the spir-v opcode assumes the operands to be "signed, unsigned" in that order, so swap if needed 11008if (type1isSigned ) { 11009 std::swap (operands [0 ],operands [1 ]); 11010 } 11011 } 11012 std::vector < spv::IdImmediate > operands2 ; 11013for (auto & o :operands ) { 11014operands2 .push_back ({true,o }); 11015 } 11016if (op == glslang::EOpDotPackedEXT || op == glslang::EOpDotPackedAccSatEXT ) { 11017operands2 .push_back ({false,0 }); 11018 } 11019return builder .createOp (opCode ,typeId ,operands2 ); 11020 } 11021 } 11022break ; 11023case glslang::EOpAtan : 11024libCall = spv::GLSLstd450Atan2 ; 11025break ; 11026 11027case glslang::EOpClamp : 11028if (isFloat ) 11029libCall = nanMinMaxClamp ? spv::GLSLstd450NClamp : spv::GLSLstd450FClamp ; 11030else if (isUnsigned ) 11031libCall = spv::GLSLstd450UClamp ; 11032else 11033libCall = spv::GLSLstd450SClamp ; 11034builder .promoteScalar (precision ,operands .front (),operands [1 ]); 11035builder .promoteScalar (precision ,operands .front (),operands [2 ]); 11036break ; 11037case glslang::EOpMix : 11038if (!builder .isBoolType (builder .getScalarTypeId (builder .getTypeId (operands .back ())))) { 11039assert (isFloat ); 11040libCall = spv::GLSLstd450FMix ; 11041 }else { 11042opCode = spv::Op ::OpSelect ; 11043 std::swap (operands .front (),operands .back ()); 11044 } 11045builder .promoteScalar (precision ,operands .front (),operands .back ()); 11046break ; 11047case glslang::EOpStep : 11048libCall = spv::GLSLstd450Step ; 11049builder .promoteScalar (precision ,operands .front (),operands .back ()); 11050break ; 11051case glslang::EOpSmoothStep : 11052libCall = spv::GLSLstd450SmoothStep ; 11053builder .promoteScalar (precision ,operands [0 ],operands [2 ]); 11054builder .promoteScalar (precision ,operands [1 ],operands [2 ]); 11055break ; 11056 11057case glslang::EOpDistance : 11058libCall = spv::GLSLstd450Distance ; 11059break ; 11060case glslang::EOpCross : 11061libCall = spv::GLSLstd450Cross ; 11062break ; 11063case glslang::EOpFaceForward : 11064libCall = spv::GLSLstd450FaceForward ; 11065break ; 11066case glslang::EOpReflect : 11067libCall = spv::GLSLstd450Reflect ; 11068break ; 11069case glslang::EOpRefract : 11070libCall = spv::GLSLstd450Refract ; 11071break ; 11072case glslang::EOpBarrier : 11073 { 11074// This is for the extended controlBarrier function, with four operands. 11075// The unextended barrier() goes through createNoArgOperation. 11076assert (operands .size ()== 4 ); 11077auto const executionScope = (spv::Scope )builder .getConstantScalar (operands [0 ]); 11078auto const memoryScope = (spv::Scope )builder .getConstantScalar (operands [1 ]); 11079auto const semantics = (spv::MemorySemanticsMask )(builder .getConstantScalar (operands [2 ]) |builder .getConstantScalar (operands [3 ])); 11080builder .createControlBarrier (executionScope ,memoryScope , 11081semantics ); 11082if (anySet (semantics , spv::MemorySemanticsMask ::MakeAvailableKHR | 11083 spv::MemorySemanticsMask ::MakeVisibleKHR | 11084 spv::MemorySemanticsMask ::OutputMemoryKHR | 11085 spv::MemorySemanticsMask ::Volatile )) { 11086builder .addCapability (spv::Capability ::VulkanMemoryModelKHR ); 11087 } 11088if (glslangIntermediate -> usingVulkanMemoryModel ()&& (executionScope == spv::Scope ::Device || 11089memoryScope == spv::Scope ::Device )) { 11090builder .addCapability (spv::Capability ::VulkanMemoryModelDeviceScopeKHR ); 11091 } 11092return 0 ; 11093 } 11094break ; 11095case glslang::EOpControlBarrierArriveEXT : 11096case glslang::EOpControlBarrierWaitEXT : 11097 { 11098builder .addExtension (spv::E_SPV_EXT_split_barrier ); 11099builder .addCapability (spv::Capability ::SplitBarrierEXT ); 11100// This is for the extended controlBarrierArrive/Wait functions, with four operands. 11101// The unextended controlBarrierArrive/controlBarrierWait() go through createNoArgOperation. 11102assert (operands .size ()== 4 ); 11103auto const executionScope = (spv::Scope )builder .getConstantScalar (operands [0 ]); 11104auto const memoryScope = (spv::Scope )builder .getConstantScalar (operands [1 ]); 11105auto const semantics = (spv::MemorySemanticsMask )(builder .getConstantScalar (operands [2 ]) |builder .getConstantScalar (operands [3 ])); 11106builder .createSplitControlBarrier ((op == glslang::EOpControlBarrierArriveEXT ? spv::Op ::OpControlBarrierArriveEXT 11107 : spv::Op ::OpControlBarrierWaitEXT ), 11108executionScope ,memoryScope ,semantics ); 11109if (anySet (semantics , spv::MemorySemanticsMask ::OutputMemoryKHR )) { 11110builder .addCapability (spv::Capability ::VulkanMemoryModelKHR ); 11111 } 11112return 0 ; 11113 } 11114break ; 11115case glslang::EOpMemoryBarrier : 11116 { 11117// This is for the extended memoryBarrier function, with three operands. 11118// The unextended memoryBarrier() goes through createNoArgOperation. 11119assert (operands .size ()== 3 ); 11120auto const memoryScope = (spv::Scope )builder .getConstantScalar (operands [0 ]); 11121auto const semantics = (spv::MemorySemanticsMask )(builder .getConstantScalar (operands [1 ]) |builder .getConstantScalar (operands [2 ])); 11122builder .createMemoryBarrier (memoryScope ,semantics ); 11123if (anySet (semantics , spv::MemorySemanticsMask ::MakeAvailableKHR | 11124 spv::MemorySemanticsMask ::MakeVisibleKHR | 11125 spv::MemorySemanticsMask ::OutputMemoryKHR | 11126 spv::MemorySemanticsMask ::Volatile )) { 11127builder .addCapability (spv::Capability ::VulkanMemoryModelKHR ); 11128 } 11129if (glslangIntermediate -> usingVulkanMemoryModel ()&& memoryScope == spv::Scope ::Device ) { 11130builder .addCapability (spv::Capability ::VulkanMemoryModelDeviceScopeKHR ); 11131 } 11132return 0 ; 11133 } 11134break ; 11135 11136case glslang::EOpInterpolateAtSample : 11137if (typeProxy == glslang::EbtFloat16 ) 11138builder .addExtension (spv::E_SPV_AMD_gpu_shader_half_float ); 11139libCall = spv::GLSLstd450InterpolateAtSample ; 11140break ; 11141case glslang::EOpInterpolateAtOffset : 11142if (typeProxy == glslang::EbtFloat16 ) 11143builder .addExtension (spv::E_SPV_AMD_gpu_shader_half_float ); 11144libCall = spv::GLSLstd450InterpolateAtOffset ; 11145break ; 11146case glslang::EOpAddCarry : 11147opCode = spv::Op ::OpIAddCarry ; 11148typeId = builder .makeStructResultType (typeId0 ,typeId0 ); 11149consumedOperands = 2 ; 11150break ; 11151case glslang::EOpSubBorrow : 11152opCode = spv::Op ::OpISubBorrow ; 11153typeId = builder .makeStructResultType (typeId0 ,typeId0 ); 11154consumedOperands = 2 ; 11155break ; 11156case glslang::EOpUMulExtended : 11157opCode = spv::Op ::OpUMulExtended ; 11158typeId = builder .makeStructResultType (typeId0 ,typeId0 ); 11159consumedOperands = 2 ; 11160break ; 11161case glslang::EOpIMulExtended : 11162opCode = spv::Op ::OpSMulExtended ; 11163typeId = builder .makeStructResultType (typeId0 ,typeId0 ); 11164consumedOperands = 2 ; 11165break ; 11166case glslang::EOpBitfieldExtract : 11167if (isUnsigned ) 11168opCode = spv::Op ::OpBitFieldUExtract ; 11169else 11170opCode = spv::Op ::OpBitFieldSExtract ; 11171break ; 11172case glslang::EOpBitfieldInsert : 11173opCode = spv::Op ::OpBitFieldInsert ; 11174break ; 11175 11176case glslang::EOpFma : 11177libCall = spv::GLSLstd450Fma ; 11178break ; 11179case glslang::EOpFrexp : 11180 { 11181libCall = spv::GLSLstd450FrexpStruct ; 11182assert (builder .isPointerType (typeId1 )); 11183typeId1 = builder .getContainedTypeId (typeId1 ); 11184int width = builder .getScalarTypeWidth (typeId1 ); 11185if (width == 16 ) 11186// Using 16-bit exp operand, enable extension SPV_AMD_gpu_shader_int16 11187builder .addExtension (spv::E_SPV_AMD_gpu_shader_int16 ); 11188if (builder .getNumComponents (operands [0 ])== 1 ) 11189frexpIntType = builder .makeIntegerType (width , true); 11190else if (builder .isCooperativeVector (operands [0 ])) 11191frexpIntType = builder .makeCooperativeVectorTypeNV (builder .makeIntegerType (width , true), 11192builder .getCooperativeVectorNumComponents (builder .getTypeId (operands [0 ]))); 11193else 11194frexpIntType = builder .makeVectorType (builder .makeIntegerType (width , true), 11195builder .getNumComponents (operands [0 ])); 11196typeId = builder .makeStructResultType (typeId0 ,frexpIntType ); 11197consumedOperands = 1 ; 11198 } 11199break ; 11200case glslang::EOpLdexp : 11201libCall = spv::GLSLstd450Ldexp ; 11202break ; 11203 11204case glslang::EOpReadInvocation : 11205return createInvocationsOperation (op ,typeId ,operands ,typeProxy ); 11206 11207case glslang::EOpSubgroupBroadcast : 11208case glslang::EOpSubgroupBallotBitExtract : 11209case glslang::EOpSubgroupShuffle : 11210case glslang::EOpSubgroupShuffleXor : 11211case glslang::EOpSubgroupShuffleUp : 11212case glslang::EOpSubgroupShuffleDown : 11213case glslang::EOpSubgroupRotate : 11214case glslang::EOpSubgroupClusteredRotate : 11215case glslang::EOpSubgroupClusteredAdd : 11216case glslang::EOpSubgroupClusteredMul : 11217case glslang::EOpSubgroupClusteredMin : 11218case glslang::EOpSubgroupClusteredMax : 11219case glslang::EOpSubgroupClusteredAnd : 11220case glslang::EOpSubgroupClusteredOr : 11221case glslang::EOpSubgroupClusteredXor : 11222case glslang::EOpSubgroupQuadBroadcast : 11223case glslang::EOpSubgroupPartitionedAdd : 11224case glslang::EOpSubgroupPartitionedMul : 11225case glslang::EOpSubgroupPartitionedMin : 11226case glslang::EOpSubgroupPartitionedMax : 11227case glslang::EOpSubgroupPartitionedAnd : 11228case glslang::EOpSubgroupPartitionedOr : 11229case glslang::EOpSubgroupPartitionedXor : 11230case glslang::EOpSubgroupPartitionedInclusiveAdd : 11231case glslang::EOpSubgroupPartitionedInclusiveMul : 11232case glslang::EOpSubgroupPartitionedInclusiveMin : 11233case glslang::EOpSubgroupPartitionedInclusiveMax : 11234case glslang::EOpSubgroupPartitionedInclusiveAnd : 11235case glslang::EOpSubgroupPartitionedInclusiveOr : 11236case glslang::EOpSubgroupPartitionedInclusiveXor : 11237case glslang::EOpSubgroupPartitionedExclusiveAdd : 11238case glslang::EOpSubgroupPartitionedExclusiveMul : 11239case glslang::EOpSubgroupPartitionedExclusiveMin : 11240case glslang::EOpSubgroupPartitionedExclusiveMax : 11241case glslang::EOpSubgroupPartitionedExclusiveAnd : 11242case glslang::EOpSubgroupPartitionedExclusiveOr : 11243case glslang::EOpSubgroupPartitionedExclusiveXor : 11244return createSubgroupOperation (op ,typeId ,operands ,typeProxy ); 11245 11246case glslang::EOpSwizzleInvocations : 11247extBuiltins = getExtBuiltins (spv::E_SPV_AMD_shader_ballot ); 11248libCall = spv::SwizzleInvocationsAMD ; 11249break ; 11250case glslang::EOpSwizzleInvocationsMasked : 11251extBuiltins = getExtBuiltins (spv::E_SPV_AMD_shader_ballot ); 11252libCall = spv::SwizzleInvocationsMaskedAMD ; 11253break ; 11254case glslang::EOpWriteInvocation : 11255extBuiltins = getExtBuiltins (spv::E_SPV_AMD_shader_ballot ); 11256libCall = spv::WriteInvocationAMD ; 11257break ; 11258 11259case glslang::EOpMin3 : 11260extBuiltins = getExtBuiltins (spv::E_SPV_AMD_shader_trinary_minmax ); 11261if (isFloat ) 11262libCall = spv::FMin3AMD ; 11263else { 11264if (isUnsigned ) 11265libCall = spv::UMin3AMD ; 11266else 11267libCall = spv::SMin3AMD ; 11268 } 11269break ; 11270case glslang::EOpMax3 : 11271extBuiltins = getExtBuiltins (spv::E_SPV_AMD_shader_trinary_minmax ); 11272if (isFloat ) 11273libCall = spv::FMax3AMD ; 11274else { 11275if (isUnsigned ) 11276libCall = spv::UMax3AMD ; 11277else 11278libCall = spv::SMax3AMD ; 11279 } 11280break ; 11281case glslang::EOpMid3 : 11282extBuiltins = getExtBuiltins (spv::E_SPV_AMD_shader_trinary_minmax ); 11283if (isFloat ) 11284libCall = spv::FMid3AMD ; 11285else { 11286if (isUnsigned ) 11287libCall = spv::UMid3AMD ; 11288else 11289libCall = spv::SMid3AMD ; 11290 } 11291break ; 11292 11293case glslang::EOpInterpolateAtVertex : 11294if (typeProxy == glslang::EbtFloat16 ) 11295builder .addExtension (spv::E_SPV_AMD_gpu_shader_half_float ); 11296extBuiltins = getExtBuiltins (spv::E_SPV_AMD_shader_explicit_vertex_parameter ); 11297libCall = spv::InterpolateAtVertexAMD ; 11298break ; 11299 11300case glslang::EOpReportIntersection : 11301typeId = builder .makeBoolType (); 11302opCode = spv::Op ::OpReportIntersectionKHR ; 11303break ; 11304case glslang::EOpTraceNV : 11305builder .createNoResultOp (spv::Op ::OpTraceNV ,operands ); 11306return 0 ; 11307case glslang::EOpTraceRayMotionNV : 11308builder .addExtension (spv::E_SPV_NV_ray_tracing_motion_blur ); 11309builder .addCapability (spv::Capability ::RayTracingMotionBlurNV ); 11310builder .createNoResultOp (spv::Op ::OpTraceRayMotionNV ,operands ); 11311return 0 ; 11312case glslang::EOpTraceKHR : 11313builder .createNoResultOp (spv::Op ::OpTraceRayKHR ,operands ); 11314return 0 ; 11315case glslang::EOpExecuteCallableNV : 11316builder .createNoResultOp (spv::Op ::OpExecuteCallableNV ,operands ); 11317return 0 ; 11318case glslang::EOpExecuteCallableKHR : 11319builder .createNoResultOp (spv::Op ::OpExecuteCallableKHR ,operands ); 11320return 0 ; 11321 11322case glslang::EOpRayQueryInitialize : 11323builder .createNoResultOp (spv::Op ::OpRayQueryInitializeKHR ,operands ); 11324return 0 ; 11325case glslang::EOpRayQueryTerminate : 11326builder .createNoResultOp (spv::Op ::OpRayQueryTerminateKHR ,operands ); 11327return 0 ; 11328case glslang::EOpRayQueryGenerateIntersection : 11329builder .createNoResultOp (spv::Op ::OpRayQueryGenerateIntersectionKHR ,operands ); 11330return 0 ; 11331case glslang::EOpRayQueryConfirmIntersection : 11332builder .createNoResultOp (spv::Op ::OpRayQueryConfirmIntersectionKHR ,operands ); 11333return 0 ; 11334case glslang::EOpRayQueryProceed : 11335typeId = builder .makeBoolType (); 11336opCode = spv::Op ::OpRayQueryProceedKHR ; 11337break ; 11338case glslang::EOpRayQueryGetIntersectionType : 11339typeId = builder .makeUintType (32 ); 11340opCode = spv::Op ::OpRayQueryGetIntersectionTypeKHR ; 11341break ; 11342case glslang::EOpRayQueryGetRayTMin : 11343typeId = builder .makeFloatType (32 ); 11344opCode = spv::Op ::OpRayQueryGetRayTMinKHR ; 11345break ; 11346case glslang::EOpRayQueryGetRayFlags : 11347typeId = builder .makeIntType (32 ); 11348opCode = spv::Op ::OpRayQueryGetRayFlagsKHR ; 11349break ; 11350case glslang::EOpRayQueryGetIntersectionT : 11351typeId = builder .makeFloatType (32 ); 11352opCode = spv::Op ::OpRayQueryGetIntersectionTKHR ; 11353break ; 11354case glslang::EOpRayQueryGetIntersectionInstanceCustomIndex : 11355typeId = builder .makeIntType (32 ); 11356opCode = spv::Op ::OpRayQueryGetIntersectionInstanceCustomIndexKHR ; 11357break ; 11358case glslang::EOpRayQueryGetIntersectionInstanceId : 11359typeId = builder .makeIntType (32 ); 11360opCode = spv::Op ::OpRayQueryGetIntersectionInstanceIdKHR ; 11361break ; 11362case glslang::EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset : 11363typeId = builder .makeUintType (32 ); 11364opCode = spv::Op ::OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR ; 11365break ; 11366case glslang::EOpRayQueryGetIntersectionGeometryIndex : 11367typeId = builder .makeIntType (32 ); 11368opCode = spv::Op ::OpRayQueryGetIntersectionGeometryIndexKHR ; 11369break ; 11370case glslang::EOpRayQueryGetIntersectionPrimitiveIndex : 11371typeId = builder .makeIntType (32 ); 11372opCode = spv::Op ::OpRayQueryGetIntersectionPrimitiveIndexKHR ; 11373break ; 11374case glslang::EOpRayQueryGetIntersectionBarycentrics : 11375typeId = builder .makeVectorType (builder .makeFloatType (32 ),2 ); 11376opCode = spv::Op ::OpRayQueryGetIntersectionBarycentricsKHR ; 11377break ; 11378case glslang::EOpRayQueryGetIntersectionFrontFace : 11379typeId = builder .makeBoolType (); 11380opCode = spv::Op ::OpRayQueryGetIntersectionFrontFaceKHR ; 11381break ; 11382case glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque : 11383typeId = builder .makeBoolType (); 11384opCode = spv::Op ::OpRayQueryGetIntersectionCandidateAABBOpaqueKHR ; 11385break ; 11386case glslang::EOpRayQueryGetIntersectionObjectRayDirection : 11387typeId = builder .makeVectorType (builder .makeFloatType (32 ),3 ); 11388opCode = spv::Op ::OpRayQueryGetIntersectionObjectRayDirectionKHR ; 11389break ; 11390case glslang::EOpRayQueryGetIntersectionObjectRayOrigin : 11391typeId = builder .makeVectorType (builder .makeFloatType (32 ),3 ); 11392opCode = spv::Op ::OpRayQueryGetIntersectionObjectRayOriginKHR ; 11393break ; 11394case glslang::EOpRayQueryGetWorldRayDirection : 11395typeId = builder .makeVectorType (builder .makeFloatType (32 ),3 ); 11396opCode = spv::Op ::OpRayQueryGetWorldRayDirectionKHR ; 11397break ; 11398case glslang::EOpRayQueryGetWorldRayOrigin : 11399typeId = builder .makeVectorType (builder .makeFloatType (32 ),3 ); 11400opCode = spv::Op ::OpRayQueryGetWorldRayOriginKHR ; 11401break ; 11402case glslang::EOpRayQueryGetIntersectionObjectToWorld : 11403typeId = builder .makeMatrixType (builder .makeFloatType (32 ),4 ,3 ); 11404opCode = spv::Op ::OpRayQueryGetIntersectionObjectToWorldKHR ; 11405break ; 11406case glslang::EOpRayQueryGetIntersectionClusterIdNV : 11407typeId = builder .makeIntegerType (32 ,1 ); 11408opCode = spv::Op ::OpRayQueryGetClusterIdNV ; 11409break ; 11410case glslang::EOpRayQueryGetIntersectionWorldToObject : 11411typeId = builder .makeMatrixType (builder .makeFloatType (32 ),4 ,3 ); 11412opCode = spv::Op ::OpRayQueryGetIntersectionWorldToObjectKHR ; 11413break ; 11414case glslang::EOpRayQueryGetIntersectionSpherePositionNV : 11415typeId = builder .makeVectorType (builder .makeFloatType (32 ),3 ); 11416opCode = spv::Op ::OpRayQueryGetIntersectionSpherePositionNV ; 11417break ; 11418case glslang::EOpRayQueryGetIntersectionSphereRadiusNV : 11419typeId = builder .makeFloatType (32 ); 11420opCode = spv::Op ::OpRayQueryGetIntersectionSphereRadiusNV ; 11421break ; 11422case glslang::EOpRayQueryGetIntersectionLSSHitValueNV : 11423typeId = builder .makeFloatType (32 ); 11424opCode = spv::Op ::OpRayQueryGetIntersectionLSSHitValueNV ; 11425break ; 11426case glslang::EOpRayQueryIsSphereHitNV : 11427typeId = builder .makeBoolType (); 11428opCode = spv::Op ::OpRayQueryIsSphereHitNV ; 11429break ; 11430case glslang::EOpRayQueryIsLSSHitNV : 11431typeId = builder .makeBoolType (); 11432opCode = spv::Op ::OpRayQueryIsLSSHitNV ; 11433break ; 11434case glslang::EOpWritePackedPrimitiveIndices4x8NV : 11435builder .createNoResultOp (spv::Op ::OpWritePackedPrimitiveIndices4x8NV ,operands ); 11436return 0 ; 11437case glslang::EOpEmitMeshTasksEXT : 11438if (taskPayloadID ) 11439operands .push_back (taskPayloadID ); 11440// As per SPV_EXT_mesh_shader make it a terminating instruction in the current block 11441builder .makeStatementTerminator (spv::Op ::OpEmitMeshTasksEXT ,operands ,"post-OpEmitMeshTasksEXT" ); 11442return 0 ; 11443case glslang::EOpSetMeshOutputsEXT : 11444builder .createNoResultOp (spv::Op ::OpSetMeshOutputsEXT ,operands ); 11445return 0 ; 11446case glslang::EOpCooperativeMatrixMulAddNV : 11447opCode = spv::Op ::OpCooperativeMatrixMulAddNV ; 11448break ; 11449case glslang::EOpHitObjectTraceRayNV : 11450builder .createNoResultOp (spv::Op ::OpHitObjectTraceRayNV ,operands ); 11451return 0 ; 11452case glslang::EOpHitObjectTraceRayEXT : 11453builder .createNoResultOp (spv::Op ::OpHitObjectTraceRayEXT ,operands ); 11454return 0 ; 11455case glslang::EOpHitObjectTraceRayMotionNV : 11456builder .createNoResultOp (spv::Op ::OpHitObjectTraceRayMotionNV ,operands ); 11457return 0 ; 11458case glslang::EOpHitObjectTraceRayMotionEXT : 11459builder .createNoResultOp (spv::Op ::OpHitObjectTraceRayMotionEXT ,operands ); 11460return 0 ; 11461case glslang::EOpHitObjectRecordHitNV : 11462builder .createNoResultOp (spv::Op ::OpHitObjectRecordHitNV ,operands ); 11463return 0 ; 11464case glslang::EOpHitObjectRecordHitMotionNV : 11465builder .createNoResultOp (spv::Op ::OpHitObjectRecordHitMotionNV ,operands ); 11466return 0 ; 11467case glslang::EOpHitObjectRecordHitWithIndexNV : 11468builder .createNoResultOp (spv::Op ::OpHitObjectRecordHitWithIndexNV ,operands ); 11469return 0 ; 11470case glslang::EOpHitObjectRecordHitWithIndexMotionNV : 11471builder .createNoResultOp (spv::Op ::OpHitObjectRecordHitWithIndexMotionNV ,operands ); 11472return 0 ; 11473case glslang::EOpHitObjectRecordMissNV : 11474builder .createNoResultOp (spv::Op ::OpHitObjectRecordMissNV ,operands ); 11475return 0 ; 11476case glslang::EOpHitObjectRecordMissEXT : 11477builder .createNoResultOp (spv::Op ::OpHitObjectRecordMissEXT ,operands ); 11478return 0 ; 11479case glslang::EOpHitObjectRecordMissMotionNV : 11480builder .createNoResultOp (spv::Op ::OpHitObjectRecordMissMotionNV ,operands ); 11481return 0 ; 11482case glslang::EOpHitObjectRecordMissMotionEXT : 11483builder .createNoResultOp (spv::Op ::OpHitObjectRecordMissMotionEXT ,operands ); 11484return 0 ; 11485case glslang::EOpHitObjectExecuteShaderNV : 11486builder .createNoResultOp (spv::Op ::OpHitObjectExecuteShaderNV ,operands ); 11487return 0 ; 11488case glslang::EOpHitObjectExecuteShaderEXT : 11489builder .createNoResultOp (spv::Op ::OpHitObjectExecuteShaderEXT ,operands ); 11490return 0 ; 11491case glslang::EOpHitObjectIsEmptyNV : 11492typeId = builder .makeBoolType (); 11493opCode = spv::Op ::OpHitObjectIsEmptyNV ; 11494break ; 11495case glslang::EOpHitObjectIsEmptyEXT : 11496typeId = builder .makeBoolType (); 11497opCode = spv::Op ::OpHitObjectIsEmptyEXT ; 11498break ; 11499case glslang::EOpHitObjectIsMissNV : 11500typeId = builder .makeBoolType (); 11501opCode = spv::Op ::OpHitObjectIsMissNV ; 11502break ; 11503case glslang::EOpHitObjectIsMissEXT : 11504typeId = builder .makeBoolType (); 11505opCode = spv::Op ::OpHitObjectIsMissEXT ; 11506break ; 11507case glslang::EOpHitObjectIsHitNV : 11508typeId = builder .makeBoolType (); 11509opCode = spv::Op ::OpHitObjectIsHitNV ; 11510break ; 11511case glslang::EOpHitObjectIsSphereHitNV : 11512typeId = builder .makeBoolType (); 11513opCode = spv::Op ::OpHitObjectIsSphereHitNV ; 11514break ; 11515case glslang::EOpHitObjectIsLSSHitNV : 11516typeId = builder .makeBoolType (); 11517opCode = spv::Op ::OpHitObjectIsLSSHitNV ; 11518break ; 11519case glslang::EOpHitObjectIsHitEXT : 11520typeId = builder .makeBoolType (); 11521opCode = spv::Op ::OpHitObjectIsHitEXT ; 11522break ; 11523case glslang::EOpHitObjectGetRayTMinNV : 11524typeId = builder .makeFloatType (32 ); 11525opCode = spv::Op ::OpHitObjectGetRayTMinNV ; 11526break ; 11527case glslang::EOpHitObjectGetRayTMinEXT : 11528typeId = builder .makeFloatType (32 ); 11529opCode = spv::Op ::OpHitObjectGetRayTMinEXT ; 11530break ; 11531case glslang::EOpHitObjectGetRayTMaxNV : 11532typeId = builder .makeFloatType (32 ); 11533opCode = spv::Op ::OpHitObjectGetRayTMaxNV ; 11534break ; 11535case glslang::EOpHitObjectGetRayTMaxEXT : 11536typeId = builder .makeFloatType (32 ); 11537opCode = spv::Op ::OpHitObjectGetRayTMaxEXT ; 11538break ; 11539case glslang::EOpHitObjectGetRayFlagsEXT : 11540typeId = builder .makeIntegerType (32 ,0 ); 11541opCode = spv::Op ::OpHitObjectGetRayFlagsEXT ; 11542break ; 11543case glslang::EOpHitObjectGetObjectRayOriginNV : 11544typeId = builder .makeVectorType (builder .makeFloatType (32 ),3 ); 11545opCode = spv::Op ::OpHitObjectGetObjectRayOriginNV ; 11546break ; 11547case glslang::EOpHitObjectGetObjectRayOriginEXT : 11548typeId = builder .makeVectorType (builder .makeFloatType (32 ),3 ); 11549opCode = spv::Op ::OpHitObjectGetObjectRayOriginEXT ; 11550break ; 11551case glslang::EOpHitObjectGetObjectRayDirectionNV : 11552typeId = builder .makeVectorType (builder .makeFloatType (32 ),3 ); 11553opCode = spv::Op ::OpHitObjectGetObjectRayDirectionNV ; 11554break ; 11555case glslang::EOpHitObjectGetObjectRayDirectionEXT : 11556typeId = builder .makeVectorType (builder .makeFloatType (32 ),3 ); 11557opCode = spv::Op ::OpHitObjectGetObjectRayDirectionEXT ; 11558break ; 11559case glslang::EOpHitObjectGetWorldRayOriginNV : 11560typeId = builder .makeVectorType (builder .makeFloatType (32 ),3 ); 11561opCode = spv::Op ::OpHitObjectGetWorldRayOriginNV ; 11562break ; 11563case glslang::EOpHitObjectGetWorldRayOriginEXT : 11564typeId = builder .makeVectorType (builder .makeFloatType (32 ),3 ); 11565opCode = spv::Op ::OpHitObjectGetWorldRayOriginEXT ; 11566break ; 11567case glslang::EOpHitObjectGetWorldRayDirectionNV : 11568typeId = builder .makeVectorType (builder .makeFloatType (32 ),3 ); 11569opCode = spv::Op ::OpHitObjectGetWorldRayDirectionNV ; 11570break ; 11571case glslang::EOpHitObjectGetWorldRayDirectionEXT : 11572typeId = builder .makeVectorType (builder .makeFloatType (32 ),3 ); 11573opCode = spv::Op ::OpHitObjectGetWorldRayDirectionEXT ; 11574break ; 11575case glslang::EOpHitObjectGetWorldToObjectNV : 11576typeId = builder .makeMatrixType (builder .makeFloatType (32 ),4 ,3 ); 11577opCode = spv::Op ::OpHitObjectGetWorldToObjectNV ; 11578break ; 11579case glslang::EOpHitObjectGetWorldToObjectEXT : 11580typeId = builder .makeMatrixType (builder .makeFloatType (32 ),4 ,3 ); 11581opCode = spv::Op ::OpHitObjectGetWorldToObjectEXT ; 11582break ; 11583case glslang::EOpHitObjectGetObjectToWorldNV : 11584typeId = builder .makeMatrixType (builder .makeFloatType (32 ),4 ,3 ); 11585opCode = spv::Op ::OpHitObjectGetObjectToWorldNV ; 11586break ; 11587case glslang::EOpHitObjectGetObjectToWorldEXT : 11588typeId = builder .makeMatrixType (builder .makeFloatType (32 ),4 ,3 ); 11589opCode = spv::Op ::OpHitObjectGetObjectToWorldEXT ; 11590break ; 11591case glslang::EOpHitObjectGetInstanceCustomIndexNV : 11592typeId = builder .makeIntegerType (32 ,1 ); 11593opCode = spv::Op ::OpHitObjectGetInstanceCustomIndexNV ; 11594break ; 11595case glslang::EOpHitObjectGetInstanceCustomIndexEXT : 11596typeId = builder .makeIntegerType (32 ,1 ); 11597opCode = spv::Op ::OpHitObjectGetInstanceCustomIndexEXT ; 11598break ; 11599case glslang::EOpHitObjectGetInstanceIdNV : 11600typeId = builder .makeIntegerType (32 ,1 ); 11601opCode = spv::Op ::OpHitObjectGetInstanceIdNV ; 11602break ; 11603case glslang::EOpHitObjectGetInstanceIdEXT : 11604typeId = builder .makeIntegerType (32 ,1 ); 11605opCode = spv::Op ::OpHitObjectGetInstanceIdEXT ; 11606break ; 11607case glslang::EOpHitObjectGetGeometryIndexNV : 11608typeId = builder .makeIntegerType (32 ,1 ); 11609opCode = spv::Op ::OpHitObjectGetGeometryIndexNV ; 11610break ; 11611case glslang::EOpHitObjectGetGeometryIndexEXT : 11612typeId = builder .makeIntegerType (32 ,1 ); 11613opCode = spv::Op ::OpHitObjectGetGeometryIndexEXT ; 11614break ; 11615case glslang::EOpHitObjectGetPrimitiveIndexNV : 11616typeId = builder .makeIntegerType (32 ,1 ); 11617opCode = spv::Op ::OpHitObjectGetPrimitiveIndexNV ; 11618break ; 11619case glslang::EOpHitObjectGetPrimitiveIndexEXT : 11620typeId = builder .makeIntegerType (32 ,1 ); 11621opCode = spv::Op ::OpHitObjectGetPrimitiveIndexEXT ; 11622break ; 11623case glslang::EOpHitObjectGetHitKindNV : 11624typeId = builder .makeIntegerType (32 ,0 ); 11625opCode = spv::Op ::OpHitObjectGetHitKindNV ; 11626break ; 11627case glslang::EOpHitObjectGetHitKindEXT : 11628typeId = builder .makeIntegerType (32 ,0 ); 11629opCode = spv::Op ::OpHitObjectGetHitKindEXT ; 11630break ; 11631case glslang::EOpHitObjectGetCurrentTimeNV : 11632typeId = builder .makeFloatType (32 ); 11633opCode = spv::Op ::OpHitObjectGetCurrentTimeNV ; 11634break ; 11635case glslang::EOpHitObjectGetCurrentTimeEXT : 11636typeId = builder .makeFloatType (32 ); 11637opCode = spv::Op ::OpHitObjectGetCurrentTimeEXT ; 11638break ; 11639case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV : 11640typeId = builder .makeIntegerType (32 ,0 ); 11641opCode = spv::Op ::OpHitObjectGetShaderBindingTableRecordIndexNV ; 11642return 0 ; 11643case glslang::EOpHitObjectGetShaderBindingTableRecordIndexEXT : 11644typeId = builder .makeIntegerType (32 ,0 ); 11645opCode = spv::Op ::OpHitObjectGetShaderBindingTableRecordIndexEXT ; 11646return 0 ; 11647case glslang::EOpHitObjectGetAttributesNV : 11648builder .createNoResultOp (spv::Op ::OpHitObjectGetAttributesNV ,operands ); 11649return 0 ; 11650case glslang::EOpHitObjectGetAttributesEXT : 11651builder .createNoResultOp (spv::Op ::OpHitObjectGetAttributesEXT ,operands ); 11652return 0 ; 11653case glslang::EOpHitObjectRecordFromQueryEXT : 11654builder .createNoResultOp (spv::Op ::OpHitObjectRecordFromQueryEXT ,operands ); 11655return 0 ; 11656case glslang::EOpHitObjectGetShaderRecordBufferHandleNV : 11657typeId = builder .makeVectorType (builder .makeUintType (32 ),2 ); 11658opCode = spv::Op ::OpHitObjectGetShaderRecordBufferHandleNV ; 11659break ; 11660case glslang::EOpHitObjectGetClusterIdNV : 11661typeId = builder .makeIntegerType (32 ,1 ); 11662opCode = spv::Op ::OpHitObjectGetClusterIdNV ; 11663break ; 11664case glslang::EOpHitObjectGetShaderRecordBufferHandleEXT : 11665typeId = builder .makeVectorType (builder .makeUintType (32 ),2 ); 11666opCode = spv::Op ::OpHitObjectGetShaderRecordBufferHandleEXT ; 11667break ; 11668case glslang::EOpHitObjectSetShaderBindingTableRecordIndexEXT : 11669builder .createNoResultOp (spv::Op ::OpHitObjectSetShaderBindingTableRecordIndexEXT ,operands ); 11670return 0 ; 11671case glslang::EOpReorderThreadNV : { 11672if (operands .size ()== 2 ) { 11673builder .createNoResultOp (spv::Op ::OpReorderThreadWithHintNV ,operands ); 11674 }else { 11675builder .createNoResultOp (spv::Op ::OpReorderThreadWithHitObjectNV ,operands ); 11676 } 11677return 0 ; 11678 } 11679case glslang::EOpReorderThreadEXT : { 11680if (operands .size ()== 2 ) { 11681builder .createNoResultOp (spv::Op ::OpReorderThreadWithHintEXT ,operands ); 11682 }else { 11683builder .createNoResultOp (spv::Op ::OpReorderThreadWithHitObjectEXT ,operands ); 11684 } 11685return 0 ; 11686 } 11687 11688case glslang::EOpHitObjectReorderExecuteEXT : { 11689if (operands .size ()== 2 ) { 11690builder .createNoResultOp (spv::Op ::OpHitObjectReorderExecuteShaderEXT ,operands ); 11691 }else { 11692// GLSL intrinsic is 11693// hitObjectReorderExecuteEXT(hitObjectEXT hitObject, uint hint, uint bits,int payload) while 11694// SPIRV is hitObject id , payload id, optional hint id, optional bits id hence reorder operands 11695builder .createNoResultOp (spv::Op ::OpHitObjectReorderExecuteShaderEXT , {operands [0 ],operands [3 ],operands [1 ],operands [2 ]}); 11696 } 11697return 0 ; 11698 } 11699 11700case glslang::EOpHitObjectTraceReorderExecuteEXT : { 11701if (operands .size ()== 12 ) { 11702builder .createNoResultOp (spv::Op ::OpHitObjectTraceReorderExecuteEXT ,operands ); 11703 }else { 11704 std::vector < spv::Id > argOperands ; 11705 std::copy (operands .begin (),operands .begin ()+ 11 , std::back_inserter (argOperands )); 11706argOperands .push_back (operands [13 ]); 11707argOperands .push_back (operands [11 ]); 11708argOperands .push_back (operands [12 ]); 11709builder .createNoResultOp (spv::Op ::OpHitObjectTraceReorderExecuteEXT ,argOperands ); 11710 } 11711return 0 ; 11712 } 11713case glslang::EOpHitObjectTraceMotionReorderExecuteEXT : { 11714if (operands .size ()== 13 ) { 11715builder .createNoResultOp (spv::Op ::OpHitObjectTraceMotionReorderExecuteEXT ,operands ); 11716 }else { 11717 std::vector < spv::Id > argOperands ; 11718 std::copy (operands .begin (),operands .begin ()+ 12 , std::back_inserter (argOperands )); 11719argOperands .push_back (operands [14 ]); 11720argOperands .push_back (operands [12 ]); 11721argOperands .push_back (operands [13 ]); 11722builder .createNoResultOp (spv::Op ::OpHitObjectTraceMotionReorderExecuteEXT ,argOperands ); 11723 } 11724return 0 ; 11725 } 11726case glslang::EOpImageSampleWeightedQCOM : 11727typeId = builder .makeVectorType (builder .makeFloatType (32 ),4 ); 11728opCode = spv::Op ::OpImageSampleWeightedQCOM ; 11729addImageProcessingQCOMDecoration (operands [2 ], spv::Decoration ::WeightTextureQCOM ); 11730break ; 11731case glslang::EOpImageBoxFilterQCOM : 11732typeId = builder .makeVectorType (builder .makeFloatType (32 ),4 ); 11733opCode = spv::Op ::OpImageBoxFilterQCOM ; 11734break ; 11735case glslang::EOpImageBlockMatchSADQCOM : 11736typeId = builder .makeVectorType (builder .makeFloatType (32 ),4 ); 11737opCode = spv::Op ::OpImageBlockMatchSADQCOM ; 11738addImageProcessingQCOMDecoration (operands [0 ], spv::Decoration ::BlockMatchTextureQCOM ); 11739addImageProcessingQCOMDecoration (operands [2 ], spv::Decoration ::BlockMatchTextureQCOM ); 11740break ; 11741case glslang::EOpImageBlockMatchSSDQCOM : 11742typeId = builder .makeVectorType (builder .makeFloatType (32 ),4 ); 11743opCode = spv::Op ::OpImageBlockMatchSSDQCOM ; 11744addImageProcessingQCOMDecoration (operands [0 ], spv::Decoration ::BlockMatchTextureQCOM ); 11745addImageProcessingQCOMDecoration (operands [2 ], spv::Decoration ::BlockMatchTextureQCOM ); 11746break ; 11747 11748case glslang::EOpFetchMicroTriangleVertexBarycentricNV : 11749typeId = builder .makeVectorType (builder .makeFloatType (32 ),2 ); 11750opCode = spv::Op ::OpFetchMicroTriangleVertexBarycentricNV ; 11751break ; 11752 11753case glslang::EOpFetchMicroTriangleVertexPositionNV : 11754typeId = builder .makeVectorType (builder .makeFloatType (32 ),3 ); 11755opCode = spv::Op ::OpFetchMicroTriangleVertexPositionNV ; 11756break ; 11757 11758case glslang::EOpImageBlockMatchWindowSSDQCOM : 11759typeId = builder .makeVectorType (builder .makeFloatType (32 ),4 ); 11760opCode = spv::Op ::OpImageBlockMatchWindowSSDQCOM ; 11761addImageProcessing2QCOMDecoration (operands [0 ], false); 11762addImageProcessing2QCOMDecoration (operands [2 ], false); 11763break ; 11764case glslang::EOpImageBlockMatchWindowSADQCOM : 11765typeId = builder .makeVectorType (builder .makeFloatType (32 ),4 ); 11766opCode = spv::Op ::OpImageBlockMatchWindowSADQCOM ; 11767addImageProcessing2QCOMDecoration (operands [0 ], false); 11768addImageProcessing2QCOMDecoration (operands [2 ], false); 11769break ; 11770case glslang::EOpImageBlockMatchGatherSSDQCOM : 11771typeId = builder .makeVectorType (builder .makeFloatType (32 ),4 ); 11772opCode = spv::Op ::OpImageBlockMatchGatherSSDQCOM ; 11773addImageProcessing2QCOMDecoration (operands [0 ], true); 11774addImageProcessing2QCOMDecoration (operands [2 ], true); 11775break ; 11776case glslang::EOpImageBlockMatchGatherSADQCOM : 11777typeId = builder .makeVectorType (builder .makeFloatType (32 ),4 ); 11778opCode = spv::Op ::OpImageBlockMatchGatherSADQCOM ; 11779addImageProcessing2QCOMDecoration (operands [0 ], true); 11780addImageProcessing2QCOMDecoration (operands [2 ], true); 11781break ; 11782case glslang::EOpCreateTensorLayoutNV : 11783return builder .createOp (spv::Op ::OpCreateTensorLayoutNV ,typeId , std::vector < spv::Id > {}); 11784case glslang::EOpCreateTensorViewNV : 11785return builder .createOp (spv::Op ::OpCreateTensorViewNV ,typeId , std::vector < spv::Id > {}); 11786case glslang::EOpTensorLayoutSetBlockSizeNV : 11787opCode = spv::Op ::OpTensorLayoutSetBlockSizeNV ; 11788break ; 11789case glslang::EOpTensorLayoutSetDimensionNV : 11790opCode = spv::Op ::OpTensorLayoutSetDimensionNV ; 11791break ; 11792case glslang::EOpTensorLayoutSetStrideNV : 11793opCode = spv::Op ::OpTensorLayoutSetStrideNV ; 11794break ; 11795case glslang::EOpTensorLayoutSliceNV : 11796opCode = spv::Op ::OpTensorLayoutSliceNV ; 11797break ; 11798case glslang::EOpTensorLayoutSetClampValueNV : 11799opCode = spv::Op ::OpTensorLayoutSetClampValueNV ; 11800break ; 11801case glslang::EOpTensorViewSetDimensionNV : 11802opCode = spv::Op ::OpTensorViewSetDimensionNV ; 11803break ; 11804case glslang::EOpTensorViewSetStrideNV : 11805opCode = spv::Op ::OpTensorViewSetStrideNV ; 11806break ; 11807case glslang::EOpTensorViewSetClipNV : 11808opCode = spv::Op ::OpTensorViewSetClipNV ; 11809break ; 11810case glslang::EOpCooperativeMatrixGetCoordinateEXT : 11811opCode = spv::Op ::OpCooperativeMatrixGetCoordinateEXT ; 11812break ; 11813case glslang::EOpBitcastExtractE2M1 : 11814case glslang::EOpBitcastExtractE3M2 : 11815case glslang::EOpBitcastExtractE2M3 : 11816 { 11817 spv::Id scalarTypeId = op == glslang::EOpBitcastExtractE2M1 ?builder .makeFloatE2M1Type () : 11818op == glslang::EOpBitcastExtractE3M2 ?builder .makeFloatE3M2Type () :builder .makeFloatE2M3Type (); 11819opCode = spv::Op ::OpBitcastExtractEXT ; 11820typeId = scalarTypeId ; 11821if (builder .isVectorType (builder .getTypeId (operands [0 ]))) { 11822int vecSize = builder .getNumTypeComponents (builder .getTypeId (operands [0 ])); 11823typeId = builder .makeVectorType (typeId ,vecSize ); 11824 } 11825builder .addExtension (spv::E_SPV_EXT_ocp_microscaling_types ); 11826builder .addCapability (spv::Capability ::BitcastExtractEXT ); 11827break ; 11828 } 11829default : 11830return 0 ; 11831 } 11832 11833 spv::Id id = 0 ; 11834if (libCall >=0 ) { 11835// Use an extended instruction from the standard library. 11836// Construct the call arguments, without modifying the original operands vector. 11837// We might need the remaining arguments, e.g. in the EOpFrexp case. 11838 std::vector < spv::Id > callArguments (operands .begin (),operands .begin ()+ consumedOperands ); 11839id = builder .createBuiltinCall (typeId ,extBuiltins >=0 ?extBuiltins :stdBuiltins ,libCall ,callArguments ); 11840 }else if (opCode == spv::Op ::OpDot && !isFloat ) { 11841// int dot(int, int) 11842// NOTE: never called for scalar/vector1, this is turned into simple mul before this can be reached 11843const int componentCount = builder .getNumComponents (operands [0 ]); 11844 spv::Id mulOp = builder .createBinOp (spv::Op ::OpIMul ,builder .getTypeId (operands [0 ]),operands [0 ],operands [1 ]); 11845builder .setPrecision (mulOp ,precision ); 11846id = builder .createCompositeExtract (mulOp ,typeId ,0 ); 11847for (int i = 1 ;i < componentCount ;++ i ) { 11848builder .setPrecision (id ,precision ); 11849id = builder .createBinOp (spv::Op ::OpIAdd ,typeId ,id ,builder .createCompositeExtract (mulOp ,typeId ,i )); 11850 } 11851 }else { 11852switch (consumedOperands ) { 11853case 0 : 11854// should all be handled by visitAggregate and createNoArgOperation 11855assert (0 ); 11856return 0 ; 11857case 1 : 11858// should all be handled by createUnaryOperation 11859assert (0 ); 11860return 0 ; 11861case 2 : 11862id = builder .createBinOp (opCode ,typeId ,operands [0 ],operands [1 ]); 11863break ; 11864default : 11865// anything 3 or over doesn't have l-value operands, so all should be consumed 11866assert (consumedOperands == operands .size ()); 11867id = builder .createOp (opCode ,typeId ,operands ); 11868break ; 11869 } 11870 } 11871 11872// Decode the return types that were structures 11873switch (op ) { 11874case glslang::EOpAddCarry : 11875case glslang::EOpSubBorrow : 11876builder .createStore (builder .createCompositeExtract (id ,typeId0 ,1 ),operands [2 ]); 11877id = builder .createCompositeExtract (id ,typeId0 ,0 ); 11878break ; 11879case glslang::EOpUMulExtended : 11880case glslang::EOpIMulExtended : 11881builder .createStore (builder .createCompositeExtract (id ,typeId0 ,0 ),operands [3 ]); 11882builder .createStore (builder .createCompositeExtract (id ,typeId0 ,1 ),operands [2 ]); 11883break ; 11884case glslang::EOpModf : 11885 { 11886assert (operands .size ()== 2 ); 11887builder .createStore (builder .createCompositeExtract (id ,typeId0 ,1 ),operands [1 ]); 11888id = builder .createCompositeExtract (id ,typeId0 ,0 ); 11889 } 11890break ; 11891case glslang::EOpFrexp : 11892 { 11893assert (operands .size ()== 2 ); 11894if (builder .isFloatType (builder .getScalarTypeId (typeId1 ))) { 11895// "exp" is floating-point type (from HLSL intrinsic) 11896 spv::Id member1 = builder .createCompositeExtract (id ,frexpIntType ,1 ); 11897member1 = builder .createUnaryOp (spv::Op ::OpConvertSToF ,typeId1 ,member1 ); 11898builder .createStore (member1 ,operands [1 ]); 11899 }else 11900// "exp" is integer type (from GLSL built-in function) 11901builder .createStore (builder .createCompositeExtract (id ,frexpIntType ,1 ),operands [1 ]); 11902id = builder .createCompositeExtract (id ,typeId0 ,0 ); 11903 } 11904break ; 11905default : 11906break ; 11907 } 11908 11909return builder .setPrecision (id ,precision ); 11910} 11911 11912// Intrinsics with no arguments (or no return value, and no precision). 11913spv::Id TGlslangToSpvTraverser ::createNoArgOperation (glslang::TOperator op , spv::Decoration precision , spv::Id typeId ) 11914{ 11915// GLSL memory barriers use queuefamily scope in new model, device scope in old model 11916 spv::Scope memoryBarrierScope = glslangIntermediate -> usingVulkanMemoryModel () ? 11917 spv::Scope ::QueueFamilyKHR : spv::Scope ::Device ; 11918 11919switch (op ) { 11920case glslang::EOpBarrier : 11921if (glslangIntermediate -> getStage ()== EShLangTessControl ) { 11922if (glslangIntermediate -> usingVulkanMemoryModel ()) { 11923builder .createControlBarrier (spv::Scope ::Workgroup , spv::Scope ::Workgroup , 11924 spv::MemorySemanticsMask ::OutputMemoryKHR | 11925 spv::MemorySemanticsMask ::AcquireRelease ); 11926builder .addCapability (spv::Capability ::VulkanMemoryModelKHR ); 11927 }else { 11928builder .createControlBarrier (spv::Scope ::Workgroup , spv::Scope ::Invocation , spv::MemorySemanticsMask ::MaskNone ); 11929 } 11930 }else { 11931builder .createControlBarrier (spv::Scope ::Workgroup , spv::Scope ::Workgroup , 11932 spv::MemorySemanticsMask ::WorkgroupMemory | 11933 spv::MemorySemanticsMask ::AcquireRelease ); 11934 } 11935return 0 ; 11936case glslang::EOpControlBarrierArriveEXT : 11937builder .addExtension (spv::E_SPV_EXT_split_barrier ); 11938builder .addCapability (spv::Capability ::SplitBarrierEXT ); 11939if (glslangIntermediate -> usingVulkanMemoryModel ()) { 11940builder .addCapability (spv::Capability ::VulkanMemoryModelKHR ); 11941 } 11942builder .createSplitControlBarrier (spv::Op ::OpControlBarrierArriveEXT , spv::Scope ::Workgroup , spv::Scope ::Workgroup , 11943 spv::MemorySemanticsMask ::WorkgroupMemory | 11944 spv::MemorySemanticsMask ::Release ); 11945return 0 ; 11946case glslang::EOpControlBarrierWaitEXT : 11947builder .addExtension (spv::E_SPV_EXT_split_barrier ); 11948builder .addCapability (spv::Capability ::SplitBarrierEXT ); 11949if (glslangIntermediate -> usingVulkanMemoryModel ()) { 11950builder .addCapability (spv::Capability ::VulkanMemoryModelKHR ); 11951 } 11952builder .createSplitControlBarrier (spv::Op ::OpControlBarrierWaitEXT , spv::Scope ::Workgroup , spv::Scope ::Workgroup , 11953 spv::MemorySemanticsMask ::WorkgroupMemory | 11954 spv::MemorySemanticsMask ::Acquire ); 11955return 0 ; 11956case glslang::EOpMemoryBarrier : 11957builder .createMemoryBarrier (memoryBarrierScope , spv::MemorySemanticsAllMemory | 11958 spv::MemorySemanticsMask ::AcquireRelease ); 11959return 0 ; 11960case glslang::EOpMemoryBarrierBuffer : 11961builder .createMemoryBarrier (memoryBarrierScope , spv::MemorySemanticsMask ::UniformMemory | 11962 spv::MemorySemanticsMask ::AcquireRelease ); 11963return 0 ; 11964case glslang::EOpMemoryBarrierShared : 11965builder .createMemoryBarrier (memoryBarrierScope , spv::MemorySemanticsMask ::WorkgroupMemory | 11966 spv::MemorySemanticsMask ::AcquireRelease ); 11967return 0 ; 11968case glslang::EOpGroupMemoryBarrier : 11969builder .createMemoryBarrier (spv::Scope ::Workgroup , spv::MemorySemanticsAllMemory | 11970 spv::MemorySemanticsMask ::AcquireRelease ); 11971return 0 ; 11972case glslang::EOpMemoryBarrierAtomicCounter : 11973builder .createMemoryBarrier (memoryBarrierScope , spv::MemorySemanticsMask ::AtomicCounterMemory | 11974 spv::MemorySemanticsMask ::AcquireRelease ); 11975return 0 ; 11976case glslang::EOpMemoryBarrierImage : 11977builder .createMemoryBarrier (memoryBarrierScope , spv::MemorySemanticsMask ::ImageMemory | 11978 spv::MemorySemanticsMask ::AcquireRelease ); 11979return 0 ; 11980case glslang::EOpAllMemoryBarrierWithGroupSync : 11981builder .createControlBarrier (spv::Scope ::Workgroup , spv::Scope ::Device , 11982 spv::MemorySemanticsAllMemory | 11983 spv::MemorySemanticsMask ::AcquireRelease ); 11984return 0 ; 11985case glslang::EOpDeviceMemoryBarrier : 11986builder .createMemoryBarrier (spv::Scope ::Device , spv::MemorySemanticsMask ::UniformMemory | 11987 spv::MemorySemanticsMask ::ImageMemory | 11988 spv::MemorySemanticsMask ::AcquireRelease ); 11989return 0 ; 11990case glslang::EOpDeviceMemoryBarrierWithGroupSync : 11991builder .createControlBarrier (spv::Scope ::Workgroup , spv::Scope ::Device , spv::MemorySemanticsMask ::UniformMemory | 11992 spv::MemorySemanticsMask ::ImageMemory | 11993 spv::MemorySemanticsMask ::AcquireRelease ); 11994return 0 ; 11995case glslang::EOpWorkgroupMemoryBarrier : 11996builder .createMemoryBarrier (spv::Scope ::Workgroup , spv::MemorySemanticsMask ::WorkgroupMemory | 11997 spv::MemorySemanticsMask ::AcquireRelease ); 11998return 0 ; 11999case glslang::EOpWorkgroupMemoryBarrierWithGroupSync : 12000builder .createControlBarrier (spv::Scope ::Workgroup , spv::Scope ::Workgroup , 12001 spv::MemorySemanticsMask ::WorkgroupMemory | 12002 spv::MemorySemanticsMask ::AcquireRelease ); 12003return 0 ; 12004case glslang::EOpSubgroupBarrier : 12005builder .createControlBarrier (spv::Scope ::Subgroup , spv::Scope ::Subgroup , spv::MemorySemanticsAllMemory | 12006 spv::MemorySemanticsMask ::AcquireRelease ); 12007return spv::NoResult ; 12008case glslang::EOpSubgroupMemoryBarrier : 12009builder .createMemoryBarrier (spv::Scope ::Subgroup , spv::MemorySemanticsAllMemory | 12010 spv::MemorySemanticsMask ::AcquireRelease ); 12011return spv::NoResult ; 12012case glslang::EOpSubgroupMemoryBarrierBuffer : 12013builder .createMemoryBarrier (spv::Scope ::Subgroup , spv::MemorySemanticsMask ::UniformMemory | 12014 spv::MemorySemanticsMask ::AcquireRelease ); 12015return spv::NoResult ; 12016case glslang::EOpSubgroupMemoryBarrierImage : 12017builder .createMemoryBarrier (spv::Scope ::Subgroup , spv::MemorySemanticsMask ::ImageMemory | 12018 spv::MemorySemanticsMask ::AcquireRelease ); 12019return spv::NoResult ; 12020case glslang::EOpSubgroupMemoryBarrierShared : 12021builder .createMemoryBarrier (spv::Scope ::Subgroup , spv::MemorySemanticsMask ::WorkgroupMemory | 12022 spv::MemorySemanticsMask ::AcquireRelease ); 12023return spv::NoResult ; 12024 12025case glslang::EOpEmitVertex : 12026builder .createNoResultOp (spv::Op ::OpEmitVertex ); 12027return 0 ; 12028case glslang::EOpEndPrimitive : 12029builder .createNoResultOp (spv::Op ::OpEndPrimitive ); 12030return 0 ; 12031 12032case glslang::EOpSubgroupElect : { 12033 std::vector < spv::Id > operands ; 12034return createSubgroupOperation (op ,typeId ,operands , glslang::EbtVoid ); 12035 } 12036case glslang::EOpTime : 12037 { 12038 std::vector < spv::Id > args ;// Dummy arguments 12039 spv::Id id = builder .createBuiltinCall (typeId ,getExtBuiltins (spv::E_SPV_AMD_gcn_shader ), spv::TimeAMD ,args ); 12040return builder .setPrecision (id ,precision ); 12041 } 12042case glslang::EOpIgnoreIntersectionNV : 12043builder .createNoResultOp (spv::Op ::OpIgnoreIntersectionNV ); 12044return 0 ; 12045case glslang::EOpTerminateRayNV : 12046builder .createNoResultOp (spv::Op ::OpTerminateRayNV ); 12047return 0 ; 12048case glslang::EOpRayQueryInitialize : 12049builder .createNoResultOp (spv::Op ::OpRayQueryInitializeKHR ); 12050return 0 ; 12051case glslang::EOpRayQueryTerminate : 12052builder .createNoResultOp (spv::Op ::OpRayQueryTerminateKHR ); 12053return 0 ; 12054case glslang::EOpRayQueryGenerateIntersection : 12055builder .createNoResultOp (spv::Op ::OpRayQueryGenerateIntersectionKHR ); 12056return 0 ; 12057case glslang::EOpRayQueryConfirmIntersection : 12058builder .createNoResultOp (spv::Op ::OpRayQueryConfirmIntersectionKHR ); 12059return 0 ; 12060case glslang::EOpBeginInvocationInterlock : 12061builder .createNoResultOp (spv::Op ::OpBeginInvocationInterlockEXT ); 12062return 0 ; 12063case glslang::EOpEndInvocationInterlock : 12064builder .createNoResultOp (spv::Op ::OpEndInvocationInterlockEXT ); 12065return 0 ; 12066 12067case glslang::EOpIsHelperInvocation : 12068 { 12069 std::vector < spv::Id > args ;// Dummy arguments 12070builder .addExtension (spv::E_SPV_EXT_demote_to_helper_invocation ); 12071builder .addCapability (spv::Capability ::DemoteToHelperInvocationEXT ); 12072return builder .createOp (spv::Op ::OpIsHelperInvocationEXT ,typeId ,args ); 12073 } 12074 12075case glslang::EOpReadClockSubgroupKHR : { 12076 std::vector < spv::Id > args ; 12077args .push_back (builder .makeUintConstant (spv::Scope ::Subgroup )); 12078builder .addExtension (spv::E_SPV_KHR_shader_clock ); 12079builder .addCapability (spv::Capability ::ShaderClockKHR ); 12080return builder .createOp (spv::Op ::OpReadClockKHR ,typeId ,args ); 12081 } 12082 12083case glslang::EOpReadClockDeviceKHR : { 12084 std::vector < spv::Id > args ; 12085args .push_back (builder .makeUintConstant (spv::Scope ::Device )); 12086builder .addExtension (spv::E_SPV_KHR_shader_clock ); 12087builder .addCapability (spv::Capability ::ShaderClockKHR ); 12088return builder .createOp (spv::Op ::OpReadClockKHR ,typeId ,args ); 12089 } 12090case glslang::EOpStencilAttachmentReadEXT : 12091case glslang::EOpDepthAttachmentReadEXT : 12092 { 12093builder .addExtension (spv::E_SPV_EXT_shader_tile_image ); 12094 12095 spv::Decoration precision ; 12096 spv::Op spv_op ; 12097if (op == glslang::EOpStencilAttachmentReadEXT ) 12098 { 12099precision = spv::Decoration ::RelaxedPrecision ; 12100spv_op = spv::Op ::OpStencilAttachmentReadEXT ; 12101builder .addCapability (spv::Capability ::TileImageStencilReadAccessEXT ); 12102 } 12103else 12104 { 12105precision = spv::NoPrecision ; 12106spv_op = spv::Op ::OpDepthAttachmentReadEXT ; 12107builder .addCapability (spv::Capability ::TileImageDepthReadAccessEXT ); 12108 } 12109 12110 std::vector < spv::Id > args ;// Dummy args 12111 spv::Id result = builder .createOp (spv_op ,typeId ,args ); 12112return builder .setPrecision (result ,precision ); 12113 } 12114default : 12115break ; 12116 } 12117 12118logger -> missingFunctionality ("unknown operation with no arguments" ); 12119 12120return 0 ; 12121} 12122 12123spv::Id TGlslangToSpvTraverser ::getSymbolId (const glslang::TIntermSymbol * symbol ) 12124{ 12125auto iter = symbolValues .find (symbol -> getId ()); 12126 spv::Id id ; 12127if (symbolValues .end ()!= iter ) { 12128id = iter -> second ; 12129return id ; 12130 } 12131 12132// it was not found, create it 12133 spv::BuiltIn builtIn = TranslateBuiltInDecoration (symbol -> getQualifier ().builtIn , false); 12134auto forcedType = getForcedType (symbol -> getQualifier ().builtIn ,symbol -> getType ()); 12135 12136// There are pairs of symbols that map to the same SPIR-V built-in: 12137// gl_ObjectToWorldEXT and gl_ObjectToWorld3x4EXT, and gl_WorldToObjectEXT 12138// and gl_WorldToObject3x4EXT. SPIR-V forbids having two OpVariables 12139// with the same BuiltIn in the same storage class, so we must re-use one. 12140const bool mayNeedToReuseBuiltIn = 12141builtIn == spv::BuiltIn ::ObjectToWorldKHR || 12142builtIn == spv::BuiltIn ::WorldToObjectKHR ; 12143 12144// EXT_descriptor_heap 12145const bool needToRemapDescHeap = 12146builtIn == spv::BuiltIn ::ResourceHeapEXT || builtIn == spv::BuiltIn ::SamplerHeapEXT ; 12147 12148if (mayNeedToReuseBuiltIn || needToRemapDescHeap ) { 12149auto iter = builtInVariableIds .find (uint32_t (builtIn )); 12150if (builtInVariableIds .end ()!= iter ) { 12151id = iter -> second ; 12152symbolValues [symbol -> getId ()]= id ; 12153if (forcedType .second != spv::NoType ) 12154forceType [id ]= forcedType .second ; 12155return id ; 12156 } 12157 } 12158 12159if (symbol -> getBasicType ()== glslang::EbtFunction ) { 12160return 0 ; 12161 } 12162 12163id = createSpvVariable (symbol ,forcedType .first ); 12164 12165if (mayNeedToReuseBuiltIn ) { 12166builtInVariableIds .insert ({uint32_t (builtIn ),id }); 12167 } 12168 12169symbolValues [symbol -> getId ()]= id ; 12170if (forcedType .second != spv::NoType ) 12171forceType [id ]= forcedType .second ; 12172 12173if (symbol -> getBasicType ()!= glslang::EbtBlock ) { 12174builder .addDecoration (id ,TranslatePrecisionDecoration (symbol -> getType ())); 12175builder .addDecoration (id ,TranslateInterpolationDecoration (symbol -> getType ().getQualifier ())); 12176builder .addDecoration (id ,TranslateAuxiliaryStorageDecoration (symbol -> getType ().getQualifier ())); 12177addMeshNVDecoration (id ,/*member*/ -1 ,symbol -> getType ().getQualifier ()); 12178if (symbol -> getQualifier ().hasComponent ()) 12179builder .addDecoration (id , spv::Decoration ::Component ,symbol -> getQualifier ().layoutComponent ); 12180if (symbol -> getQualifier ().hasIndex ()) 12181builder .addDecoration (id , spv::Decoration ::Index ,symbol -> getQualifier ().layoutIndex ); 12182if (symbol -> getType ().getQualifier ().hasSpecConstantId ()) { 12183builder .addDecoration (id , spv::Decoration ::SpecId ,symbol -> getType ().getQualifier ().layoutSpecConstantId ); 12184// GL_EXT_opacity_micromap_ray_query_mode: if gl_EnableOpacityMicromapEXT is materialized (i.e. 12185// it is read somewhere), remember its spec constant so finishSpv() references this same one for 12186// the OpacityMicromapIdKHR execution mode rather than synthesizing a duplicate SpecId. 12187if (glslangIntermediate -> getEnableOpacityMicromapSpecId ()!= glslang::TQualifier ::layoutNotSet && 12188symbol -> getName ()== "gl_EnableOpacityMicromapEXT" ) 12189opacityMicromapEnableConstId = id ; 12190 } 12191// atomic counters use this: 12192if (symbol -> getQualifier ().hasOffset ()) 12193builder .addDecoration (id , spv::Decoration ::Offset ,symbol -> getQualifier ().layoutOffset ); 12194 } 12195 12196if (symbol -> getQualifier ().hasLocation ()) { 12197if (!(glslangIntermediate -> isRayTracingStage ()&& 12198 (glslangIntermediate -> IsRequestedExtension (glslang::E_GL_EXT_ray_tracing )|| 12199glslangIntermediate -> IsRequestedExtension (glslang::E_GL_NV_shader_invocation_reorder )|| 12200glslangIntermediate -> IsRequestedExtension (glslang::E_GL_EXT_shader_invocation_reorder )) 12201&& (builder .getStorageClass (id )== spv::StorageClass ::RayPayloadKHR || 12202builder .getStorageClass (id )== spv::StorageClass ::IncomingRayPayloadKHR || 12203builder .getStorageClass (id )== spv::StorageClass ::CallableDataKHR || 12204builder .getStorageClass (id )== spv::StorageClass ::IncomingCallableDataKHR || 12205builder .getStorageClass (id )== spv::StorageClass ::HitObjectAttributeEXT || 12206builder .getStorageClass (id )== spv::StorageClass ::HitObjectAttributeNV ))) { 12207// Location values are used to link TraceRayKHR/ExecuteCallableKHR/HitObjectGetAttributesNV 12208// to corresponding variables but are not valid in SPIRV since they are supported only 12209// for Input/Output Storage classes. 12210builder .addDecoration (id , spv::Decoration ::Location ,symbol -> getQualifier ().layoutLocation ); 12211 } 12212 } 12213 12214builder .addDecoration (id ,TranslateInvariantDecoration (symbol -> getType ().getQualifier ())); 12215if (symbol -> getQualifier ().hasStream ()&& glslangIntermediate -> isMultiStream ()) { 12216builder .addCapability (spv::Capability ::GeometryStreams ); 12217builder .addDecoration (id , spv::Decoration ::Stream ,symbol -> getQualifier ().layoutStream ); 12218 } 12219if (symbol -> getQualifier ().hasSet ()) 12220builder .addDecoration (id , spv::Decoration ::DescriptorSet ,symbol -> getQualifier ().layoutSet ); 12221else if (IsDescriptorResource (symbol -> getType ())) { 12222// default to 0 12223builder .addDecoration (id , spv::Decoration ::DescriptorSet ,0 ); 12224 } 12225if (symbol -> getQualifier ().hasBinding ()) 12226builder .addDecoration (id , spv::Decoration ::Binding ,symbol -> getQualifier ().layoutBinding ); 12227else if (IsDescriptorResource (symbol -> getType ())) { 12228// default to 0 12229builder .addDecoration (id , spv::Decoration ::Binding ,0 ); 12230 } 12231if (symbol -> getQualifier ().hasAttachment ()) 12232builder .addDecoration (id , spv::Decoration ::InputAttachmentIndex ,symbol -> getQualifier ().layoutAttachment ); 12233if (glslangIntermediate -> getXfbMode ()) { 12234builder .addCapability (spv::Capability ::TransformFeedback ); 12235if (symbol -> getQualifier ().hasXfbBuffer ()) { 12236builder .addDecoration (id , spv::Decoration ::XfbBuffer ,symbol -> getQualifier ().layoutXfbBuffer ); 12237unsigned stride = glslangIntermediate -> getXfbStride (symbol -> getQualifier ().layoutXfbBuffer ); 12238if (stride != glslang::TQualifier ::layoutXfbStrideEnd ) 12239builder .addDecoration (id , spv::Decoration ::XfbStride ,stride ); 12240 } 12241if (symbol -> getQualifier ().hasXfbOffset ()) 12242builder .addDecoration (id , spv::Decoration ::Offset ,symbol -> getQualifier ().layoutXfbOffset ); 12243 } 12244 12245// add built-in variable decoration 12246if (builtIn != spv::BuiltIn ::Max ) { 12247// WorkgroupSize deprecated in spirv1.6 12248if (glslangIntermediate -> getSpv ().spv < glslang::EShTargetSpv_1_6 || 12249builtIn != spv::BuiltIn ::WorkgroupSize ) 12250builder .addDecoration (id , spv::Decoration ::BuiltIn , (int )builtIn ); 12251 } 12252 12253// Add volatile decoration to HelperInvocation for spirv1.6 and beyond 12254if (builtIn == spv::BuiltIn ::HelperInvocation && 12255 !glslangIntermediate -> usingVulkanMemoryModel ()&& 12256glslangIntermediate -> getSpv ().spv >= glslang::EShTargetSpv_1_6 ) { 12257builder .addDecoration (id , spv::Decoration ::Volatile ); 12258 } 12259 12260// Subgroup builtins which have input storage class are volatile for ray tracing stages. 12261if (symbol -> getType ().isImage ()|| symbol -> getQualifier ().isPipeInput ()) { 12262 std::vector < spv::Decoration > memory ; 12263TranslateMemoryDecoration (symbol -> getType ().getQualifier (),memory , 12264glslangIntermediate -> usingVulkanMemoryModel ()); 12265for (unsigned int i = 0 ;i < memory .size ();++ i ) 12266builder .addDecoration (id ,memory [i ]); 12267 } 12268 12269if (builtIn == spv::BuiltIn ::SampleMask ) { 12270 spv::Decoration decoration ; 12271// GL_NV_sample_mask_override_coverage extension 12272if (glslangIntermediate -> getLayoutOverrideCoverage ()) 12273decoration = spv::Decoration ::OverrideCoverageNV ; 12274else 12275decoration = spv::Decoration ::Max ; 12276builder .addDecoration (id ,decoration ); 12277if (decoration != spv::Decoration ::Max ) { 12278builder .addCapability (spv::Capability ::SampleMaskOverrideCoverageNV ); 12279builder .addExtension (spv::E_SPV_NV_sample_mask_override_coverage ); 12280 } 12281 } 12282else if (builtIn == spv::BuiltIn ::Layer ) { 12283// SPV_NV_viewport_array2 extension 12284if (symbol -> getQualifier ().layoutViewportRelative ) { 12285builder .addDecoration (id , spv::Decoration ::ViewportRelativeNV ); 12286builder .addCapability (spv::Capability ::ShaderViewportMaskNV ); 12287builder .addExtension (spv::E_SPV_NV_viewport_array2 ); 12288 } 12289if (symbol -> getQualifier ().layoutSecondaryViewportRelativeOffset != -2048 ) { 12290builder .addDecoration (id , spv::Decoration ::SecondaryViewportRelativeNV , 12291symbol -> getQualifier ().layoutSecondaryViewportRelativeOffset ); 12292builder .addCapability (spv::Capability ::ShaderStereoViewNV ); 12293builder .addExtension (spv::E_SPV_NV_stereo_view_rendering ); 12294 } 12295 } 12296 12297if (symbol -> getQualifier ().layoutPassthrough ) { 12298builder .addDecoration (id , spv::Decoration ::PassthroughNV ); 12299builder .addCapability (spv::Capability ::GeometryShaderPassthroughNV ); 12300builder .addExtension (spv::E_SPV_NV_geometry_shader_passthrough ); 12301 } 12302if (symbol -> getQualifier ().pervertexNV ) { 12303builder .addDecoration (id , spv::Decoration ::PerVertexNV ); 12304builder .addCapability (spv::Capability ::FragmentBarycentricNV ); 12305builder .addExtension (spv::E_SPV_NV_fragment_shader_barycentric ); 12306 } 12307 12308if (symbol -> getQualifier ().pervertexEXT ) { 12309builder .addDecoration (id , spv::Decoration ::PerVertexKHR ); 12310builder .addCapability (spv::Capability ::FragmentBarycentricKHR ); 12311builder .addExtension (spv::E_SPV_KHR_fragment_shader_barycentric ); 12312 } 12313 12314if (glslangIntermediate -> getHlslFunctionality1 ()&& symbol -> getType ().getQualifier ().semanticName != nullptr ) { 12315builder .addExtension ("SPV_GOOGLE_hlsl_functionality1" ); 12316builder .addDecoration (id , spv::Decoration ::HlslSemanticGOOGLE , 12317symbol -> getType ().getQualifier ().semanticName ); 12318 } 12319 12320if (symbol -> isReference ()) { 12321builder .addDecoration (id ,symbol -> getType ().getQualifier ().restrict ? 12322 spv::Decoration ::RestrictPointerEXT : spv::Decoration ::AliasedPointerEXT ); 12323 } 12324 12325// Add SPIR-V decorations (GL_EXT_spirv_intrinsics) 12326if (symbol -> getType ().getQualifier ().hasSpirvDecorate ()) 12327applySpirvDecorate (symbol -> getType (),id , {}); 12328 12329if (symbol -> getQualifier ().hasBank ()) { 12330builder .addExtension (spv::E_SPV_NV_push_constant_bank ); 12331builder .addCapability (spv::Capability ::PushConstantBanksNV ); 12332builder .addDecoration (id , spv::Decoration ::BankNV ,symbol -> getQualifier ().layoutBank ); 12333 } 12334 12335if (symbol -> getQualifier ().hasMemberOffset ()) { 12336builder .addExtension (spv::E_SPV_NV_push_constant_bank ); 12337builder .addCapability (spv::Capability ::PushConstantBanksNV ); 12338builder .addDecoration (id , spv::Decoration ::MemberOffsetNV ,symbol -> getQualifier ().layoutMemberOffset ); 12339 } 12340 12341return id ; 12342} 12343 12344// add per-primitive, per-view. per-task decorations to a struct member (member >= 0) or an object 12345void TGlslangToSpvTraverser ::addMeshNVDecoration (spv::Id id ,int member ,const glslang::TQualifier & qualifier ) 12346{ 12347bool isMeshShaderExt = (glslangIntermediate -> getRequestedExtensions ().find (glslang::E_GL_EXT_mesh_shader )!= 12348glslangIntermediate -> getRequestedExtensions ().end ()); 12349 12350if (member >=0 ) { 12351if (qualifier .perPrimitiveNV ) { 12352// Need to add capability/extension for fragment shader. 12353// Mesh shader already adds this by default. 12354if (glslangIntermediate -> getStage ()== EShLangFragment ) { 12355if (isMeshShaderExt ) { 12356builder .addCapability (spv::Capability ::MeshShadingEXT ); 12357builder .addExtension (spv::E_SPV_EXT_mesh_shader ); 12358 }else { 12359builder .addCapability (spv::Capability ::MeshShadingNV ); 12360builder .addExtension (spv::E_SPV_NV_mesh_shader ); 12361 } 12362 } 12363builder .addMemberDecoration (id , (unsigned )member , spv::Decoration ::PerPrimitiveNV ); 12364 } 12365if (qualifier .perViewNV ) 12366builder .addMemberDecoration (id , (unsigned )member , spv::Decoration ::PerViewNV ); 12367if (qualifier .perTaskNV ) 12368builder .addMemberDecoration (id , (unsigned )member , spv::Decoration ::PerTaskNV ); 12369 }else { 12370if (qualifier .perPrimitiveNV ) { 12371// Need to add capability/extension for fragment shader. 12372// Mesh shader already adds this by default. 12373if (glslangIntermediate -> getStage ()== EShLangFragment ) { 12374if (isMeshShaderExt ) { 12375builder .addCapability (spv::Capability ::MeshShadingEXT ); 12376builder .addExtension (spv::E_SPV_EXT_mesh_shader ); 12377 }else { 12378builder .addCapability (spv::Capability ::MeshShadingNV ); 12379builder .addExtension (spv::E_SPV_NV_mesh_shader ); 12380 } 12381 } 12382builder .addDecoration (id , spv::Decoration ::PerPrimitiveNV ); 12383 } 12384if (qualifier .perViewNV ) 12385builder .addDecoration (id , spv::Decoration ::PerViewNV ); 12386if (qualifier .perTaskNV ) 12387builder .addDecoration (id , spv::Decoration ::PerTaskNV ); 12388 } 12389} 12390 12391bool TGlslangToSpvTraverser ::hasQCOMImageProceessingDecoration (spv::Id id , spv::Decoration decor ) 12392{ 12393 std::vector < spv::Decoration > & decoVec = idToQCOMDecorations [id ]; 12394for (auto d :decoVec ) { 12395if (d == decor ) 12396return true; 12397 } 12398return false; 12399} 12400 12401void TGlslangToSpvTraverser ::addImageProcessingQCOMDecoration (spv::Id id , spv::Decoration decor ) 12402{ 12403 spv::Op opc = builder .getOpCode (id ); 12404if (opc == spv::Op ::OpSampledImage ) { 12405id = builder .getIdOperand (id ,0 ); 12406opc = builder .getOpCode (id ); 12407 } 12408 12409if (opc == spv::Op ::OpLoad ) { 12410 spv::Id texid = builder .getIdOperand (id ,0 ); 12411if (!hasQCOMImageProceessingDecoration (texid ,decor )) {// 12412builder .addDecoration (texid ,decor ); 12413idToQCOMDecorations [texid ].push_back (decor ); 12414 } 12415 } 12416} 12417 12418void TGlslangToSpvTraverser ::addImageProcessing2QCOMDecoration (spv::Id id ,bool isForGather ) 12419{ 12420if (isForGather ) { 12421return addImageProcessingQCOMDecoration (id , spv::Decoration ::BlockMatchTextureQCOM ); 12422 } 12423 12424auto addDecor = 12425 [this ](spv::Id id , spv::Decoration decor ) { 12426 spv::Op tsopc = this -> builder .getOpCode (id ); 12427if (tsopc == spv::Op ::OpLoad ) { 12428 spv::Id tsid = this -> builder .getIdOperand (id ,0 ); 12429if (this -> glslangIntermediate -> getSpv ().spv >= glslang::EShTargetSpv_1_4 ) { 12430assert (iOSet .count (tsid )> 0 ); 12431 } 12432if (!hasQCOMImageProceessingDecoration (tsid ,decor )) { 12433this -> builder .addDecoration (tsid ,decor ); 12434idToQCOMDecorations [tsid ].push_back (decor ); 12435 } 12436 } 12437 }; 12438 12439 spv::Op opc = builder .getOpCode (id ); 12440bool isInterfaceObject = (opc != spv::Op ::OpSampledImage ); 12441 12442if (!isInterfaceObject ) { 12443addDecor (builder .getIdOperand (id ,0 ), spv::Decoration ::BlockMatchTextureQCOM ); 12444addDecor (builder .getIdOperand (id ,1 ), spv::Decoration ::BlockMatchSamplerQCOM ); 12445 }else { 12446addDecor (id , spv::Decoration ::BlockMatchTextureQCOM ); 12447addDecor (id , spv::Decoration ::BlockMatchSamplerQCOM ); 12448 } 12449} 12450 12451// Make a full tree of instructions to build a SPIR-V specialization constant, 12452// or regular constant if possible. 12453// 12454// TBD: this is not yet done, nor verified to be the best design, it does do the leaf symbols though 12455// 12456// Recursively walk the nodes. The nodes form a tree whose leaves are 12457// regular constants, which themselves are trees that createSpvConstant() 12458// recursively walks. So, this function walks the "top" of the tree: 12459// - emit specialization constant-building instructions for specConstant 12460// - when running into a non-spec-constant, switch to createSpvConstant() 12461spv::Id TGlslangToSpvTraverser ::createSpvConstant (const glslang::TIntermTyped & node ) 12462{ 12463assert (node .getQualifier ().isConstant ()); 12464 12465// Handle front-end constants first (non-specialization constants). 12466if (!node .getQualifier ().specConstant ) { 12467// hand off to the non-spec-constant path 12468assert (node .getAsConstantUnion ()!= nullptr || node .getAsSymbolNode ()!= nullptr ); 12469int nextConst = 0 ; 12470return createSpvConstantFromConstUnionArray (node .getType (),node .getAsConstantUnion () ? 12471node .getAsConstantUnion ()-> getConstArray () :node .getAsSymbolNode ()-> getConstArray (), 12472nextConst , false); 12473 } 12474 12475// We now know we have a specialization constant to build 12476 12477// Extra capabilities may be needed. 12478if (node .getType ().contains8BitInt ()) 12479builder .addCapability (spv::Capability ::Int8 ); 12480if (node .getType ().contains16BitFloat ()) 12481builder .addCapability (spv::Capability ::Float16 ); 12482if (node .getType ().contains16BitInt ()) 12483builder .addCapability (spv::Capability ::Int16 ); 12484if (node .getType ().contains64BitInt ()) 12485builder .addCapability (spv::Capability ::Int64 ); 12486if (node .getType ().containsDouble ()) 12487builder .addCapability (spv::Capability ::Float64 ); 12488 12489// gl_WorkGroupSize is a special case until the front-end handles hierarchical specialization constants, 12490// even then, it's specialization ids are handled by special case syntax in GLSL: layout(local_size_x = ... 12491if (node .getType ().getQualifier ().builtIn == glslang::EbvWorkGroupSize ) { 12492 std::vector < spv::Id > dimConstId ; 12493for (int dim = 0 ;dim < 3 ;++ dim ) { 12494bool specConst = (glslangIntermediate -> getLocalSizeSpecId (dim )!= glslang::TQualifier ::layoutNotSet ); 12495dimConstId .push_back (builder .makeUintConstant (glslangIntermediate -> getLocalSize (dim ),specConst )); 12496if (specConst ) { 12497builder .addDecoration (dimConstId .back (), spv::Decoration ::SpecId , 12498glslangIntermediate -> getLocalSizeSpecId (dim )); 12499 } 12500 } 12501return builder .makeCompositeConstant (builder .makeVectorType (builder .makeUintType (32 ),3 ),dimConstId , true); 12502 } 12503 12504// An AST node labelled as specialization constant should be a symbol node. 12505// Its initializer should either be a sub tree with constant nodes, or a constant union array. 12506if (auto * sn = node .getAsSymbolNode ()) { 12507 spv::Id result ; 12508if (auto * sub_tree = sn -> getConstSubtree ()) { 12509// Traverse the constant constructor sub tree like generating normal run-time instructions. 12510// During the AST traversal, if the node is marked as 'specConstant', SpecConstantOpModeGuard 12511// will set the builder into spec constant op instruction generating mode. 12512sub_tree -> traverse (this ); 12513result = accessChainLoad (sub_tree -> getType ()); 12514 }else if (auto * const_union_array = & sn -> getConstArray ()) { 12515int nextConst = 0 ; 12516result = createSpvConstantFromConstUnionArray (sn -> getType (),* const_union_array ,nextConst , true); 12517 }else { 12518logger -> missingFunctionality ("Invalid initializer for spec constant." ); 12519return spv::NoResult ; 12520 } 12521builder .addName (result ,sn -> getName ().c_str ()); 12522return result ; 12523 } 12524 12525// Neither a front-end constant node, nor a specialization constant node with constant union array or 12526// constant sub tree as initializer. 12527logger -> missingFunctionality ("Neither a front-end constant nor a spec constant." ); 12528return spv::NoResult ; 12529} 12530 12531// Use 'consts' as the flattened glslang source of scalar constants to recursively 12532// build the aggregate SPIR-V constant. 12533// 12534// If there are not enough elements present in 'consts', 0 will be substituted; 12535// an empty 'consts' can be used to create a fully zeroed SPIR-V constant. 12536// 12537spv::Id TGlslangToSpvTraverser ::createSpvConstantFromConstUnionArray (const glslang::TType & glslangType , 12538const glslang::TConstUnionArray & consts ,int & nextConst ,bool specConstant ) 12539{ 12540// vector of constants for SPIR-V 12541 std::vector < spv::Id > spvConsts ; 12542 12543// Type is used for struct and array constants 12544 spv::Id typeId = convertGlslangToSpvType (glslangType ); 12545 12546if (glslangType .isArray ()) { 12547 glslang::TType elementType (glslangType ,0 ); 12548for (int i = 0 ;i < glslangType .getOuterArraySize ();++ i ) 12549spvConsts .push_back (createSpvConstantFromConstUnionArray (elementType ,consts ,nextConst , false)); 12550 }else if (glslangType .isMatrix ()) { 12551 glslang::TType vectorType (glslangType ,0 ); 12552for (int col = 0 ;col < glslangType .getMatrixCols ();++ col ) 12553spvConsts .push_back (createSpvConstantFromConstUnionArray (vectorType ,consts ,nextConst , false)); 12554 }else if (glslangType .isCoopMat ()) { 12555 glslang::TType componentType (glslangType .getBasicType ()); 12556spvConsts .push_back (createSpvConstantFromConstUnionArray (componentType ,consts ,nextConst , false)); 12557 }else if (glslangType .isStruct ()) { 12558 glslang::TVector < glslang::TTypeLoc > ::const_iterator iter ; 12559for (iter = glslangType .getStruct ()-> begin ();iter != glslangType .getStruct ()-> end ();++ iter ) 12560spvConsts .push_back (createSpvConstantFromConstUnionArray (* iter -> type ,consts ,nextConst , false)); 12561 }else if (glslangType .getVectorSize ()> 1 || glslangType .isCoopVecOrLongVector ()) { 12562unsigned int numComponents = glslangType .isCoopVecOrLongVector () ?glslangType .getTypeParameters ()-> arraySizes -> getDimSize (0 ) :glslangType .getVectorSize (); 12563for (unsigned int i = 0 ;i < numComponents ;++ i ) { 12564bool zero = nextConst >=consts .size (); 12565switch (glslangType .getBasicType ()) { 12566case glslang::EbtInt : 12567spvConsts .push_back (builder .makeIntConstant (zero ?0 :consts [nextConst ].getIConst ())); 12568break ; 12569case glslang::EbtUint : 12570spvConsts .push_back (builder .makeUintConstant (zero ?0 :consts [nextConst ].getUConst ())); 12571break ; 12572case glslang::EbtFloat : 12573spvConsts .push_back (builder .makeFloatConstant (zero ?0.0F : (float )consts [nextConst ].getDConst ())); 12574break ; 12575case glslang::EbtBool : 12576spvConsts .push_back (builder .makeBoolConstant (zero ? false :consts [nextConst ].getBConst ())); 12577break ; 12578case glslang::EbtInt8 : 12579builder .addCapability (spv::Capability ::Int8 ); 12580spvConsts .push_back (builder .makeInt8Constant (zero ?0 :consts [nextConst ].getI8Const ())); 12581break ; 12582case glslang::EbtUint8 : 12583builder .addCapability (spv::Capability ::Int8 ); 12584spvConsts .push_back (builder .makeUint8Constant (zero ?0 :consts [nextConst ].getU8Const ())); 12585break ; 12586case glslang::EbtInt16 : 12587builder .addCapability (spv::Capability ::Int16 ); 12588spvConsts .push_back (builder .makeInt16Constant (zero ?0 :consts [nextConst ].getI16Const ())); 12589break ; 12590case glslang::EbtUint16 : 12591builder .addCapability (spv::Capability ::Int16 ); 12592spvConsts .push_back (builder .makeUint16Constant (zero ?0 :consts [nextConst ].getU16Const ())); 12593break ; 12594case glslang::EbtInt64 : 12595spvConsts .push_back (builder .makeInt64Constant (zero ?0 :consts [nextConst ].getI64Const ())); 12596break ; 12597case glslang::EbtUint64 : 12598spvConsts .push_back (builder .makeUint64Constant (zero ?0 :consts [nextConst ].getU64Const ())); 12599break ; 12600case glslang::EbtDouble : 12601spvConsts .push_back (builder .makeDoubleConstant (zero ?0.0 :consts [nextConst ].getDConst ())); 12602break ; 12603case glslang::EbtFloat16 : 12604builder .addCapability (spv::Capability ::Float16 ); 12605spvConsts .push_back (builder .makeFloat16Constant (zero ?0.0F : (float )consts [nextConst ].getDConst ())); 12606break ; 12607case glslang::EbtBFloat16 : 12608spvConsts .push_back (builder .makeBFloat16Constant (zero ?0.0F : (float )consts [nextConst ].getDConst ())); 12609break ; 12610case glslang::EbtFloatE5M2 : 12611spvConsts .push_back (builder .makeFloatE5M2Constant (zero ?0.0F : (float )consts [nextConst ].getDConst ())); 12612break ; 12613case glslang::EbtFloatE4M3 : 12614spvConsts .push_back (builder .makeFloatE4M3Constant (zero ?0.0F : (float )consts [nextConst ].getDConst ())); 12615break ; 12616case glslang::EbtFloatE2M1 : 12617spvConsts .push_back (builder .makeFloatE2M1Constant (zero ?0.0F : (float )consts [nextConst ].getDConst ())); 12618break ; 12619case glslang::EbtFloatE3M2 : 12620spvConsts .push_back (builder .makeFloatE3M2Constant (zero ?0.0F : (float )consts [nextConst ].getDConst ())); 12621break ; 12622case glslang::EbtFloatE2M3 : 12623spvConsts .push_back (builder .makeFloatE2M3Constant (zero ?0.0F : (float )consts [nextConst ].getDConst ())); 12624break ; 12625case glslang::EbtFloatUE8M0 : 12626spvConsts .push_back (builder .makeFloatUE8M0Constant (zero ?0.0F : (float )consts [nextConst ].getDConst ())); 12627break ; 12628case glslang::EbtFloatMXINT8 : 12629spvConsts .push_back (builder .makeFloatMXINT8Constant (zero ?0.0F : (float )consts [nextConst ].getDConst ())); 12630break ; 12631default : 12632assert (0 ); 12633break ; 12634 } 12635++ nextConst ; 12636 } 12637 }else { 12638// we have a non-aggregate (scalar) constant 12639bool zero = nextConst >=consts .size (); 12640 spv::Id scalar = 0 ; 12641switch (glslangType .getBasicType ()) { 12642case glslang::EbtInt : 12643scalar = builder .makeIntConstant (zero ?0 :consts [nextConst ].getIConst (),specConstant ); 12644break ; 12645case glslang::EbtUint : 12646scalar = builder .makeUintConstant (zero ?0 :consts [nextConst ].getUConst (),specConstant ); 12647break ; 12648case glslang::EbtFloat : 12649scalar = builder .makeFloatConstant (zero ?0.0F : (float )consts [nextConst ].getDConst (),specConstant ); 12650break ; 12651case glslang::EbtBool : 12652scalar = builder .makeBoolConstant (zero ? false :consts [nextConst ].getBConst (),specConstant ); 12653break ; 12654case glslang::EbtInt8 : 12655builder .addCapability (spv::Capability ::Int8 ); 12656scalar = builder .makeInt8Constant (zero ?0 :consts [nextConst ].getI8Const (),specConstant ); 12657break ; 12658case glslang::EbtUint8 : 12659builder .addCapability (spv::Capability ::Int8 ); 12660scalar = builder .makeUint8Constant (zero ?0 :consts [nextConst ].getU8Const (),specConstant ); 12661break ; 12662case glslang::EbtInt16 : 12663builder .addCapability (spv::Capability ::Int16 ); 12664scalar = builder .makeInt16Constant (zero ?0 :consts [nextConst ].getI16Const (),specConstant ); 12665break ; 12666case glslang::EbtUint16 : 12667builder .addCapability (spv::Capability ::Int16 ); 12668scalar = builder .makeUint16Constant (zero ?0 :consts [nextConst ].getU16Const (),specConstant ); 12669break ; 12670case glslang::EbtInt64 : 12671scalar = builder .makeInt64Constant (zero ?0 :consts [nextConst ].getI64Const (),specConstant ); 12672break ; 12673case glslang::EbtUint64 : 12674scalar = builder .makeUint64Constant (zero ?0 :consts [nextConst ].getU64Const (),specConstant ); 12675break ; 12676case glslang::EbtDouble : 12677scalar = builder .makeDoubleConstant (zero ?0.0 :consts [nextConst ].getDConst (),specConstant ); 12678break ; 12679case glslang::EbtFloat16 : 12680builder .addCapability (spv::Capability ::Float16 ); 12681scalar = builder .makeFloat16Constant (zero ?0.0F : (float )consts [nextConst ].getDConst (),specConstant ); 12682break ; 12683case glslang::EbtBFloat16 : 12684scalar = builder .makeBFloat16Constant (zero ?0.0F : (float )consts [nextConst ].getDConst (),specConstant ); 12685break ; 12686case glslang::EbtFloatE5M2 : 12687scalar = builder .makeFloatE5M2Constant (zero ?0.0F : (float )consts [nextConst ].getDConst (),specConstant ); 12688break ; 12689case glslang::EbtFloatE4M3 : 12690scalar = builder .makeFloatE4M3Constant (zero ?0.0F : (float )consts [nextConst ].getDConst (),specConstant ); 12691break ; 12692case glslang::EbtFloatE2M1 : 12693scalar = builder .makeFloatE2M1Constant (zero ?0.0F : (float )consts [nextConst ].getDConst (),specConstant ); 12694break ; 12695case glslang::EbtFloatE3M2 : 12696scalar = builder .makeFloatE3M2Constant (zero ?0.0F : (float )consts [nextConst ].getDConst (),specConstant ); 12697break ; 12698case glslang::EbtFloatE2M3 : 12699scalar = builder .makeFloatE2M3Constant (zero ?0.0F : (float )consts [nextConst ].getDConst (),specConstant ); 12700break ; 12701case glslang::EbtFloatUE8M0 : 12702scalar = builder .makeFloatUE8M0Constant (zero ?0.0F : (float )consts [nextConst ].getDConst (),specConstant ); 12703break ; 12704case glslang::EbtFloatMXINT8 : 12705scalar = builder .makeFloatMXINT8Constant (zero ?0.0F : (float )consts [nextConst ].getDConst (),specConstant ); 12706break ; 12707case glslang::EbtReference : 12708scalar = builder .makeUint64Constant (zero ?0 :consts [nextConst ].getU64Const (),specConstant ); 12709scalar = builder .createUnaryOp (spv::Op ::OpBitcast ,typeId ,scalar ); 12710break ; 12711case glslang::EbtString : 12712scalar = builder .getStringId (consts [nextConst ].getSConst ()-> c_str ()); 12713break ; 12714default : 12715assert (0 ); 12716break ; 12717 } 12718++ nextConst ; 12719return scalar ; 12720 } 12721 12722return builder .makeCompositeConstant (typeId ,spvConsts ); 12723} 12724 12725// Return true if the node is a constant or symbol whose reading has no 12726// non-trivial observable cost or effect. 12727bool TGlslangToSpvTraverser ::isTrivialLeaf (const glslang::TIntermTyped * node ) 12728{ 12729// don't know what this is 12730if (node == nullptr ) 12731return false; 12732 12733// a constant is safe 12734if (node -> getAsConstantUnion ()!= nullptr ) 12735return true; 12736 12737// not a symbol means non-trivial 12738if (node -> getAsSymbolNode ()== nullptr ) 12739return false; 12740 12741// a symbol, depends on what's being read 12742switch (node -> getType ().getQualifier ().storage ) { 12743case glslang::EvqTemporary : 12744case glslang::EvqGlobal : 12745case glslang::EvqIn : 12746case glslang::EvqInOut : 12747case glslang::EvqConst : 12748case glslang::EvqConstReadOnly : 12749case glslang::EvqUniform : 12750return true; 12751default : 12752return false; 12753 } 12754} 12755 12756// A node is trivial if it is a single operation with no side effects. 12757// HLSL (and/or vectors) are always trivial, as it does not short circuit. 12758// Otherwise, error on the side of saying non-trivial. 12759// Return true if trivial. 12760bool TGlslangToSpvTraverser ::isTrivial (const glslang::TIntermTyped * node ) 12761{ 12762if (node == nullptr ) 12763return false; 12764 12765// count non scalars as trivial, as well as anything coming from HLSL 12766if (!node -> getType ().isScalarOrVec1 ()|| glslangIntermediate -> getSource ()== glslang::EShSourceHlsl ) 12767return true; 12768 12769// symbols and constants are trivial 12770if (isTrivialLeaf (node )) 12771return true; 12772 12773// otherwise, it needs to be a simple operation or one or two leaf nodes 12774 12775// not a simple operation 12776const glslang::TIntermBinary * binaryNode = node -> getAsBinaryNode (); 12777const glslang::TIntermUnary * unaryNode = node -> getAsUnaryNode (); 12778if (binaryNode == nullptr && unaryNode == nullptr ) 12779return false; 12780 12781// not on leaf nodes 12782if (binaryNode && (!isTrivialLeaf (binaryNode -> getLeft ())|| !isTrivialLeaf (binaryNode -> getRight ()))) 12783return false; 12784 12785if (unaryNode && !isTrivialLeaf (unaryNode -> getOperand ())) { 12786return false; 12787 } 12788 12789if (IsOpNumericConv (node -> getAsOperator ()-> getOp ())&& 12790node -> getType ().getBasicType ()== glslang::EbtBool ) { 12791return true; 12792 } 12793 12794switch (node -> getAsOperator ()-> getOp ()) { 12795case glslang::EOpLogicalNot : 12796case glslang::EOpEqual : 12797case glslang::EOpNotEqual : 12798case glslang::EOpLessThan : 12799case glslang::EOpGreaterThan : 12800case glslang::EOpLessThanEqual : 12801case glslang::EOpGreaterThanEqual : 12802case glslang::EOpIndexDirect : 12803case glslang::EOpIndexDirectStruct : 12804case glslang::EOpLogicalXor : 12805case glslang::EOpAny : 12806case glslang::EOpAll : 12807return true; 12808default : 12809return false; 12810 } 12811} 12812 12813// Emit short-circuiting code, where 'right' is never evaluated unless 12814// the left side is true (for &&) or false (for ||). 12815spv::Id TGlslangToSpvTraverser ::createShortCircuit (glslang::TOperator op , glslang::TIntermTyped & left , 12816 glslang::TIntermTyped & right ) 12817{ 12818 spv::Id boolTypeId = builder .makeBoolType (); 12819 12820// emit left operand 12821builder .clearAccessChain (); 12822left .traverse (this ); 12823 spv::Id leftId = accessChainLoad (left .getType ()); 12824 12825// Operands to accumulate OpPhi operands 12826 std::vector < spv::Id > phiOperands ; 12827phiOperands .reserve (4 ); 12828// accumulate left operand's phi information 12829phiOperands .push_back (leftId ); 12830phiOperands .push_back (builder .getBuildPoint ()-> getId ()); 12831 12832// Make the two kinds of operation symmetric with a "!" 12833// || => emit "if (! left) result = right" 12834// && => emit "if ( left) result = right" 12835// 12836// TODO: this runtime "not" for || could be avoided by adding functionality 12837// to 'builder' to have an "else" without an "then" 12838if (op == glslang::EOpLogicalOr ) 12839leftId = builder .createUnaryOp (spv::Op ::OpLogicalNot ,boolTypeId ,leftId ); 12840 12841// make an "if" based on the left value 12842 spv::Builder ::If ifBuilder (leftId , spv::SelectionControlMask ::MaskNone ,builder ); 12843 12844// emit right operand as the "then" part of the "if" 12845builder .clearAccessChain (); 12846right .traverse (this ); 12847 spv::Id rightId = accessChainLoad (right .getType ()); 12848 12849// accumulate left operand's phi information 12850phiOperands .push_back (rightId ); 12851phiOperands .push_back (builder .getBuildPoint ()-> getId ()); 12852 12853// finish the "if" 12854ifBuilder .makeEndIf (); 12855 12856// phi together the two results 12857return builder .createOp (spv::Op ::OpPhi ,boolTypeId ,phiOperands ); 12858} 12859 12860// Return type Id of the imported set of extended instructions corresponds to the name. 12861// Import this set if it has not been imported yet. 12862spv::Id TGlslangToSpvTraverser ::getExtBuiltins (const char * name ) 12863{ 12864if (extBuiltinMap .find (name )!= extBuiltinMap .end ()) 12865return extBuiltinMap [name ]; 12866else { 12867 spv::Id extBuiltins = builder .import (name ); 12868extBuiltinMap [name ]= extBuiltins ; 12869return extBuiltins ; 12870 } 12871} 12872 12873void TGlslangToSpvTraverser ::enableCoopMatConversions () 12874{ 12875if (glslangIntermediate -> usingCoopMatMaint1 ()) { 12876builder .addCapability (spv::Capability ::CooperativeMatrixConversionsEXT ); 12877builder .addExtension (spv::E_SPV_EXT_cooperative_matrix_maintenance1 ); 12878 }else { 12879builder .addCapability (spv::Capability ::CooperativeMatrixConversionsNV ); 12880builder .addExtension (spv::E_SPV_NV_cooperative_matrix2 ); 12881 } 12882} 12883 12884}// end anonymous namespace 12885 12886namespace glslang { 12887 12888void GetSpirvVersion (std::string & version ) 12889{ 12890const int bufSize = 100 ; 12891char buf [bufSize ]; 12892snprintf (buf ,bufSize ,"0x%08x, Revision %d" , spv::Version , spv::Revision ); 12893version = buf ; 12894} 12895 12896// For low-order part of the generator's magic number. Bump up 12897// when there is a change in the style (e.g., if SSA form changes, 12898// or a different instruction sequence to do something gets used). 12899int GetSpirvGeneratorVersion () 12900{ 12901// return 1; // start 12902// return 2; // EOpAtomicCounterDecrement gets a post decrement, to map between GLSL -> SPIR-V 12903// return 3; // change/correct barrier-instruction operands, to match memory model group decisions 12904// return 4; // some deeper access chains: for dynamic vector component, and local Boolean component 12905// return 5; // make OpArrayLength result type be an int with signedness of 0 12906// return 6; // revert version 5 change, which makes a different (new) kind of incorrect code, 12907// versions 4 and 6 each generate OpArrayLength as it has long been done 12908// return 7; // GLSL volatile keyword maps to both SPIR-V decorations Volatile and Coherent 12909// return 8; // switch to new dead block eliminator; use OpUnreachable 12910// return 9; // don't include opaque function parameters in OpEntryPoint global's operand list 12911// return 10; // Generate OpFUnordNotEqual for != comparisons 12912return 11 ;// Make OpEmitMeshTasksEXT a terminal instruction 12913} 12914 12915// Write SPIR-V out to a binary file 12916bool OutputSpvBin (const std::vector < unsigned int >& spirv ,const char * baseName ) 12917{ 12918 std::ofstream out ; 12919out .open (baseName , std::ios::binary | std::ios::out ); 12920if (out .fail ()) { 12921printf ("ERROR: Failed to open file: %s\n" ,baseName ); 12922return false; 12923 } 12924for (int i = 0 ;i < (int )spirv .size ();++ i ) { 12925unsigned int word = spirv [i ]; 12926out .write ((const char * )& word ,4 ); 12927 } 12928out .close (); 12929return true; 12930} 12931 12932// Write SPIR-V out to a text file with 32-bit hexadecimal words 12933bool OutputSpvHex (const std::vector < unsigned int >& spirv ,const char * baseName ,const char * varName ) 12934{ 12935 std::ofstream out ; 12936out .open (baseName , std::ios::binary | std::ios::out ); 12937if (out .fail ()) { 12938printf ("ERROR: Failed to open file: %s\n" ,baseName ); 12939return false; 12940 } 12941out <<"\t// " << 12942GetSpirvGeneratorVersion () << 12943GLSLANG_VERSION_MAJOR <<"." <<GLSLANG_VERSION_MINOR <<"." <<GLSLANG_VERSION_PATCH << 12944GLSLANG_VERSION_FLAVOR << std::endl ; 12945if (varName != nullptr ) { 12946out <<"\t #pragma once" << std::endl ; 12947out <<"const uint32_t " <<varName <<"[] = {" << std::endl ; 12948 } 12949const int WORDS_PER_LINE = 8 ; 12950for (int i = 0 ;i < (int )spirv .size ();i += WORDS_PER_LINE ) { 12951out <<"\t" ; 12952for (int j = 0 ;j < WORDS_PER_LINE && i + j < (int )spirv .size ();++ j ) { 12953const unsigned int word = spirv [i + j ]; 12954out <<"0x" << std::hex << std::setw (8 ) << std::setfill ('0' ) <<word ; 12955if (i + j + 1 < (int )spirv .size ()) { 12956out <<"," ; 12957 } 12958 } 12959out << std::endl ; 12960 } 12961if (varName != nullptr ) { 12962out <<"};" ; 12963out << std::endl ; 12964 } 12965out .close (); 12966return true; 12967} 12968 12969// 12970// Set up the glslang traversal 12971// 12972void GlslangToSpv (const TIntermediate & intermediate , std::vector < unsigned int >& spirv ,SpvOptions * options ) 12973{ 12974 spv::SpvBuildLogger logger ; 12975GlslangToSpv (intermediate ,spirv ,& logger ,options ); 12976} 12977 12978void GlslangToSpv (const TIntermediate & intermediate , std::vector < unsigned int >& spirv , 12979 spv::SpvBuildLogger * logger ,SpvOptions * options ) 12980{ 12981TIntermNode * root = intermediate .getTreeRoot (); 12982 12983if (root == nullptr ) 12984return ; 12985 12986SpvOptions defaultOptions ; 12987if (options == nullptr ) 12988options = & defaultOptions ; 12989 12990GetThreadPoolAllocator ().push (); 12991 12992TGlslangToSpvTraverser it (intermediate .getSpv ().spv ,& intermediate ,logger ,* options ); 12993root -> traverse (& it ); 12994it .finishSpv (options -> compileOnly ); 12995it .dumpSpv (spirv ); 12996 12997#if ENABLE_OPT 12998// If from HLSL, run spirv-opt to "legalize" the SPIR-V for Vulkan 12999// eg. forward and remove memory writes of opaque types. 13000bool prelegalization = intermediate .getSource ()== EShSourceHlsl ; 13001if ((prelegalization || options -> optimizeSize || options -> optimizePerformance )&& !options -> disableOptimizer ) { 13002SpirvToolsTransform (intermediate ,spirv ,logger ,options ,prelegalization ); 13003prelegalization = false; 13004 } 13005else if (options -> stripDebugInfo ) { 13006// Strip debug info even if optimization is disabled. 13007SpirvToolsStripDebugInfo (intermediate ,spirv ,logger ); 13008 } 13009 13010if (options -> validate ) 13011SpirvToolsValidate (intermediate ,spirv ,logger ,prelegalization ); 13012 13013if (options -> disassemble ) 13014SpirvToolsDisassemble (std::cout ,spirv ); 13015 13016#endif 13017 13018GetThreadPoolAllocator ().pop (); 13019} 13020 13021}// end namespace glslang