2 * Copyright (c) 2018 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 #include <dali/graphics/vulkan/spirv/vulkan-spirv.h>
21 #include <dali/graphics/vulkan/spirv/vulkan-spirv-opcode.h>
23 #define debug( x ) std::cout << x << std::endl;
33 SPIRVShader::Impl& SPIRVShader::GetImplementation() const
38 #pragma GCC diagnostic push
39 #pragma GCC diagnostic ignored "-Wframe-larger-than="
40 struct SPIRVShader::Impl
43 * 32bit word needed to identify SPIRV code
45 static constexpr uint32_t MAGIC_NUMBER{0x07230203u};
48 * SPIRV header binary structure
53 uint32_t versionNumber; // 0 | major | minor | 0
54 uint32_t generatorMagicNumber;
60 * Stores descriptorset bindings and createinfo data used by reflection
62 struct DescriptorSetLayoutAndBindingInfo
64 std::vector<vk::DescriptorSetLayoutBinding> bindings;
65 vk::DescriptorSetLayoutCreateInfo createInfo;
68 SPIRVOpCode& FindByResultId( uint32_t resultId ) const
70 return *(opResults[resultId] );
73 SPIRVOpCode* FindByResultId( SPIRVOpCode& opcode ) const
79 return opResults[opcode.localData.resultId];
82 SPIRVOpCode* FindByResultPtrId( uint32_t resultId ) const
84 if( resultId < opResults.size() )
86 return opResults[resultId];
97 Impl( void* pData, std::size_t size, vk::ShaderStageFlags stages )
100 auto begin = reinterpret_cast<uint32_t*>( pData );
101 auto end = begin + size;
102 std::copy( begin, end, data.begin() );
112 explicit Impl( std::vector<T> buffer, vk::ShaderStageFlags stages )
114 data.resize( ( buffer.size() * sizeof( buffer[0] ) ) / sizeof( uint32_t ) );
115 auto begin = reinterpret_cast<uint32_t*>( &*buffer.begin() );
116 auto end = reinterpret_cast<uint32_t*>( &*buffer.end() );
117 std::copy( begin, end, data.begin() );
120 auto FindDecorationsForId( uint32_t id )
122 std::vector<SPIRVOpCode*> retval{};
123 for( auto&& op : opCodes )
125 if( op.code == SpvOpDecorate && op.GetParameterU32( 0 ) == id )
127 retval.push_back( &op );
133 auto FindMemberDecorationsForId( uint32_t id, uint32_t memberIndex )
135 std::vector<SPIRVOpCode*> retval{};
136 for( auto&& op : opCodes )
138 if( op.code == SpvOpMemberDecorate && op.GetParameterU32( 0 ) == id && op.GetParameterU32( 1 ) == memberIndex )
140 retval.push_back( &op );
146 SPIRVOpCode& GetReferencedOpCode( const SPIRVOpCode& opCode, uint32_t refIndex ) const
148 return FindByResultId( opCode.GetParameterU32( refIndex ) );
151 auto GetDecorationsOpId( const SPIRVOpCode& resultOp )
153 std::vector<SPIRVOpCode*> retval;
154 if( resultOp.hasResult )
156 for( auto&& op : opCodes )
158 if( op == SpvOpDecorate && op.GetParameterU32( 0 ) == resultOp.localData.resultId )
160 retval.push_back( &op );
167 bool CheckDecorationForOpId( const SPIRVOpCode& resultOp, SpvDecoration expectedDecoration )
169 if( resultOp.hasResult )
171 for( auto&& op : opCodes )
173 if( op == SpvOpDecorate && op.GetParameterU32( 0 ) == resultOp.localData.resultId &&
174 op.GetParameter<SpvDecoration>( 1 ) == expectedDecoration )
183 struct SPIRVReflectionData
185 SPIRVReflectionData() = default;
186 SPIRVReflectionData( const SPIRVReflectionData& ) = default;
187 SPIRVReflectionData& operator=( const SPIRVReflectionData& ) = default;
188 SPIRVReflectionData( SPIRVReflectionData&& ) = delete;
189 SPIRVReflectionData& operator=( SPIRVReflectionData&& ) = delete;
192 SPIRVOpCode* op{nullptr};
193 SpvStorageClass storage{SpvStorageClassMax};
194 vk::DescriptorType descriptorType{}; // only valid for uniforms
195 std::unordered_map<SpvDecoration, SPIRVOpCode*> decorations{};
196 std::vector<SPIRVReflectionData> members{}; // used by structs only
197 uint32_t structSize{0u};
200 template<class M, class K>
201 bool MapContains( const M& map, const K& key ) const
203 return map.find( key ) != map.end();
210 GetResult( bool v, V& value)
211 : success(v), result(&value)
216 : success(v), result(nullptr)
230 GetResult() : success( false ), result(nullptr){}
235 template<class K, class V>
236 GetResult<V> GetMapItem( std::unordered_map<K,V>& map, const K& key )
238 auto iter = map.find( key );
239 if( iter == map.end() )
241 return GetResult<V>( false );
244 return GetResult<V>( true, iter->second );
250 uint32_t sizeInBytes;
253 uint32_t componentSizeInBytes;
256 auto GetTypeInfo( const SPIRVOpCode& typeOpCode ) const
258 auto retval = SPIRVTypeInfo{};
260 const vk::Format VEC[] =
262 vk::Format::eUndefined,
263 vk::Format::eR32Sfloat,
264 vk::Format::eR32G32Sfloat,
265 vk::Format::eR32G32B32Sfloat,
266 vk::Format::eR32G32B32A32Sfloat,
269 // note: always assumed:
273 if( typeOpCode == SpvOpTypeMatrix )
275 retval.components = typeOpCode.GetParameterU32( 2 );
276 retval.rows = retval.components;
277 retval.componentSizeInBytes = sizeof(float);
278 retval.sizeInBytes = (retval.components*retval.components)*retval.componentSizeInBytes;
279 retval.vkFormat = VEC[retval.components];
281 else if(typeOpCode == SpvOpTypeVector)
283 retval.components = typeOpCode.GetParameterU32( 2 );
285 retval.componentSizeInBytes = sizeof(float);
286 retval.sizeInBytes = retval.components*retval.componentSizeInBytes;
287 retval.vkFormat = VEC[retval.components];
289 else if(typeOpCode == SpvOpTypeFloat)
291 retval.components = 1;
293 retval.componentSizeInBytes = sizeof(float);
294 retval.sizeInBytes = sizeof(float);
295 retval.vkFormat = vk::Format::eR32Sfloat;
297 else if(typeOpCode == SpvOpTypeInt)
299 retval.components = 1;
301 retval.componentSizeInBytes = sizeof(uint32_t);
302 retval.sizeInBytes = sizeof(uint32_t);
303 retval.vkFormat = vk::Format::eR32Sint;
307 retval.components = 0;
309 retval.componentSizeInBytes = 0;
310 retval.sizeInBytes = 0;
311 retval.vkFormat = vk::Format::eUndefined;
319 auto BuildReflection()
322 using MemberNameArray = std::vector<SPIRVOpCode*>;
323 auto vars = std::vector<SPIRVOpCode*>{};
324 auto opNames = std::unordered_map<uint32_t, SPIRVOpCode*>{};
326 // member names, key: struct id, value: ordered vector of OpMemberName ops
327 auto opMemberNames = std::unordered_map<uint32_t, MemberNameArray>{};
328 for( auto&& op : opCodes )
330 auto id = op.GetParameterU32(0);
331 if( op == SpvOpVariable )
333 vars.push_back( &op );
335 else if( op == SpvOpName )
337 opNames.emplace( id, &op );
339 else if( op == SpvOpMemberName )
341 GetResult<MemberNameArray> result{};
342 MemberNameArray* memberNames{ nullptr };
343 if( !(result = GetMapItem( opMemberNames, id )).success )
345 opMemberNames.emplace(id, MemberNameArray{} );
346 memberNames = &opMemberNames[id];
350 memberNames = result.result;
353 if(memberNames->size() <= op.GetParameterU32(1))
354 memberNames->resize( op.GetParameterU32(1)+1 );
355 (*memberNames)[op.GetParameterU32(1)] = &op;
359 // find uniforms and inputs
360 auto decorationVariables = std::unordered_map<uint32_t, SPIRVReflectionData>{};
361 auto uniformVariables = std::vector<SPIRVOpCode*>{};
362 auto inputVariables = std::vector<SPIRVOpCode*>{};
363 auto outputVariables = std::vector<SPIRVOpCode*>{};
364 for( auto&& op : vars )
366 auto storage = op->GetParameter<SpvStorageClass>( 2 );
367 bool varFound{false};
368 if( storage == SpvStorageClassUniform || storage == SpvStorageClassUniformConstant )
370 uniformVariables.emplace_back( op );
373 else if( storage == SpvStorageClassInput )
375 inputVariables.emplace_back( op );
378 else if( storage == SpvStorageClassOutput )
380 outputVariables.emplace_back( op );
384 // find decorations if variable
387 auto id = op->localData.resultId;
388 auto decorations = FindDecorationsForId( id );
389 SPIRVReflectionData decorationInfo;
390 decorationInfo.op = op;
391 decorationInfo.storage = storage;
393 // update descriptor type if viable
394 decorationInfo.descriptorType = FindDescriptorTypeForVariable( *op );
396 for( auto&& decoration : decorations )
398 auto decorationQualifier = decoration->GetParameter<SpvDecoration>( 1 );
399 decorationInfo.decorations.emplace( decorationQualifier, decoration );
400 std::cout << decorationQualifier << std::endl;
402 decorationVariables.emplace( id, decorationInfo );
404 // store name if element is named
405 GetResult<SPIRVOpCode*> name{};
407 bool foundName = false;
408 if( (name = GetMapItem( opNames, id )).success )
411 // variable may not be named ( global scope of the shader )
412 if( !(*name.result)->GetParameterAsString( 1 ).empty() )
414 std::cout <<"Found name\n";
415 decorationVariables[id].name = (*name.result)->GetParameterAsString( 1 );
420 // continue if name hasn't been found, this means the variable is an uniform
421 // in the global scope
424 auto pointerId = op->GetParameterU32(0);
425 auto pointer = FindByResultId( pointerId );
426 auto pointerToType = FindByResultId( pointer.GetParameterU32(2) );
428 // find name of the structure
429 GetResult<SPIRVOpCode*> retval{};
430 if( (retval = GetMapItem( opNames, pointerToType.localData.resultId )).success )
432 std::cout << "Found: " << (*retval.result)->GetParameterAsString(1) << std::endl;
433 decorationVariables[id].name = (*retval.result)->GetParameterAsString(1);
436 // depending on the type, we may need to extract members, member types as well
437 // as other relevant data
438 if( pointerToType == SpvOpTypeStruct )
441 auto memberCount = pointerToType.localData.count-2;
442 std::cout << "Found struct, look for member names and member decorations: "
443 "member count: " << memberCount << std::endl;
445 // for each member resolve type and compute size of the structure
446 auto memberNames = opMemberNames[ pointerToType.localData.resultId ];
447 for( auto i = 0u; i < memberCount; ++i )
449 auto& memberName = memberNames[i];
450 SPIRVReflectionData memberOpInfo;
451 memberOpInfo.name = memberName->GetParameterAsString(2);
452 auto memberResultId = pointerToType.GetParameterU32( i+1 );
453 memberOpInfo.op = FindByResultPtrId( memberResultId );
455 // look for decoration for each member ( needed in order to build data structures )
456 auto memberDecorationOps = FindMemberDecorationsForId( pointerToType.localData.resultId, i );
457 for( auto&& mop : memberDecorationOps )
459 memberOpInfo.decorations.emplace( mop->GetParameter<SpvDecoration>( 2 ), mop );
461 decorationVariables[id].members.emplace_back(memberOpInfo);
462 std::cout << "memberName: " << memberName->GetParameterAsString(2);
463 std::cout << std::endl;
466 uint32_t structSize = 0u;
468 // for last member update size of the data structure ( for blocks only )
471 if( memberCount > 0 )
473 auto& lastMember = decorationVariables[id].members.back();
475 if( MapContains( lastMember.decorations, SpvDecorationOffset ) )
477 structSize = lastMember.decorations[SpvDecorationOffset]->GetParameterU32(3);
479 auto typeInfo = GetTypeInfo( *lastMember.op );
480 structSize += typeInfo.sizeInBytes;
482 decorationVariables[id].structSize = structSize;
484 std::cout << "struct size: " << structSize << std::endl;
490 std::cout << "Found " << uniformVariables.size() << " variables\n";
492 return decorationVariables;
495 auto LoadOpCodes( const std::vector<SPIRVWord>& _data )
497 auto retval = std::vector<SPIRVOpCode>{};
499 // test if we have valid SPIRV header
500 auto iter = data.begin();
503 debug( "Not SPIRV!" );
507 debug( "SPIR-V detected" );
508 std::advance( iter, 5u ); // skip header
510 while( iter != data.end() )
513 auto wordCount = ( ( opword >> 16 ) & 0xFFFF );
514 auto opCode = ( (opword)&0xFFFF );
516 auto& op = FindOpCode( opCode );
518 if( op != OP_CODE_NULL )
520 uint32_t resultIndex{0};
521 int resultIndexOffset = 1;
522 int32_t resultType{0u};
525 retval.emplace_back( op );
526 auto& opcode = retval.back();
527 opcode.localData.start = &*iter;
528 opcode.localData.count = wordCount;
530 // update result type and index for non-void opcodes
531 if( op.hasResultType )
537 if( op.hasResultType )
539 resultType = static_cast<int32_t>( *( iter + 1 ) );
541 resultIndex = *( iter + resultIndexOffset );
542 opcode.localData.resultId = resultIndex;
543 opcode.localData.resultType = resultType;
548 std::advance( iter, wordCount );
554 auto CreateOpResults( std::vector<SPIRVOpCode>& _opcodes )
556 auto retval = std::vector<SPIRVOpCode*>{};
557 for( auto i = 0u; i < _opcodes.size(); ++i )
559 const auto& op = _opcodes[i];
562 if( retval.size() <= op.localData.resultId )
564 retval.resize( op.localData.resultId + 1 );
566 retval[op.localData.resultId] = &_opcodes[i];
572 vk::DescriptorType FindDescriptorTypeForVariable( SPIRVOpCode& opVariable )
574 vk::DescriptorType descriptorType{};
576 auto storageClass = opVariable.GetParameter<SpvStorageClass>(2);
578 // we need to detect storage by call into function
579 if (storageClass == SpvStorageClassUniformConstant)
581 auto& resource = opVariable;
582 if (TestStorageImageDescriptor(resource))
584 descriptorType = vk::DescriptorType::eStorageImage;
586 else if(TestSamplerDescriptor(resource))
588 descriptorType = vk::DescriptorType::eSampler;
590 else if(TestSampledImageDescriptor(resource))
592 descriptorType = vk::DescriptorType::eSampledImage;
594 else if(TestCombinedImageSamplerDescriptor(resource))
596 descriptorType = vk::DescriptorType::eCombinedImageSampler;
598 else if(TestUniformTexelBufferDescriptor(resource))
600 descriptorType = vk::DescriptorType::eUniformTexelBuffer;
602 else if(TestStorageTexelBufferDescriptor(resource))
604 descriptorType = vk::DescriptorType::eStorageTexelBuffer;
608 // @todo check the shader, something hasn't been recognized
609 descriptorType = vk::DescriptorType{};
612 if(descriptorType != vk::DescriptorType{})
614 //uniformResources.push_back( &resource );
617 else if(storageClass == SpvStorageClassUniform)
619 descriptorType = vk::DescriptorType::eUniformBuffer;
621 return descriptorType;
624 auto GenerateVulkanDescriptorSetLayouts()
626 // key: descriptor set, value: ds layout create info and binding
627 auto vkDescriptorSetLayoutCreateInfos = std::unordered_map<uint32_t, DescriptorSetLayoutAndBindingInfo>{};
629 for(auto&& symbol : reflectionData)
631 auto storage = symbol.second.storage;
632 auto& symbolData = symbol.second;
633 if( storage == SpvStorageClassUniform || storage == SpvStorageClassUniformConstant )
635 auto binding = MapContains( symbolData.decorations, SpvDecorationBinding ) ? symbolData.decorations[SpvDecorationBinding]->GetParameterU32(2) : 0u;
636 auto descriptorSet = MapContains( symbolData.decorations, SpvDecorationDescriptorSet ) ? symbolData.decorations[SpvDecorationDescriptorSet]->GetParameterU32(2) : 0u;
637 debug("found layout: binding: " << binding << " ds: " << descriptorSet << ", type: " << U32(symbolData.descriptorType) );
639 auto& ds = (MapContains( vkDescriptorSetLayoutCreateInfos, descriptorSet ) ?
640 vkDescriptorSetLayoutCreateInfos[descriptorSet] :
641 (*vkDescriptorSetLayoutCreateInfos.emplace( descriptorSet, DescriptorSetLayoutAndBindingInfo{} ).first).second);
644 ds.bindings.emplace_back( vk::DescriptorSetLayoutBinding{}.setBinding( binding )
645 .setDescriptorCount( 1 )
646 .setDescriptorType( symbolData.descriptorType )
647 .setStageFlags( vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment ) );
651 // sort bindings and complete create info structures
652 for( auto&& ds : vkDescriptorSetLayoutCreateInfos )
654 std::sort(ds.second.bindings.begin(), ds.second.bindings.end(), []( auto& a, auto& b ){ return a.binding < b.binding; });
655 ds.second.createInfo.setBindingCount( U32(ds.second.bindings.size()) );
656 ds.second.createInfo.pBindings = ds.second.bindings.data();
659 return vkDescriptorSetLayoutCreateInfos;
665 opCodes = std::move(LoadOpCodes(data));
667 // create results lookup array
668 opResults = std::move(CreateOpResults(opCodes));
670 // build reflection map
671 reflectionData = std::move(BuildReflection());
673 // build vulkan descriptor set layout infos
674 descriptorSetLayoutCreateInfoMap = std::move(GenerateVulkanDescriptorSetLayouts());
676 // generate additional reflection structures
677 uint32_t blockIndex = 0u;
678 for( auto&& symbol : reflectionData )
680 auto& symbolData = symbol.second;
681 auto binding = MapContains( symbolData.decorations, SpvDecorationBinding ) ? symbolData.decorations[SpvDecorationBinding]->GetParameterU32(2) : 0u;
682 auto descriptorSet = MapContains( symbolData.decorations, SpvDecorationDescriptorSet ) ? symbolData.decorations[SpvDecorationDescriptorSet]->GetParameterU32(2) : 0u;
684 if( symbolData.storage == SpvStorageClassUniform )
686 auto block = SPIRVUniformBlock{};
687 block.name = symbolData.name;
688 block.size = symbolData.structSize;
689 block.binding = binding;
690 block.descriptorSet = descriptorSet;
692 uint32_t location{ 0u };
693 for( auto&& member : symbolData.members )
695 auto blockMember = SPIRVUniformBlockMember{};
696 blockMember.name = member.name;
697 blockMember.location = location++;
698 blockMember.offset = MapContains( member.decorations, SpvDecorationOffset ) ? member.decorations[SpvDecorationOffset]->GetParameterU32(3) : 0u;
699 blockMember.blockIndex = blockIndex;
700 block.members.emplace_back( blockMember );
703 uniformBlockReflection.emplace_back( block );
706 else if( symbolData.storage == SpvStorageClassUniformConstant )
708 auto opaque = SPIRVUniformOpaque{};
709 opaque.name = symbolData.name;
710 opaque.binding = binding;
711 opaque.descriptorSet = descriptorSet;
712 opaque.type = symbolData.descriptorType;
713 uniformOpaqueReflection.emplace_back( opaque );
721 * Recognizes descriptor type VkDescriptorTypeStorageImage
723 * layout (set=m, binding=n, r32f) uniform image2D myStorageImage;
726 * %7 = OpTypeImage %6 2D 0 0 0 2 R32f
727 * %8 = OpTypePointer UniformConstant %7
728 * %9 = OpVariable %8 UniformConstant
732 bool TestStorageImageDescriptor( SPIRVOpCode& opcode )
734 auto opPointer = &FindByResultId( opcode.GetParameterU32(0) );
735 if( (opPointer && *opPointer == SpvOpTypePointer) )
737 auto& opTypeImage = GetReferencedOpCode( *opPointer, 2 );
738 if( opTypeImage == SpvOpTypeImage && opTypeImage.GetParameterU32( 6 ) == 2 )
747 * Recognizes descriptor type VkDescriptorTypeSampler
749 layout (set=m, binding=n) uniform sampler mySampler;
752 %3 = OpTypeFunction %2
754 %7 = OpTypePointer UniformConstant %6
755 %8 = OpVariable %7 UniformConstant
760 bool TestSamplerDescriptor( SPIRVOpCode& opcode )
762 auto opPointer = &FindByResultId( opcode.GetParameterU32(0) );
763 if( (opPointer && *opPointer == SpvOpTypePointer) )
765 auto& opTypeSampler = GetReferencedOpCode( *opPointer, 2 );
766 if( opTypeSampler == SpvOpTypeSampler )
775 * Recognizes descriptor type VkDescriptorTypeSampledImage
777 * layout (set=m, binding=n) uniform texture2D mySampledImage;
780 %7 = OpTypeImage %6 2D 0 0 0 1 Unknown
781 %8 = OpTypePointer UniformConstant %7
782 %9 = OpVariable %8 UniformConstant
787 bool TestSampledImageDescriptor( SPIRVOpCode& opcode)
789 auto opPointer = &FindByResultId( opcode.GetParameterU32(0) );
790 if( (opPointer && *opPointer == SpvOpTypePointer) )
792 auto& opTypeImage = GetReferencedOpCode( *opPointer, 2 );
793 if( opTypeImage == SpvOpTypeImage && opTypeImage.GetParameterU32( 6 ) == 1 )
802 * Recognizes descriptor type VkDescriptorTypeCombinedImageSampler
804 * layout (set=m, binding=n) uniform sampler2D myCombinedImageSampler;
806 %7 = OpTypeImage %6 2D 0 0 0 1 Unknown
807 %8 = OpTypeSampledImage %7
808 %9 = OpTypePointer UniformConstant %8
809 %10 = OpVariable %9 UniformConstant
813 bool TestCombinedImageSamplerDescriptor( SPIRVOpCode& opcode )
815 auto opPointer = &FindByResultId( opcode.GetParameterU32(0) );
816 if( (opPointer && *opPointer == SpvOpTypePointer) )
818 auto& opCode = GetReferencedOpCode( *opPointer, 2 );
819 if( opCode == SpvOpTypeSampledImage )
828 * Recognizes descriptor type VkDescriptorTypeUniformTexelBuffer
830 * layout (set=m, binding=n) uniform samplerBuffer myUniformTexelBuffer;
833 %7 = OpTypeImage %6 Buffer 0 0 0 1 Unknown
834 %8 = OpTypePointer UniformConstant %7
835 %9 = OpVariable %8 UniformConstant
839 bool TestUniformTexelBufferDescriptor( SPIRVOpCode& opcode )
841 auto opPointer = &FindByResultId( opcode.GetParameterU32(0) );
842 if( (opPointer && *opPointer == SpvOpTypePointer) )
844 auto& opCode = GetReferencedOpCode( *opPointer, 2 );
845 if( opCode == SpvOpTypeImage && opCode.GetParameter<SpvDim>( 2 ) == SpvDimBuffer &&
846 opCode.GetParameterU32( 6 ) == 1 )
855 * Recognizes descriptor type VkDescriptorTypeStorageTexelBuffer
857 * layout (set=m, binding=n, r32f) uniform imageBuffer myStorageTexelBuffer;
859 %7 = OpTypeImage %6 Buffer 0 0 0 2 R32f
860 %8 = OpTypePointer UniformConstant %7
861 %9 = OpVariable %8 UniformConstant
865 bool TestStorageTexelBufferDescriptor( SPIRVOpCode& opcode )
867 auto opPointer = &FindByResultId( opcode.GetParameterU32(0) );
868 if( (opPointer && *opPointer == SpvOpTypePointer) )
870 auto& opCode = GetReferencedOpCode( *opPointer, 2 );
871 if( opCode == SpvOpTypeImage && opCode.GetParameter<SpvDim>( 2 ) == SpvDimBuffer &&
872 opCode.GetParameterU32( 6 ) == 2 )
881 * Recognizes descriptor type VkDescriptorTypeUniformBuffer
883 layout (set=m, binding=n) uniform myUniformBuffer
888 %11 = OpTypeStruct %10
889 %12 = OpTypePointer Uniform %11
890 %13 = OpVariable %12 Uniform
891 * @todo pull data out of OpDecorate ( Block )
895 bool TestUniformBufferDescriptor( SPIRVOpCode& opcode )
897 auto opPointer = &FindByResultId( opcode.GetParameterU32(0) );
898 if( (opPointer && *opPointer == SpvOpTypePointer) && opPointer->GetParameter<SpvStorageClass>( 1 ) == SpvStorageClassUniform )
900 auto& opTypeStruct = GetReferencedOpCode( *opPointer, 2 );
901 if( opTypeStruct == SpvOpTypeStruct )
903 return CheckDecorationForOpId( opTypeStruct, SpvDecorationBlock );
909 bool TestStorageBufferDescriptor( SPIRVOpCode& opcode )
911 auto opPointer = FindByResultId( opcode );
912 if( (opPointer && *opPointer == SpvOpTypePointer) && opPointer->GetParameter<SpvStorageClass>( 1 ) == SpvStorageClassUniform )
914 auto& opTypeStruct = GetReferencedOpCode( *opPointer, 2 );
915 if( opTypeStruct == SpvOpTypeStruct )
917 return CheckDecorationForOpId( opTypeStruct, SpvDecorationBufferBlock );
923 std::vector<vk::DescriptorSetLayoutCreateInfo> GenerateDescriptorSetLayoutCreateInfo() const
925 auto retval = std::vector<vk::DescriptorSetLayoutCreateInfo>{};
926 for( auto& layout : descriptorSetLayoutCreateInfoMap )
928 retval.emplace_back( layout.second.createInfo );
934 bool GetVertexInputAttributes( std::vector<SPIRVVertexInputAttribute>& out, bool canOverlap = false )
936 for( auto&& i : reflectionData )
938 if( i.second.storage == SpvStorageClassInput )
940 auto attr = SPIRVVertexInputAttribute{};
941 attr.name = i.second.name;
942 attr.location = MapContains( i.second.decorations, SpvDecorationLocation ) ?
943 i.second.decorations[SpvDecorationLocation]->GetParameterU32(2) : 0u;
944 attr.format = GetTypeInfo(
945 GetReferencedOpCode( GetReferencedOpCode( *i.second.op, 0 ), 2)
947 out.emplace_back( attr );
955 * Tests if the header is valid for SPIR-V
960 header = *reinterpret_cast<Header*>( data.data() );
961 return MAGIC_NUMBER == header.magicNumber;
965 std::vector<SPIRVOpCode> opCodes; // contains all opcodes
966 std::vector<SPIRVOpCode*> opResults; // links to the resulting opcode or nullptr if opcode doesn't return
968 std::unordered_map<uint32_t, SPIRVReflectionData> reflectionData;
969 std::unordered_map<uint32_t, DescriptorSetLayoutAndBindingInfo> descriptorSetLayoutCreateInfoMap;
971 std::vector<SPIRVWord> data;
974 std::vector<SPIRVUniformBlock> uniformBlockReflection;
975 std::vector<SPIRVUniformOpaque> uniformOpaqueReflection;
979 #pragma GCC diagnostic pop
981 /**************************************************************************************
985 SPIRVShader::SPIRVShader() = default;
987 SPIRVShader::~SPIRVShader() = default;
989 SPIRVShader::SPIRVShader( SPIRVShader&& shader ) noexcept = default;
991 SPIRVShader::SPIRVShader( Impl& impl )
993 mImpl.reset( &impl );
996 SPIRVShader::SPIRVShader( std::vector<SPIRVWord> code, vk::ShaderStageFlags stages )
998 mImpl = std::make_unique<Impl>( code, stages );
1001 std::vector<vk::DescriptorSetLayoutCreateInfo> SPIRVShader::GenerateDescriptorSetLayoutCreateInfo() const
1003 return mImpl->GenerateDescriptorSetLayoutCreateInfo();
1006 uint32_t SPIRVShader::GetOpCodeCount() const
1008 return static_cast<uint32_t>( mImpl->opCodes.size() );
1011 const SPIRVOpCode* SPIRVShader::GetOpCodeAt( uint32_t index ) const
1013 return &mImpl->opCodes[index];
1016 const SPIRVOpCode* SPIRVShader::GetOpCodeForResultId( uint32_t resultId ) const
1018 return mImpl->opResults[resultId];
1021 SPIRVWord SPIRVShader::GetOpCodeParameterWord( const SPIRVOpCode& opCode, uint32_t index ) const
1023 return GetOpCodeParameter<SPIRVWord>( opCode, index );
1026 SpvOp SPIRVShader::GetOpCodeType( SPIRVOpCode& opCode )
1031 const uint32_t* SPIRVShader::GetOpCodeParameterPtr( const SPIRVOpCode& opCode, uint32_t index ) const
1033 return ( opCode.localData.start + index + 1 );
1036 void SPIRVShader::GetVertexInputAttributes( std::vector<SPIRVVertexInputAttribute>& out ) const
1038 mImpl->GetVertexInputAttributes( out );
1041 const std::vector<SPIRVUniformBlock>& SPIRVShader::GetUniformBlocks() const
1043 return mImpl->uniformBlockReflection;
1046 const std::vector<SPIRVUniformOpaque>& SPIRVShader::GetOpaqueUniforms() const
1048 return mImpl->uniformOpaqueReflection;
1051 bool SPIRVShader::FindUniformMemberByName( const std::string& uniformName, SPIRVUniformBlockMember& out ) const
1053 for( auto&& ubo : mImpl->uniformBlockReflection )
1055 for( auto&& member : ubo.members )
1057 if( member.name == uniformName )
1067 /**************************************************************************************
1076 std::unique_ptr<SPIRVShader> SPIRVUtils::Parse( std::vector<SPIRVWord> data, vk::ShaderStageFlags stages )
1078 auto shader = std::unique_ptr<SPIRVShader>( new SPIRVShader( data, stages ) );
1079 if( !shader->GetImplementation().Initialise() )
1086 std::unique_ptr<SPIRVShader> SPIRVUtils::Parse( const SPIRVWord* data, size_t sizeInBytes, vk::ShaderStageFlags stages )
1088 std::vector<SPIRVWord> spirvCode{};
1089 auto wordSize = sizeInBytes / sizeof( SPIRVWord );
1090 spirvCode.resize( wordSize );
1091 std::copy( data, data + wordSize, spirvCode.begin() );
1092 return Parse( spirvCode, stages );
1095 } // namespace SpirV
1097 } // namespace Vulkan
1099 } // namespace Graphics