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 struct SPIRVShader::Impl
41 * 32bit word needed to identify SPIRV code
43 static constexpr uint32_t MAGIC_NUMBER{0x07230203u};
46 * SPIRV header binary structure
51 uint32_t versionNumber; // 0 | major | minor | 0
52 uint32_t generatorMagicNumber;
58 * Stores descriptorset bindings and createinfo data used by reflection
60 struct DescriptorSetLayoutAndBindingInfo
62 std::vector<vk::DescriptorSetLayoutBinding> bindings;
63 vk::DescriptorSetLayoutCreateInfo createInfo;
66 SPIRVOpCode& FindByResultId( uint32_t resultId ) const
68 return *(opResults[resultId] );
71 SPIRVOpCode* FindByResultId( SPIRVOpCode& opcode ) const
77 return opResults[opcode.localData.resultId];
80 SPIRVOpCode* FindByResultPtrId( uint32_t resultId ) const
82 if( resultId < opResults.size() )
84 return opResults[resultId];
95 Impl( void* pData, std::size_t size, vk::ShaderStageFlags stages )
98 auto begin = reinterpret_cast<uint32_t*>( pData );
99 auto end = begin + size;
100 std::copy( begin, end, data.begin() );
110 explicit Impl( std::vector<T> buffer, vk::ShaderStageFlags stages )
112 data.resize( ( buffer.size() * sizeof( buffer[0] ) ) / sizeof( uint32_t ) );
113 auto begin = reinterpret_cast<uint32_t*>( &*buffer.begin() );
114 auto end = reinterpret_cast<uint32_t*>( &*buffer.end() );
115 std::copy( begin, end, data.begin() );
118 auto FindDecorationsForId( uint32_t id )
120 std::vector<SPIRVOpCode*> retval{};
121 for( auto&& op : opCodes )
123 if( op.code == SpvOpDecorate && op.GetParameterU32( 0 ) == id )
125 retval.push_back( &op );
131 auto FindMemberDecorationsForId( uint32_t id, uint32_t memberIndex )
133 std::vector<SPIRVOpCode*> retval{};
134 for( auto&& op : opCodes )
136 if( op.code == SpvOpMemberDecorate && op.GetParameterU32( 0 ) == id && op.GetParameterU32( 1 ) == memberIndex )
138 retval.push_back( &op );
144 SPIRVOpCode& GetReferencedOpCode( const SPIRVOpCode& opCode, uint32_t refIndex ) const
146 return FindByResultId( opCode.GetParameterU32( refIndex ) );
149 auto GetDecorationsOpId( const SPIRVOpCode& resultOp )
151 std::vector<SPIRVOpCode*> retval;
152 if( resultOp.hasResult )
154 for( auto&& op : opCodes )
156 if( op == SpvOpDecorate && op.GetParameterU32( 0 ) == resultOp.localData.resultId )
158 retval.push_back( &op );
165 bool CheckDecorationForOpId( const SPIRVOpCode& resultOp, SpvDecoration expectedDecoration )
167 if( resultOp.hasResult )
169 for( auto&& op : opCodes )
171 if( op == SpvOpDecorate && op.GetParameterU32( 0 ) == resultOp.localData.resultId &&
172 op.GetParameter<SpvDecoration>( 1 ) == expectedDecoration )
181 struct SPIRVReflectionData
183 SPIRVReflectionData() = default;
184 SPIRVReflectionData( const SPIRVReflectionData& ) = default;
185 SPIRVReflectionData& operator=( const SPIRVReflectionData& ) = default;
186 SPIRVReflectionData( SPIRVReflectionData&& ) = delete;
187 SPIRVReflectionData& operator=( SPIRVReflectionData&& ) = delete;
190 SPIRVOpCode* op{nullptr};
191 SpvStorageClass storage{SpvStorageClassMax};
192 vk::DescriptorType descriptorType{}; // only valid for uniforms
193 std::unordered_map<SpvDecoration, SPIRVOpCode*> decorations{};
194 std::vector<SPIRVReflectionData> members{}; // used by structs only
195 uint32_t structSize{0u};
198 template<class M, class K>
199 bool MapContains( const M& map, const K& key ) const
201 return map.find( key ) != map.end();
208 GetResult( bool v, V& value)
209 : success(v), result(&value)
214 : success(v), result(nullptr)
228 GetResult() : success( false ), result(nullptr){}
233 template<class K, class V>
234 GetResult<V> GetMapItem( std::unordered_map<K,V>& map, const K& key )
236 auto iter = map.find( key );
237 if( iter == map.end() )
239 return GetResult<V>( false );
242 return GetResult<V>( true, iter->second );
248 uint32_t sizeInBytes;
251 uint32_t componentSizeInBytes;
254 auto GetTypeInfo( const SPIRVOpCode& typeOpCode ) const
256 auto retval = SPIRVTypeInfo{};
258 const vk::Format VEC[] =
260 vk::Format::eUndefined,
261 vk::Format::eR32Sfloat,
262 vk::Format::eR32G32Sfloat,
263 vk::Format::eR32G32B32Sfloat,
264 vk::Format::eR32G32B32A32Sfloat,
267 // note: always assumed:
271 if( typeOpCode == SpvOpTypeMatrix )
273 retval.components = typeOpCode.GetParameterU32( 2 );
274 retval.rows = retval.components;
275 retval.componentSizeInBytes = sizeof(float);
276 retval.sizeInBytes = (retval.components*retval.components)*retval.componentSizeInBytes;
277 retval.vkFormat = VEC[retval.components];
279 else if(typeOpCode == SpvOpTypeVector)
281 retval.components = typeOpCode.GetParameterU32( 2 );
283 retval.componentSizeInBytes = sizeof(float);
284 retval.sizeInBytes = retval.components*retval.componentSizeInBytes;
285 retval.vkFormat = VEC[retval.components];
287 else if(typeOpCode == SpvOpTypeFloat)
289 retval.components = 1;
291 retval.componentSizeInBytes = sizeof(float);
292 retval.sizeInBytes = sizeof(float);
293 retval.vkFormat = vk::Format::eR32Sfloat;
295 else if(typeOpCode == SpvOpTypeInt)
297 retval.components = 1;
299 retval.componentSizeInBytes = sizeof(uint32_t);
300 retval.sizeInBytes = sizeof(uint32_t);
301 retval.vkFormat = vk::Format::eR32Sint;
305 retval.components = 0;
307 retval.componentSizeInBytes = 0;
308 retval.sizeInBytes = 0;
309 retval.vkFormat = vk::Format::eUndefined;
317 auto BuildReflection()
320 using MemberNameArray = std::vector<SPIRVOpCode*>;
321 auto vars = std::vector<SPIRVOpCode*>{};
322 auto opNames = std::unordered_map<uint32_t, SPIRVOpCode*>{};
324 // member names, key: struct id, value: ordered vector of OpMemberName ops
325 auto opMemberNames = std::unordered_map<uint32_t, MemberNameArray>{};
326 for( auto&& op : opCodes )
328 auto id = op.GetParameterU32(0);
329 if( op == SpvOpVariable )
331 vars.push_back( &op );
333 else if( op == SpvOpName )
335 opNames.emplace( id, &op );
337 else if( op == SpvOpMemberName )
339 GetResult<MemberNameArray> result{};
340 MemberNameArray* memberNames{ nullptr };
341 if( !(result = GetMapItem( opMemberNames, id )).success )
343 opMemberNames.emplace(id, MemberNameArray{} );
344 memberNames = &opMemberNames[id];
348 memberNames = result.result;
351 if(memberNames->size() <= op.GetParameterU32(1))
352 memberNames->resize( op.GetParameterU32(1)+1 );
353 (*memberNames)[op.GetParameterU32(1)] = &op;
357 // find uniforms and inputs
358 auto decorationVariables = std::unordered_map<uint32_t, SPIRVReflectionData>{};
359 auto uniformVariables = std::vector<SPIRVOpCode*>{};
360 auto inputVariables = std::vector<SPIRVOpCode*>{};
361 auto outputVariables = std::vector<SPIRVOpCode*>{};
362 for( auto&& op : vars )
364 auto storage = op->GetParameter<SpvStorageClass>( 2 );
365 bool varFound{false};
366 if( storage == SpvStorageClassUniform || storage == SpvStorageClassUniformConstant )
368 uniformVariables.emplace_back( op );
371 else if( storage == SpvStorageClassInput )
373 inputVariables.emplace_back( op );
376 else if( storage == SpvStorageClassOutput )
378 outputVariables.emplace_back( op );
382 // find decorations if variable
385 auto id = op->localData.resultId;
386 auto decorations = FindDecorationsForId( id );
387 SPIRVReflectionData decorationInfo;
388 decorationInfo.op = op;
389 decorationInfo.storage = storage;
391 // update descriptor type if viable
392 decorationInfo.descriptorType = FindDescriptorTypeForVariable( *op );
394 for( auto&& decoration : decorations )
396 auto decorationQualifier = decoration->GetParameter<SpvDecoration>( 1 );
397 decorationInfo.decorations.emplace( decorationQualifier, decoration );
398 std::cout << decorationQualifier << std::endl;
400 decorationVariables.emplace( id, decorationInfo );
402 // store name if element is named
403 GetResult<SPIRVOpCode*> name{};
405 bool foundName = false;
406 if( (name = GetMapItem( opNames, id )).success )
409 // variable may not be named ( global scope of the shader )
410 if( !(*name.result)->GetParameterAsString( 1 ).empty() )
412 std::cout <<"Found name\n";
413 decorationVariables[id].name = (*name.result)->GetParameterAsString( 1 );
418 // continue if name hasn't been found, this means the variable is an uniform
419 // in the global scope
422 auto pointerId = op->GetParameterU32(0);
423 auto pointer = FindByResultId( pointerId );
424 auto pointerToType = FindByResultId( pointer.GetParameterU32(2) );
426 // find name of the structure
427 GetResult<SPIRVOpCode*> retval{};
428 if( (retval = GetMapItem( opNames, pointerToType.localData.resultId )).success )
430 std::cout << "Found: " << (*retval.result)->GetParameterAsString(1) << std::endl;
431 decorationVariables[id].name = (*retval.result)->GetParameterAsString(1);
434 // depending on the type, we may need to extract members, member types as well
435 // as other relevant data
436 if( pointerToType == SpvOpTypeStruct )
439 auto memberCount = pointerToType.localData.count-2;
440 std::cout << "Found struct, look for member names and member decorations: "
441 "member count: " << memberCount << std::endl;
443 // for each member resolve type and compute size of the structure
444 auto memberNames = opMemberNames[ pointerToType.localData.resultId ];
445 for( auto i = 0u; i < memberCount; ++i )
447 auto& memberName = memberNames[i];
448 SPIRVReflectionData memberOpInfo;
449 memberOpInfo.name = memberName->GetParameterAsString(2);
450 auto memberResultId = pointerToType.GetParameterU32( i+1 );
451 memberOpInfo.op = FindByResultPtrId( memberResultId );
453 // look for decoration for each member ( needed in order to build data structures )
454 auto memberDecorationOps = FindMemberDecorationsForId( pointerToType.localData.resultId, i );
455 for( auto&& mop : memberDecorationOps )
457 memberOpInfo.decorations.emplace( mop->GetParameter<SpvDecoration>( 2 ), mop );
459 decorationVariables[id].members.emplace_back(memberOpInfo);
460 std::cout << "memberName: " << memberName->GetParameterAsString(2);
461 std::cout << std::endl;
464 uint32_t structSize = 0u;
466 // for last member update size of the data structure ( for blocks only )
469 if( memberCount > 0 )
471 auto& lastMember = decorationVariables[id].members.back();
473 if( MapContains( lastMember.decorations, SpvDecorationOffset ) )
475 structSize = lastMember.decorations[SpvDecorationOffset]->GetParameterU32(3);
477 auto typeInfo = GetTypeInfo( *lastMember.op );
478 structSize += typeInfo.sizeInBytes;
480 decorationVariables[id].structSize = structSize;
482 std::cout << "struct size: " << structSize << std::endl;
488 std::cout << "Found " << uniformVariables.size() << " variables\n";
490 return decorationVariables;
493 auto LoadOpCodes( const std::vector<SPIRVWord>& _data )
495 auto retval = std::vector<SPIRVOpCode>{};
497 // test if we have valid SPIRV header
498 auto iter = data.begin();
501 debug( "Not SPIRV!" );
505 debug( "SPIR-V detected" );
506 std::advance( iter, 5u ); // skip header
508 while( iter != data.end() )
511 auto wordCount = ( ( opword >> 16 ) & 0xFFFF );
512 auto opCode = ( (opword)&0xFFFF );
514 auto& op = FindOpCode( opCode );
516 if( op != OP_CODE_NULL )
518 uint32_t resultIndex{0};
519 int resultIndexOffset = 1;
520 int32_t resultType{0u};
523 retval.emplace_back( op );
524 auto& opcode = retval.back();
525 opcode.localData.start = &*iter;
526 opcode.localData.count = wordCount;
528 // update result type and index for non-void opcodes
529 if( op.hasResultType )
535 if( op.hasResultType )
537 resultType = static_cast<int32_t>( *( iter + 1 ) );
539 resultIndex = *( iter + resultIndexOffset );
540 opcode.localData.resultId = resultIndex;
541 opcode.localData.resultType = resultType;
546 std::advance( iter, wordCount );
552 auto CreateOpResults( std::vector<SPIRVOpCode>& _opcodes )
554 auto retval = std::vector<SPIRVOpCode*>{};
555 for( auto i = 0u; i < _opcodes.size(); ++i )
557 const auto& op = _opcodes[i];
560 if( retval.size() <= op.localData.resultId )
562 retval.resize( op.localData.resultId + 1 );
564 retval[op.localData.resultId] = &_opcodes[i];
570 vk::DescriptorType FindDescriptorTypeForVariable( SPIRVOpCode& opVariable )
572 vk::DescriptorType descriptorType{};
574 auto storageClass = opVariable.GetParameter<SpvStorageClass>(2);
576 // we need to detect storage by call into function
577 if (storageClass == SpvStorageClassUniformConstant)
579 auto& resource = opVariable;
580 if (TestStorageImageDescriptor(resource))
582 descriptorType = vk::DescriptorType::eStorageImage;
584 else if(TestSamplerDescriptor(resource))
586 descriptorType = vk::DescriptorType::eSampler;
588 else if(TestSampledImageDescriptor(resource))
590 descriptorType = vk::DescriptorType::eSampledImage;
592 else if(TestCombinedImageSamplerDescriptor(resource))
594 descriptorType = vk::DescriptorType::eCombinedImageSampler;
596 else if(TestUniformTexelBufferDescriptor(resource))
598 descriptorType = vk::DescriptorType::eUniformTexelBuffer;
600 else if(TestStorageTexelBufferDescriptor(resource))
602 descriptorType = vk::DescriptorType::eStorageTexelBuffer;
606 // @todo check the shader, something hasn't been recognized
607 descriptorType = vk::DescriptorType{};
610 if(descriptorType != vk::DescriptorType{})
612 //uniformResources.push_back( &resource );
615 else if(storageClass == SpvStorageClassUniform)
617 descriptorType = vk::DescriptorType::eUniformBuffer;
619 return descriptorType;
622 auto GenerateVulkanDescriptorSetLayouts()
624 // key: descriptor set, value: ds layout create info and binding
625 auto vkDescriptorSetLayoutCreateInfos = std::unordered_map<uint32_t, DescriptorSetLayoutAndBindingInfo>{};
627 for(auto&& symbol : reflectionData)
629 auto storage = symbol.second.storage;
630 auto& symbolData = symbol.second;
631 if( storage == SpvStorageClassUniform || storage == SpvStorageClassUniformConstant )
633 auto binding = MapContains( symbolData.decorations, SpvDecorationBinding ) ? symbolData.decorations[SpvDecorationBinding]->GetParameterU32(2) : 0u;
634 auto descriptorSet = MapContains( symbolData.decorations, SpvDecorationDescriptorSet ) ? symbolData.decorations[SpvDecorationDescriptorSet]->GetParameterU32(2) : 0u;
635 debug("found layout: binding: " << binding << " ds: " << descriptorSet << ", type: " << U32(symbolData.descriptorType) );
637 auto& ds = (MapContains( vkDescriptorSetLayoutCreateInfos, descriptorSet ) ?
638 vkDescriptorSetLayoutCreateInfos[descriptorSet] :
639 (*vkDescriptorSetLayoutCreateInfos.emplace( descriptorSet, DescriptorSetLayoutAndBindingInfo{} ).first).second);
642 ds.bindings.emplace_back( vk::DescriptorSetLayoutBinding{}.setBinding( binding )
643 .setDescriptorCount( 1 )
644 .setDescriptorType( symbolData.descriptorType )
645 .setStageFlags( vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment ) );
649 // sort bindings and complete create info structures
650 for( auto&& ds : vkDescriptorSetLayoutCreateInfos )
652 std::sort(ds.second.bindings.begin(), ds.second.bindings.end(), []( auto& a, auto& b ){ return a.binding < b.binding; });
653 ds.second.createInfo.setBindingCount( U32(ds.second.bindings.size()) );
654 ds.second.createInfo.pBindings = ds.second.bindings.data();
657 return vkDescriptorSetLayoutCreateInfos;
663 opCodes = std::move(LoadOpCodes(data));
665 // create results lookup array
666 opResults = std::move(CreateOpResults(opCodes));
668 // build reflection map
669 reflectionData = std::move(BuildReflection());
671 // build vulkan descriptor set layout infos
672 descriptorSetLayoutCreateInfoMap = std::move(GenerateVulkanDescriptorSetLayouts());
674 // generate additional reflection structures
675 uint32_t blockIndex = 0u;
676 for( auto&& symbol : reflectionData )
678 auto& symbolData = symbol.second;
679 auto binding = MapContains( symbolData.decorations, SpvDecorationBinding ) ? symbolData.decorations[SpvDecorationBinding]->GetParameterU32(2) : 0u;
680 auto descriptorSet = MapContains( symbolData.decorations, SpvDecorationDescriptorSet ) ? symbolData.decorations[SpvDecorationDescriptorSet]->GetParameterU32(2) : 0u;
682 if( symbolData.storage == SpvStorageClassUniform )
684 auto block = SPIRVUniformBlock{};
685 block.name = symbolData.name;
686 block.size = symbolData.structSize;
687 block.binding = binding;
688 block.descriptorSet = descriptorSet;
690 uint32_t location{ 0u };
691 for( auto&& member : symbolData.members )
693 auto blockMember = SPIRVUniformBlockMember{};
694 blockMember.name = member.name;
695 blockMember.location = location++;
696 blockMember.offset = MapContains( member.decorations, SpvDecorationOffset ) ? member.decorations[SpvDecorationOffset]->GetParameterU32(3) : 0u;
697 blockMember.blockIndex = blockIndex;
698 block.members.emplace_back( blockMember );
701 uniformBlockReflection.emplace_back( block );
704 else if( symbolData.storage == SpvStorageClassUniformConstant )
706 auto opaque = SPIRVUniformOpaque{};
707 opaque.name = symbolData.name;
708 opaque.binding = binding;
709 opaque.descriptorSet = descriptorSet;
710 opaque.type = symbolData.descriptorType;
711 uniformOpaqueReflection.emplace_back( opaque );
719 * Recognizes descriptor type VkDescriptorTypeStorageImage
721 * layout (set=m, binding=n, r32f) uniform image2D myStorageImage;
724 * %7 = OpTypeImage %6 2D 0 0 0 2 R32f
725 * %8 = OpTypePointer UniformConstant %7
726 * %9 = OpVariable %8 UniformConstant
730 bool TestStorageImageDescriptor( SPIRVOpCode& opcode )
732 auto opPointer = &FindByResultId( opcode.GetParameterU32(0) );
733 if( (opPointer && *opPointer == SpvOpTypePointer) )
735 auto& opTypeImage = GetReferencedOpCode( *opPointer, 2 );
736 if( opTypeImage == SpvOpTypeImage && opTypeImage.GetParameterU32( 6 ) == 2 )
745 * Recognizes descriptor type VkDescriptorTypeSampler
747 layout (set=m, binding=n) uniform sampler mySampler;
750 %3 = OpTypeFunction %2
752 %7 = OpTypePointer UniformConstant %6
753 %8 = OpVariable %7 UniformConstant
758 bool TestSamplerDescriptor( SPIRVOpCode& opcode )
760 auto opPointer = &FindByResultId( opcode.GetParameterU32(0) );
761 if( (opPointer && *opPointer == SpvOpTypePointer) )
763 auto& opTypeSampler = GetReferencedOpCode( *opPointer, 2 );
764 if( opTypeSampler == SpvOpTypeSampler )
773 * Recognizes descriptor type VkDescriptorTypeSampledImage
775 * layout (set=m, binding=n) uniform texture2D mySampledImage;
778 %7 = OpTypeImage %6 2D 0 0 0 1 Unknown
779 %8 = OpTypePointer UniformConstant %7
780 %9 = OpVariable %8 UniformConstant
785 bool TestSampledImageDescriptor( SPIRVOpCode& opcode)
787 auto opPointer = &FindByResultId( opcode.GetParameterU32(0) );
788 if( (opPointer && *opPointer == SpvOpTypePointer) )
790 auto& opTypeImage = GetReferencedOpCode( *opPointer, 2 );
791 if( opTypeImage == SpvOpTypeImage && opTypeImage.GetParameterU32( 6 ) == 1 )
800 * Recognizes descriptor type VkDescriptorTypeCombinedImageSampler
802 * layout (set=m, binding=n) uniform sampler2D myCombinedImageSampler;
804 %7 = OpTypeImage %6 2D 0 0 0 1 Unknown
805 %8 = OpTypeSampledImage %7
806 %9 = OpTypePointer UniformConstant %8
807 %10 = OpVariable %9 UniformConstant
811 bool TestCombinedImageSamplerDescriptor( SPIRVOpCode& opcode )
813 auto opPointer = &FindByResultId( opcode.GetParameterU32(0) );
814 if( (opPointer && *opPointer == SpvOpTypePointer) )
816 auto& opCode = GetReferencedOpCode( *opPointer, 2 );
817 if( opCode == SpvOpTypeSampledImage )
826 * Recognizes descriptor type VkDescriptorTypeUniformTexelBuffer
828 * layout (set=m, binding=n) uniform samplerBuffer myUniformTexelBuffer;
831 %7 = OpTypeImage %6 Buffer 0 0 0 1 Unknown
832 %8 = OpTypePointer UniformConstant %7
833 %9 = OpVariable %8 UniformConstant
837 bool TestUniformTexelBufferDescriptor( SPIRVOpCode& opcode )
839 auto opPointer = &FindByResultId( opcode.GetParameterU32(0) );
840 if( (opPointer && *opPointer == SpvOpTypePointer) )
842 auto& opCode = GetReferencedOpCode( *opPointer, 2 );
843 if( opCode == SpvOpTypeImage && opCode.GetParameter<SpvDim>( 2 ) == SpvDimBuffer &&
844 opCode.GetParameterU32( 6 ) == 1 )
853 * Recognizes descriptor type VkDescriptorTypeStorageTexelBuffer
855 * layout (set=m, binding=n, r32f) uniform imageBuffer myStorageTexelBuffer;
857 %7 = OpTypeImage %6 Buffer 0 0 0 2 R32f
858 %8 = OpTypePointer UniformConstant %7
859 %9 = OpVariable %8 UniformConstant
863 bool TestStorageTexelBufferDescriptor( SPIRVOpCode& opcode )
865 auto opPointer = &FindByResultId( opcode.GetParameterU32(0) );
866 if( (opPointer && *opPointer == SpvOpTypePointer) )
868 auto& opCode = GetReferencedOpCode( *opPointer, 2 );
869 if( opCode == SpvOpTypeImage && opCode.GetParameter<SpvDim>( 2 ) == SpvDimBuffer &&
870 opCode.GetParameterU32( 6 ) == 2 )
879 * Recognizes descriptor type VkDescriptorTypeUniformBuffer
881 layout (set=m, binding=n) uniform myUniformBuffer
886 %11 = OpTypeStruct %10
887 %12 = OpTypePointer Uniform %11
888 %13 = OpVariable %12 Uniform
889 * @todo pull data out of OpDecorate ( Block )
893 bool TestUniformBufferDescriptor( SPIRVOpCode& opcode )
895 auto opPointer = &FindByResultId( opcode.GetParameterU32(0) );
896 if( (opPointer && *opPointer == SpvOpTypePointer) && opPointer->GetParameter<SpvStorageClass>( 1 ) == SpvStorageClassUniform )
898 auto& opTypeStruct = GetReferencedOpCode( *opPointer, 2 );
899 if( opTypeStruct == SpvOpTypeStruct )
901 return CheckDecorationForOpId( opTypeStruct, SpvDecorationBlock );
907 bool TestStorageBufferDescriptor( SPIRVOpCode& opcode )
909 auto opPointer = FindByResultId( opcode );
910 if( (opPointer && *opPointer == SpvOpTypePointer) && opPointer->GetParameter<SpvStorageClass>( 1 ) == SpvStorageClassUniform )
912 auto& opTypeStruct = GetReferencedOpCode( *opPointer, 2 );
913 if( opTypeStruct == SpvOpTypeStruct )
915 return CheckDecorationForOpId( opTypeStruct, SpvDecorationBufferBlock );
921 std::vector<vk::DescriptorSetLayoutCreateInfo> GenerateDescriptorSetLayoutCreateInfo() const
923 auto retval = std::vector<vk::DescriptorSetLayoutCreateInfo>{};
924 for( auto& layout : descriptorSetLayoutCreateInfoMap )
926 retval.emplace_back( layout.second.createInfo );
932 bool GetVertexInputAttributes( std::vector<SPIRVVertexInputAttribute>& out, bool canOverlap = false )
934 for( auto&& i : reflectionData )
936 if( i.second.storage == SpvStorageClassInput )
938 auto attr = SPIRVVertexInputAttribute{};
939 attr.name = i.second.name;
940 attr.location = MapContains( i.second.decorations, SpvDecorationLocation ) ?
941 i.second.decorations[SpvDecorationLocation]->GetParameterU32(2) : 0u;
942 attr.format = GetTypeInfo(
943 GetReferencedOpCode( GetReferencedOpCode( *i.second.op, 0 ), 2)
945 out.emplace_back( attr );
953 * Tests if the header is valid for SPIR-V
958 header = *reinterpret_cast<Header*>( data.data() );
959 return MAGIC_NUMBER == header.magicNumber;
963 std::vector<SPIRVOpCode> opCodes; // contains all opcodes
964 std::vector<SPIRVOpCode*> opResults; // links to the resulting opcode or nullptr if opcode doesn't return
966 std::unordered_map<uint32_t, SPIRVReflectionData> reflectionData;
967 std::unordered_map<uint32_t, DescriptorSetLayoutAndBindingInfo> descriptorSetLayoutCreateInfoMap;
969 std::vector<SPIRVWord> data;
972 std::vector<SPIRVUniformBlock> uniformBlockReflection;
973 std::vector<SPIRVUniformOpaque> uniformOpaqueReflection;
978 /**************************************************************************************
982 SPIRVShader::SPIRVShader() = default;
984 SPIRVShader::~SPIRVShader() = default;
986 SPIRVShader::SPIRVShader( SPIRVShader&& shader ) noexcept = default;
988 SPIRVShader::SPIRVShader( Impl& impl )
990 mImpl.reset( &impl );
993 SPIRVShader::SPIRVShader( std::vector<SPIRVWord> code, vk::ShaderStageFlags stages )
995 mImpl = std::make_unique<Impl>( code, stages );
998 std::vector<vk::DescriptorSetLayoutCreateInfo> SPIRVShader::GenerateDescriptorSetLayoutCreateInfo() const
1000 return mImpl->GenerateDescriptorSetLayoutCreateInfo();
1003 uint32_t SPIRVShader::GetOpCodeCount() const
1005 return static_cast<uint32_t>( mImpl->opCodes.size() );
1008 const SPIRVOpCode* SPIRVShader::GetOpCodeAt( uint32_t index ) const
1010 return &mImpl->opCodes[index];
1013 const SPIRVOpCode* SPIRVShader::GetOpCodeForResultId( uint32_t resultId ) const
1015 return mImpl->opResults[resultId];
1018 SPIRVWord SPIRVShader::GetOpCodeParameterWord( const SPIRVOpCode& opCode, uint32_t index ) const
1020 return GetOpCodeParameter<SPIRVWord>( opCode, index );
1023 SpvOp SPIRVShader::GetOpCodeType( SPIRVOpCode& opCode )
1028 const uint32_t* SPIRVShader::GetOpCodeParameterPtr( const SPIRVOpCode& opCode, uint32_t index ) const
1030 return ( opCode.localData.start + index + 1 );
1033 void SPIRVShader::GetVertexInputAttributes( std::vector<SPIRVVertexInputAttribute>& out ) const
1035 mImpl->GetVertexInputAttributes( out );
1038 const std::vector<SPIRVUniformBlock>& SPIRVShader::GetUniformBlocks() const
1040 return mImpl->uniformBlockReflection;
1043 const std::vector<SPIRVUniformOpaque>& SPIRVShader::GetOpaqueUniforms() const
1045 return mImpl->uniformOpaqueReflection;
1048 bool SPIRVShader::FindUniformMemberByName( const std::string& uniformName, SPIRVUniformBlockMember& out ) const
1050 for( auto&& ubo : mImpl->uniformBlockReflection )
1052 for( auto&& member : ubo.members )
1054 if( member.name == uniformName )
1064 /**************************************************************************************
1073 std::unique_ptr<SPIRVShader> SPIRVUtils::Parse( std::vector<SPIRVWord> data, vk::ShaderStageFlags stages )
1075 auto shader = std::unique_ptr<SPIRVShader>( new SPIRVShader( data, stages ) );
1076 if( !shader->GetImplementation().Initialise() )
1083 std::unique_ptr<SPIRVShader> SPIRVUtils::Parse( const SPIRVWord* data, size_t sizeInBytes, vk::ShaderStageFlags stages )
1085 std::vector<SPIRVWord> spirvCode{};
1086 auto wordSize = sizeInBytes / sizeof( SPIRVWord );
1087 spirvCode.resize( wordSize );
1088 std::copy( data, data + wordSize, spirvCode.begin() );
1089 return Parse( spirvCode, stages );
1092 } // namespace SpirV
1094 } // namespace Vulkan
1096 } // namespace Graphics