[Vulkan] Cleanup after removing rendering backend
[platform/core/uifw/dali-core.git] / dali / graphics / vulkan / spirv / vulkan-spirv.cpp
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 #include <iostream>
19
20 #include <dali/graphics/vulkan/spirv/vulkan-spirv.h>
21 #include <dali/graphics/vulkan/spirv/vulkan-spirv-opcode.h>
22
23 #define debug( x ) std::cout << x << std::endl;
24
25 namespace Dali
26 {
27 namespace Graphics
28 {
29 namespace Vulkan
30 {
31 namespace SpirV
32 {
33 SPIRVShader::Impl& SPIRVShader::GetImplementation() const
34 {
35   return *mImpl;
36 }
37
38 struct SPIRVShader::Impl
39 {
40   /**
41    * 32bit word needed to identify SPIRV code
42    */
43   static constexpr uint32_t MAGIC_NUMBER{0x07230203u};
44
45   /**
46    * SPIRV header binary structure
47    */
48   struct Header
49   {
50     uint32_t magicNumber;
51     uint32_t versionNumber; // 0 | major | minor | 0
52     uint32_t generatorMagicNumber;
53     uint32_t bound;
54     uint32_t reserved;
55   };
56
57   /**
58    * Stores descriptorset bindings and createinfo data used by reflection
59    */
60   struct DescriptorSetLayoutAndBindingInfo
61   {
62     std::vector<vk::DescriptorSetLayoutBinding> bindings;
63     vk::DescriptorSetLayoutCreateInfo createInfo;
64   };
65
66   SPIRVOpCode& FindByResultId( uint32_t resultId ) const
67   {
68     return *(opResults[resultId] );
69   }
70
71   SPIRVOpCode* FindByResultId( SPIRVOpCode& opcode ) const
72   {
73     if(!opcode.hasResult)
74     {
75       return nullptr;
76     }
77     return opResults[opcode.localData.resultId];
78   }
79
80   SPIRVOpCode* FindByResultPtrId( uint32_t resultId ) const
81   {
82     if( resultId < opResults.size() )
83     {
84       return opResults[resultId];
85     }
86     return nullptr;
87   }
88
89   /**
90    * Constructor
91    * @param pData
92    * @param size
93    * @param stages
94    */
95   Impl( void* pData, std::size_t size, vk::ShaderStageFlags stages )
96   {
97     data.resize( size );
98     auto begin = reinterpret_cast<uint32_t*>( pData );
99     auto end   = begin + size;
100     std::copy( begin, end, data.begin() );
101   }
102
103   /**
104    * Constructor
105    * @tparam T
106    * @param buffer
107    * @param stages
108    */
109   template<typename T>
110   explicit Impl( std::vector<T> buffer, vk::ShaderStageFlags stages )
111   {
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() );
116   }
117
118   auto FindDecorationsForId( uint32_t id )
119   {
120     std::vector<SPIRVOpCode*> retval{};
121     for( auto&& op : opCodes )
122     {
123       if( op.code == SpvOpDecorate && op.GetParameterU32( 0 ) == id )
124       {
125         retval.push_back( &op );
126       }
127     }
128     return retval;
129   }
130
131   auto FindMemberDecorationsForId( uint32_t id, uint32_t memberIndex )
132   {
133     std::vector<SPIRVOpCode*> retval{};
134     for( auto&& op : opCodes )
135     {
136       if( op.code == SpvOpMemberDecorate && op.GetParameterU32( 0 ) == id && op.GetParameterU32( 1 ) == memberIndex )
137       {
138         retval.push_back( &op );
139       }
140     }
141     return retval;
142   }
143
144   SPIRVOpCode& GetReferencedOpCode( const SPIRVOpCode& opCode, uint32_t refIndex ) const
145   {
146     return FindByResultId( opCode.GetParameterU32( refIndex ) );
147   }
148
149   auto GetDecorationsOpId( const SPIRVOpCode& resultOp )
150   {
151     std::vector<SPIRVOpCode*> retval;
152     if( resultOp.hasResult )
153     {
154       for( auto&& op : opCodes )
155       {
156         if( op == SpvOpDecorate && op.GetParameterU32( 0 ) == resultOp.localData.resultId )
157         {
158           retval.push_back( &op );
159         }
160       }
161     }
162     return retval;
163   }
164
165   bool CheckDecorationForOpId( const SPIRVOpCode& resultOp, SpvDecoration expectedDecoration )
166   {
167     if( resultOp.hasResult )
168     {
169       for( auto&& op : opCodes )
170       {
171         if( op == SpvOpDecorate && op.GetParameterU32( 0 ) == resultOp.localData.resultId &&
172             op.GetParameter<SpvDecoration>( 1 ) == expectedDecoration )
173         {
174           return true;
175         }
176       }
177     }
178     return false;
179   }
180
181   struct SPIRVReflectionData
182   {
183     SPIRVReflectionData() = default;
184     SPIRVReflectionData( const SPIRVReflectionData& ) = default;
185     SPIRVReflectionData& operator=( const SPIRVReflectionData& ) = default;
186     SPIRVReflectionData( SPIRVReflectionData&& ) = delete;
187     SPIRVReflectionData& operator=( SPIRVReflectionData&& ) = delete;
188
189     std::string                                     name{};
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};
196   };
197
198   template<class M, class K>
199   bool MapContains( const M& map, const K& key ) const
200   {
201     return map.find( key ) != map.end();
202   }
203
204
205   template<class V>
206   struct GetResult
207   {
208     GetResult( bool v, V& value)
209     : success(v), result(&value)
210     {
211     }
212
213     GetResult( bool v )
214       : success(v), result(nullptr)
215     {
216     }
217
218     operator V&()
219     {
220       return *result;
221     }
222
223     operator V*()
224     {
225       return result;
226     }
227
228     GetResult() : success( false ), result(nullptr){}
229     bool  success;
230     V*     result;
231   };
232
233   template<class K, class V>
234   GetResult<V> GetMapItem( std::unordered_map<K,V>& map, const K& key )
235   {
236     auto iter = map.find( key );
237     if( iter == map.end() )
238     {
239       return GetResult<V>( false );
240     }
241
242     return GetResult<V>( true, iter->second );
243   }
244
245   struct SPIRVTypeInfo
246   {
247     vk::Format  vkFormat;
248     uint32_t    sizeInBytes;
249     uint32_t    components;
250     uint32_t    rows;
251     uint32_t    componentSizeInBytes;
252   };
253
254   auto GetTypeInfo( const SPIRVOpCode& typeOpCode ) const
255   {
256     auto retval = SPIRVTypeInfo{};
257
258     const vk::Format VEC[] =
259                        {
260                          vk::Format::eUndefined,
261                          vk::Format::eR32Sfloat,
262                          vk::Format::eR32G32Sfloat,
263                          vk::Format::eR32G32B32Sfloat,
264                          vk::Format::eR32G32B32A32Sfloat,
265                        };
266
267     // note: always assumed:
268     // - not normalized
269     // - float
270     // - signed
271     if( typeOpCode == SpvOpTypeMatrix )
272     {
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];
278     }
279     else if(typeOpCode == SpvOpTypeVector)
280     {
281       retval.components = typeOpCode.GetParameterU32( 2 );
282       retval.rows = 1;
283       retval.componentSizeInBytes = sizeof(float);
284       retval.sizeInBytes = retval.components*retval.componentSizeInBytes;
285       retval.vkFormat = VEC[retval.components];
286     }
287     else if(typeOpCode == SpvOpTypeFloat)
288     {
289       retval.components = 1;
290       retval.rows = 1;
291       retval.componentSizeInBytes = sizeof(float);
292       retval.sizeInBytes = sizeof(float);
293       retval.vkFormat = vk::Format::eR32Sfloat;
294     }
295     else if(typeOpCode == SpvOpTypeInt)
296     {
297       retval.components = 1;
298       retval.rows = 1;
299       retval.componentSizeInBytes = sizeof(uint32_t);
300       retval.sizeInBytes = sizeof(uint32_t);
301       retval.vkFormat = vk::Format::eR32Sint;
302     }
303     else
304     {
305       retval.components = 0;
306       retval.rows = 0;
307       retval.componentSizeInBytes = 0;
308       retval.sizeInBytes = 0;
309       retval.vkFormat = vk::Format::eUndefined;
310     }
311
312     return retval;
313   }
314
315
316
317   auto BuildReflection()
318   {
319     // collect variables
320     using MemberNameArray = std::vector<SPIRVOpCode*>;
321     auto vars = std::vector<SPIRVOpCode*>{};
322     auto opNames = std::unordered_map<uint32_t, SPIRVOpCode*>{};
323
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 )
327     {
328       auto id = op.GetParameterU32(0);
329       if( op == SpvOpVariable )
330       {
331         vars.push_back( &op );
332       }
333       else if( op == SpvOpName )
334       {
335         opNames.emplace( id, &op );
336       }
337       else if( op == SpvOpMemberName )
338       {
339         GetResult<MemberNameArray> result{};
340         MemberNameArray* memberNames{ nullptr };
341         if( !(result = GetMapItem( opMemberNames, id )).success )
342         {
343           opMemberNames.emplace(id, MemberNameArray{} );
344           memberNames = &opMemberNames[id];
345         }
346         else
347         {
348           memberNames = result.result;
349         }
350
351         if(memberNames->size() <= op.GetParameterU32(1))
352           memberNames->resize( op.GetParameterU32(1)+1 );
353         (*memberNames)[op.GetParameterU32(1)] = &op;
354       }
355     }
356
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 )
363     {
364       auto storage = op->GetParameter<SpvStorageClass>( 2 );
365       bool varFound{false};
366       if( storage == SpvStorageClassUniform || storage == SpvStorageClassUniformConstant )
367       {
368         uniformVariables.emplace_back( op );
369         varFound = true;
370       }
371       else if( storage == SpvStorageClassInput )
372       {
373         inputVariables.emplace_back( op );
374         varFound = true;
375       }
376       else if( storage == SpvStorageClassOutput )
377       {
378         outputVariables.emplace_back( op );
379         varFound = true;
380       }
381
382       // find decorations if variable
383       if( varFound )
384       {
385         auto id = op->localData.resultId;
386         auto decorations = FindDecorationsForId( id );
387         SPIRVReflectionData decorationInfo;
388         decorationInfo.op = op;
389         decorationInfo.storage = storage;
390
391         // update descriptor type if viable
392         decorationInfo.descriptorType = FindDescriptorTypeForVariable( *op );
393
394         for( auto&& decoration : decorations )
395         {
396           auto decorationQualifier = decoration->GetParameter<SpvDecoration>( 1 );
397           decorationInfo.decorations.emplace( decorationQualifier, decoration );
398           std::cout << decorationQualifier << std::endl;
399         }
400         decorationVariables.emplace( id, decorationInfo );
401
402         // store name if element is named
403         GetResult<SPIRVOpCode*> name{};
404
405         bool foundName = false;
406         if( (name = GetMapItem( opNames, id )).success )
407         {
408
409           // variable may not be named ( global scope of the shader )
410           if( !(*name.result)->GetParameterAsString( 1 ).empty() )
411           {
412             std::cout <<"Found name\n";
413             decorationVariables[id].name = (*name.result)->GetParameterAsString( 1 );
414             foundName = true;
415           }
416         }
417
418         // continue if name hasn't been found, this means the variable is an uniform
419         // in the global scope
420         if( !foundName )
421         {
422           auto pointerId = op->GetParameterU32(0);
423           auto pointer = FindByResultId( pointerId );
424           auto pointerToType = FindByResultId( pointer.GetParameterU32(2) );
425
426           // find name of the structure
427           GetResult<SPIRVOpCode*> retval{};
428           if( (retval = GetMapItem( opNames, pointerToType.localData.resultId )).success )
429           {
430             std::cout << "Found: " << (*retval.result)->GetParameterAsString(1) << std::endl;
431             decorationVariables[id].name = (*retval.result)->GetParameterAsString(1);
432           }
433
434           // depending on the type, we may need to extract members, member types as well
435           // as other relevant data
436           if( pointerToType == SpvOpTypeStruct )
437           {
438
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;
442
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 )
446             {
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 );
452
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 )
456               {
457                 memberOpInfo.decorations.emplace( mop->GetParameter<SpvDecoration>( 2 ), mop );
458               }
459               decorationVariables[id].members.emplace_back(memberOpInfo);
460               std::cout << "memberName: " << memberName->GetParameterAsString(2);
461               std::cout << std::endl;
462             }
463
464             uint32_t structSize = 0u;
465
466             // for last member update size of the data structure ( for blocks only )
467             if(memberCount)
468             {
469               if( memberCount > 0 )
470               {
471                 auto& lastMember = decorationVariables[id].members.back();
472
473                 if( MapContains( lastMember.decorations, SpvDecorationOffset ) )
474                 {
475                   structSize = lastMember.decorations[SpvDecorationOffset]->GetParameterU32(3);
476                 }
477                 auto typeInfo = GetTypeInfo( *lastMember.op );
478                 structSize += typeInfo.sizeInBytes;
479               }
480               decorationVariables[id].structSize = structSize;
481             }
482             std::cout << "struct size: " << structSize << std::endl;
483           }
484         }
485       }
486     }
487
488     std::cout << "Found " << uniformVariables.size() << " variables\n";
489
490     return decorationVariables;
491   }
492
493   auto LoadOpCodes( const std::vector<SPIRVWord>& _data )
494   {
495     auto retval = std::vector<SPIRVOpCode>{};
496
497     // test if we have valid SPIRV header
498     auto iter = data.begin();
499     if( !CheckHeader() )
500     {
501       debug( "Not SPIRV!" );
502       return retval;
503     }
504
505     debug( "SPIR-V detected" );
506     std::advance( iter, 5u ); // skip header
507
508     while( iter != data.end() )
509     {
510       auto opword    = *iter;
511       auto wordCount = ( ( opword >> 16 ) & 0xFFFF );
512       auto opCode    = ( (opword)&0xFFFF );
513
514       auto& op = FindOpCode( opCode );
515
516       if( op != OP_CODE_NULL )
517       {
518         uint32_t resultIndex{0};
519         int      resultIndexOffset = 1;
520         int32_t  resultType{0u};
521
522         // make a copy
523         retval.emplace_back( op );
524         auto& opcode           = retval.back();
525         opcode.localData.start = &*iter;
526         opcode.localData.count = wordCount;
527
528         // update result type and index for non-void opcodes
529         if( op.hasResultType )
530         {
531           resultIndexOffset++;
532         }
533         if( op.hasResult )
534         {
535           if( op.hasResultType )
536           {
537             resultType = static_cast<int32_t>( *( iter + 1 ) );
538           }
539           resultIndex                 = *( iter + resultIndexOffset );
540           opcode.localData.resultId   = resultIndex;
541           opcode.localData.resultType = resultType;
542         }
543       }
544
545       // next instruction
546       std::advance( iter, wordCount );
547     }
548
549     return retval;
550   }
551
552   auto CreateOpResults( std::vector<SPIRVOpCode>& _opcodes )
553   {
554     auto retval = std::vector<SPIRVOpCode*>{};
555     for( auto i = 0u; i < _opcodes.size(); ++i )
556     {
557       const auto& op = _opcodes[i];
558       if( op.hasResult )
559       {
560         if( retval.size() <= op.localData.resultId )
561         {
562           retval.resize( op.localData.resultId + 1 );
563         }
564         retval[op.localData.resultId] = &_opcodes[i];
565       }
566     }
567     return retval;
568   }
569
570   vk::DescriptorType FindDescriptorTypeForVariable( SPIRVOpCode& opVariable )
571   {
572     vk::DescriptorType descriptorType{};
573
574     auto storageClass = opVariable.GetParameter<SpvStorageClass>(2);
575
576     // we need to detect storage by call into function
577     if (storageClass == SpvStorageClassUniformConstant)
578     {
579       auto& resource = opVariable;
580       if (TestStorageImageDescriptor(resource))
581       {
582         descriptorType = vk::DescriptorType::eStorageImage;
583       }
584       else if(TestSamplerDescriptor(resource))
585       {
586         descriptorType = vk::DescriptorType::eSampler;
587       }
588       else if(TestSampledImageDescriptor(resource))
589       {
590         descriptorType = vk::DescriptorType::eSampledImage;
591       }
592       else if(TestCombinedImageSamplerDescriptor(resource))
593       {
594         descriptorType = vk::DescriptorType::eCombinedImageSampler;
595       }
596       else if(TestUniformTexelBufferDescriptor(resource))
597       {
598         descriptorType = vk::DescriptorType::eUniformTexelBuffer;
599       }
600       else if(TestStorageTexelBufferDescriptor(resource))
601       {
602         descriptorType = vk::DescriptorType::eStorageTexelBuffer;
603       }
604       else
605       {
606         // @todo check the shader, something hasn't been recognized
607         descriptorType = vk::DescriptorType{};
608       }
609
610       if(descriptorType != vk::DescriptorType{})
611       {
612         //uniformResources.push_back( &resource );
613       }
614     }
615     else if(storageClass == SpvStorageClassUniform)
616     {
617       descriptorType = vk::DescriptorType::eUniformBuffer;
618     }
619     return descriptorType;
620   }
621
622   auto GenerateVulkanDescriptorSetLayouts()
623   {
624     // key: descriptor set, value: ds layout create info and binding
625     auto vkDescriptorSetLayoutCreateInfos = std::unordered_map<uint32_t, DescriptorSetLayoutAndBindingInfo>{};
626
627     for(auto&& symbol : reflectionData)
628     {
629       auto storage = symbol.second.storage;
630       auto& symbolData = symbol.second;
631       if( storage == SpvStorageClassUniform || storage == SpvStorageClassUniformConstant )
632       {
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) );
636
637         auto& ds = (MapContains( vkDescriptorSetLayoutCreateInfos, descriptorSet ) ?
638                     vkDescriptorSetLayoutCreateInfos[descriptorSet] :
639                     (*vkDescriptorSetLayoutCreateInfos.emplace( descriptorSet, DescriptorSetLayoutAndBindingInfo{} ).first).second);
640
641
642         ds.bindings.emplace_back( vk::DescriptorSetLayoutBinding{}.setBinding( binding )
643                                                                   .setDescriptorCount( 1 )
644                                                                   .setDescriptorType( symbolData.descriptorType )
645                                                                   .setStageFlags( vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment ) );
646       }
647     }
648
649     // sort bindings and complete create info structures
650     for( auto&& ds : vkDescriptorSetLayoutCreateInfos )
651     {
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();
655     }
656
657     return vkDescriptorSetLayoutCreateInfos;
658   }
659
660   bool Initialise()
661   {
662     // load opcodes
663     opCodes = std::move(LoadOpCodes(data));
664
665     // create results lookup array
666     opResults = std::move(CreateOpResults(opCodes));
667
668     // build reflection map
669     reflectionData = std::move(BuildReflection());
670
671     // build vulkan descriptor set layout infos
672     descriptorSetLayoutCreateInfoMap = std::move(GenerateVulkanDescriptorSetLayouts());
673
674     // generate additional reflection structures
675     uint32_t blockIndex = 0u;
676     for( auto&& symbol : reflectionData )
677     {
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;
681
682       if( symbolData.storage == SpvStorageClassUniform )
683       {
684         auto block = SPIRVUniformBlock{};
685         block.name = symbolData.name;
686         block.size = symbolData.structSize;
687         block.binding = binding;
688         block.descriptorSet = descriptorSet;
689
690         uint32_t location{ 0u };
691         for( auto&& member : symbolData.members )
692         {
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 );
699         }
700         blockIndex++;
701         uniformBlockReflection.emplace_back( block );
702
703       }
704       else if( symbolData.storage == SpvStorageClassUniformConstant )
705       {
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 );
712       }
713     }
714
715     return true;
716   }
717
718   /**
719    * Recognizes descriptor type VkDescriptorTypeStorageImage
720    * GLSL:
721    *      layout (set=m, binding=n, r32f) uniform image2D myStorageImage;
722    *
723    * SPIR-V:
724    *      %7 = OpTypeImage %6 2D 0 0 0 2 R32f
725    *      %8 = OpTypePointer UniformConstant %7
726    *      %9 = OpVariable %8 UniformConstant
727    * @param resource
728    * @return
729    */
730   bool TestStorageImageDescriptor( SPIRVOpCode& opcode )
731   {
732     auto opPointer = &FindByResultId( opcode.GetParameterU32(0) );
733     if( (opPointer && *opPointer == SpvOpTypePointer) )
734     {
735       auto& opTypeImage = GetReferencedOpCode( *opPointer, 2 );
736       if( opTypeImage == SpvOpTypeImage && opTypeImage.GetParameterU32( 6 ) == 2 )
737       {
738         return true;
739       }
740     }
741     return false;
742   }
743
744   /**
745    * Recognizes descriptor type VkDescriptorTypeSampler
746    * GLSL:
747           layout (set=m, binding=n) uniform sampler mySampler;
748    *
749    * SPIR-V:
750           %3 = OpTypeFunction %2
751           %6 = OpTypeSampler
752           %7 = OpTypePointer UniformConstant %6
753           %8 = OpVariable %7 UniformConstant
754
755    * @param resource
756    * @return
757    */
758   bool TestSamplerDescriptor( SPIRVOpCode& opcode )
759   {
760     auto opPointer = &FindByResultId( opcode.GetParameterU32(0) );
761     if( (opPointer && *opPointer == SpvOpTypePointer) )
762     {
763       auto& opTypeSampler = GetReferencedOpCode( *opPointer, 2 );
764       if( opTypeSampler == SpvOpTypeSampler )
765       {
766         return true;
767       }
768     }
769     return false;
770   }
771
772   /**
773    * Recognizes descriptor type VkDescriptorTypeSampledImage
774    * GLSL:
775    *      layout (set=m, binding=n) uniform texture2D mySampledImage;
776    * SPIR_V:
777           %6 = OpTypeFloat 32
778           %7 = OpTypeImage %6 2D 0 0 0 1 Unknown
779           %8 = OpTypePointer UniformConstant %7
780           %9 = OpVariable %8 UniformConstant
781    *
782    * @param resource
783    * @return
784    */
785   bool TestSampledImageDescriptor( SPIRVOpCode& opcode)
786   {
787     auto opPointer = &FindByResultId( opcode.GetParameterU32(0) );
788     if( (opPointer && *opPointer == SpvOpTypePointer) )
789     {
790       auto& opTypeImage = GetReferencedOpCode( *opPointer, 2 );
791       if( opTypeImage == SpvOpTypeImage && opTypeImage.GetParameterU32( 6 ) == 1 )
792       {
793         return true;
794       }
795     }
796     return false;
797   }
798
799   /**
800    * Recognizes descriptor type VkDescriptorTypeCombinedImageSampler
801    * GLSL:
802    *      layout (set=m, binding=n) uniform sampler2D myCombinedImageSampler;
803    * SPIR-V:
804           %7 = OpTypeImage %6 2D 0 0 0 1 Unknown
805           %8 = OpTypeSampledImage %7
806           %9 = OpTypePointer UniformConstant %8
807          %10 = OpVariable %9 UniformConstant
808    * @param resource
809    * @return
810    */
811   bool TestCombinedImageSamplerDescriptor( SPIRVOpCode& opcode )
812   {
813     auto opPointer = &FindByResultId( opcode.GetParameterU32(0) );
814     if( (opPointer && *opPointer == SpvOpTypePointer) )
815     {
816       auto& opCode = GetReferencedOpCode( *opPointer, 2 );
817       if( opCode == SpvOpTypeSampledImage )
818       {
819         return true;
820       }
821     }
822     return false;
823   }
824
825   /**
826    * Recognizes descriptor type VkDescriptorTypeUniformTexelBuffer
827    * GLSL:
828    *      layout (set=m, binding=n) uniform samplerBuffer myUniformTexelBuffer;
829    * SPIR-V:
830             %6 = OpTypeFloat 32
831             %7 = OpTypeImage %6 Buffer 0 0 0 1 Unknown
832             %8 = OpTypePointer UniformConstant %7
833             %9 = OpVariable %8 UniformConstant
834    * @param resource
835    * @return
836    */
837   bool TestUniformTexelBufferDescriptor( SPIRVOpCode& opcode  )
838   {
839     auto opPointer = &FindByResultId( opcode.GetParameterU32(0) );
840     if( (opPointer && *opPointer == SpvOpTypePointer) )
841     {
842       auto& opCode = GetReferencedOpCode( *opPointer, 2 );
843       if( opCode == SpvOpTypeImage && opCode.GetParameter<SpvDim>( 2 ) == SpvDimBuffer &&
844           opCode.GetParameterU32( 6 ) == 1 )
845       {
846         return true;
847       }
848     }
849     return false;
850   }
851
852   /**
853    * Recognizes descriptor type VkDescriptorTypeStorageTexelBuffer
854    * GLSL:
855    *      layout (set=m, binding=n, r32f) uniform imageBuffer myStorageTexelBuffer;
856    * SPIR-V:
857           %7 = OpTypeImage %6 Buffer 0 0 0 2 R32f
858           %8 = OpTypePointer UniformConstant %7
859           %9 = OpVariable %8 UniformConstant
860    * @param resource
861    * @return
862    */
863   bool TestStorageTexelBufferDescriptor( SPIRVOpCode& opcode )
864   {
865     auto opPointer = &FindByResultId( opcode.GetParameterU32(0) );
866     if( (opPointer && *opPointer == SpvOpTypePointer) )
867     {
868       auto& opCode = GetReferencedOpCode( *opPointer, 2 );
869       if( opCode == SpvOpTypeImage && opCode.GetParameter<SpvDim>( 2 ) == SpvDimBuffer &&
870           opCode.GetParameterU32( 6 ) == 2 )
871       {
872         return true;
873       }
874     }
875     return false;
876   }
877
878   /**
879    * Recognizes descriptor type VkDescriptorTypeUniformBuffer
880    * GLSL:
881           layout (set=m, binding=n) uniform myUniformBuffer
882           {
883               vec4 myElement[32];
884           };
885    * SPIR-V:
886          %11 = OpTypeStruct %10
887          %12 = OpTypePointer Uniform %11
888          %13 = OpVariable %12 Uniform
889    * @todo pull data out of OpDecorate ( Block )
890    * @param resource
891    * @return
892    */
893   bool TestUniformBufferDescriptor( SPIRVOpCode& opcode )
894   {
895     auto opPointer = &FindByResultId( opcode.GetParameterU32(0) );
896     if( (opPointer && *opPointer == SpvOpTypePointer) && opPointer->GetParameter<SpvStorageClass>( 1 ) == SpvStorageClassUniform )
897     {
898       auto& opTypeStruct = GetReferencedOpCode( *opPointer, 2 );
899       if( opTypeStruct == SpvOpTypeStruct )
900       {
901         return CheckDecorationForOpId( opTypeStruct, SpvDecorationBlock );
902       }
903     }
904     return false;
905   }
906
907   bool TestStorageBufferDescriptor( SPIRVOpCode& opcode )
908   {
909     auto opPointer = FindByResultId( opcode );
910     if( (opPointer && *opPointer == SpvOpTypePointer) && opPointer->GetParameter<SpvStorageClass>( 1 ) == SpvStorageClassUniform )
911     {
912       auto& opTypeStruct = GetReferencedOpCode( *opPointer, 2 );
913       if( opTypeStruct == SpvOpTypeStruct )
914       {
915         return CheckDecorationForOpId( opTypeStruct, SpvDecorationBufferBlock );
916       }
917     }
918     return false;
919   }
920
921   std::vector<vk::DescriptorSetLayoutCreateInfo> GenerateDescriptorSetLayoutCreateInfo() const
922   {
923     auto retval = std::vector<vk::DescriptorSetLayoutCreateInfo>{};
924     for( auto& layout : descriptorSetLayoutCreateInfoMap )
925     {
926       retval.emplace_back( layout.second.createInfo );
927     }
928
929     return retval;
930   }
931
932   bool GetVertexInputAttributes( std::vector<SPIRVVertexInputAttribute>& out, bool canOverlap = false )
933   {
934     for( auto&& i : reflectionData )
935     {
936       if( i.second.storage == SpvStorageClassInput )
937       {
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)
944         ).vkFormat;
945         out.emplace_back( attr );
946       }
947     }
948
949     return true;
950   }
951
952   /**
953    * Tests if the header is valid for SPIR-V
954    * @return
955    */
956   bool CheckHeader()
957   {
958     header = *reinterpret_cast<Header*>( data.data() );
959     return MAGIC_NUMBER == header.magicNumber;
960   }
961
962 public:
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
965
966   std::unordered_map<uint32_t, SPIRVReflectionData> reflectionData;
967   std::unordered_map<uint32_t, DescriptorSetLayoutAndBindingInfo>      descriptorSetLayoutCreateInfoMap;
968
969   std::vector<SPIRVWord>    data;
970
971
972   std::vector<SPIRVUniformBlock>                                       uniformBlockReflection;
973   std::vector<SPIRVUniformOpaque>                                      uniformOpaqueReflection;
974   Header                                                               header;
975
976 };
977
978 /**************************************************************************************
979  * SPIRVShader
980  */
981
982 SPIRVShader::SPIRVShader() = default;
983
984 SPIRVShader::~SPIRVShader() = default;
985
986 SPIRVShader::SPIRVShader( SPIRVShader&& shader ) noexcept = default;
987
988 SPIRVShader::SPIRVShader( Impl& impl )
989 {
990   mImpl.reset( &impl );
991 }
992
993 SPIRVShader::SPIRVShader( std::vector<SPIRVWord> code, vk::ShaderStageFlags stages )
994 {
995   mImpl = std::make_unique<Impl>( code, stages );
996 }
997
998 std::vector<vk::DescriptorSetLayoutCreateInfo> SPIRVShader::GenerateDescriptorSetLayoutCreateInfo() const
999 {
1000   return mImpl->GenerateDescriptorSetLayoutCreateInfo();
1001 }
1002
1003 uint32_t SPIRVShader::GetOpCodeCount() const
1004 {
1005   return static_cast<uint32_t>( mImpl->opCodes.size() );
1006 }
1007
1008 const SPIRVOpCode* SPIRVShader::GetOpCodeAt( uint32_t index ) const
1009 {
1010   return &mImpl->opCodes[index];
1011 }
1012
1013 const SPIRVOpCode* SPIRVShader::GetOpCodeForResultId( uint32_t resultId ) const
1014 {
1015   return mImpl->opResults[resultId];
1016 }
1017
1018 SPIRVWord SPIRVShader::GetOpCodeParameterWord( const SPIRVOpCode& opCode, uint32_t index ) const
1019 {
1020   return GetOpCodeParameter<SPIRVWord>( opCode, index );
1021 }
1022
1023 SpvOp SPIRVShader::GetOpCodeType( SPIRVOpCode& opCode )
1024 {
1025   return SpvOpMax;
1026 }
1027
1028 const uint32_t* SPIRVShader::GetOpCodeParameterPtr( const SPIRVOpCode& opCode, uint32_t index ) const
1029 {
1030   return ( opCode.localData.start + index + 1 );
1031 }
1032
1033 void SPIRVShader::GetVertexInputAttributes( std::vector<SPIRVVertexInputAttribute>& out ) const
1034 {
1035   mImpl->GetVertexInputAttributes( out );
1036 }
1037
1038 const std::vector<SPIRVUniformBlock>& SPIRVShader::GetUniformBlocks() const
1039 {
1040   return mImpl->uniformBlockReflection;
1041 }
1042
1043 const std::vector<SPIRVUniformOpaque>& SPIRVShader::GetOpaqueUniforms() const
1044 {
1045   return mImpl->uniformOpaqueReflection;
1046 }
1047
1048 bool SPIRVShader::FindUniformMemberByName( const std::string& uniformName, SPIRVUniformBlockMember& out ) const
1049 {
1050   for( auto&& ubo : mImpl->uniformBlockReflection )
1051   {
1052     for( auto&& member : ubo.members )
1053     {
1054       if( member.name == uniformName )
1055       {
1056         out = member;
1057         return true;
1058       }
1059     }
1060   }
1061   return false;
1062 }
1063
1064 /**************************************************************************************
1065  * SPIRVUtils
1066  */
1067
1068 /**
1069  * SPIRVUtils
1070  * @param data
1071  * @return
1072  */
1073 std::unique_ptr<SPIRVShader> SPIRVUtils::Parse( std::vector<SPIRVWord> data, vk::ShaderStageFlags stages )
1074 {
1075   auto shader = std::unique_ptr<SPIRVShader>( new SPIRVShader( data, stages ) );
1076   if( !shader->GetImplementation().Initialise() )
1077   {
1078     return nullptr;
1079   }
1080   return shader;
1081 }
1082
1083 std::unique_ptr<SPIRVShader> SPIRVUtils::Parse( const SPIRVWord* data, size_t sizeInBytes, vk::ShaderStageFlags stages )
1084 {
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 );
1090 }
1091
1092 } // namespace SpirV
1093
1094 } // namespace Vulkan
1095
1096 } // namespace Graphics
1097
1098 } // namespace Dali