[Vulkan] SPIRV simplified reflection ( work in progress )
[platform/core/uifw/dali-core.git] / dali / graphics / vulkan / vulkan-pipeline.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 <dali/graphics/vulkan/vulkan-pipeline.h>
19 #include <dali/graphics/vulkan/vulkan-graphics.h>
20 #include <dali/graphics/vulkan/vulkan-surface.h>
21 #include <dali/graphics/vulkan/vulkan-descriptor-set.h>
22 #include <dali/graphics/vulkan/spirv/vulkan-spirv.h>
23
24 namespace Dali
25 {
26 namespace Graphics
27 {
28 namespace Vulkan
29 {
30
31 namespace
32 {
33 static const vk::ShaderStageFlags DEFAULT_SHADER_STAGES{ vk::ShaderStageFlagBits::eVertex|vk::ShaderStageFlagBits::eFragment };
34 }
35
36 /**
37  * Class Pipeline::Impl
38  * Internal implementation of the pipeline
39  */
40 struct Pipeline::Impl
41 {
42
43
44   Impl( Vulkan::Graphics& graphics, const vk::GraphicsPipelineCreateInfo& info ) :
45     mInfo( info ),
46     mGraphics( graphics )
47   {
48   };
49
50   Impl() = default;
51   ~Impl()
52   {
53     if(mPipelineLayout)
54     {
55       mGraphics.GetDevice().destroyPipelineLayout( mPipelineLayout, mGraphics.GetAllocator() );
56     }
57     if(mPipeline)
58     {
59       mGraphics.GetDevice().destroyPipeline( mPipeline, mGraphics.GetAllocator() );
60     }
61   }
62
63   /**
64    *
65    * @return
66    */
67   vk::Pipeline GetVkPipeline() const
68   {
69     return mPipeline;
70   }
71
72   vk::Result Initialise()
73   {
74     if( !ValidateShaderModules() )
75     {
76       return vk::Result::eErrorInitializationFailed;
77     }
78
79     CreatePipelineLayout();
80
81     // use default render pass for default framebuffer
82     // TODO: swapchain/surface should use vulkan-framebuffer object
83     // in place of swapchain structures!
84     if( !mInfo.renderPass )
85     {
86       SetRenderPass( mGraphics.GetSurface( 0 ).GetRenderPass() );
87     }
88
89     SetRasterizationState();
90
91     SetDepthStencilState();
92
93     SetMultisampleState();
94
95     SetColorBlendState();
96
97     mInfo.setFlags( vk::PipelineCreateFlagBits::eAllowDerivatives );
98     // create pipeline
99     mPipeline = VkAssert( mGraphics.GetDevice().createGraphicsPipeline( nullptr, mInfo, mGraphics.GetAllocator() ) );
100     if(mPipeline)
101     {
102       return vk::Result::eSuccess;
103     }
104     return vk::Result::eErrorInitializationFailed;
105   }
106
107   void SetRenderPass( vk::RenderPass renderpass )
108   {
109     mInfo.setRenderPass( renderpass );
110   }
111
112   void SetDepthStencilState()
113   {
114     mDepthStencilState = vk::PipelineDepthStencilStateCreateInfo{};
115     mDepthStencilState.setDepthBoundsTestEnable( false );
116     mDepthStencilState.setStencilTestEnable( false );
117     mInfo.setPDepthStencilState( & mDepthStencilState );
118   }
119
120   void SetMultisampleState()
121   {
122     mMultisampleState = vk::PipelineMultisampleStateCreateInfo{};
123     mMultisampleState.setSampleShadingEnable( false );
124     mMultisampleState.setRasterizationSamples( vk::SampleCountFlagBits::e1);
125     mMultisampleState.setAlphaToCoverageEnable( false );
126     mMultisampleState.setMinSampleShading( 1.0f );
127     mMultisampleState.setPSampleMask( nullptr );
128     mInfo.setPMultisampleState( &mMultisampleState );
129   }
130
131   void SetVertexInputState(
132     std::vector<vk::VertexInputAttributeDescription> attrDesc,
133     std::vector<vk::VertexInputBindingDescription> bindingDesc)
134   {
135     mBindingDesc.clear();
136     mAttrDesc.clear();
137     mVertexInputState = vk::PipelineVertexInputStateCreateInfo{};
138     mVertexInputState.setPVertexAttributeDescriptions( (mAttrDesc = attrDesc).data() );
139     mVertexInputState.setPVertexBindingDescriptions( (mBindingDesc = bindingDesc).data() );
140     mVertexInputState.setVertexAttributeDescriptionCount( U32(mAttrDesc.size()) );
141     mVertexInputState.setVertexBindingDescriptionCount( U32(mBindingDesc.size()) );
142     mInfo.setPVertexInputState( &mVertexInputState );
143   }
144
145   /**
146    * Sets the viewport on uncompiled pipeline
147    * @return
148    */
149   void SetViewport( float x, float y, float width, float height )
150   {
151     assert( !mPipeline && "Pipeline cannot be changed anymore!");
152
153     // AB: add scissor, read data from graphics for fullscreen viewport
154     // simplified mode for the demo purposes
155     mViewports.emplace_back( x, y, width, height );
156     mViewports[0].setMinDepth( 0.0f );
157     mViewports[0].setMaxDepth( 1.0f );
158     mScissors = vk::Rect2D( { static_cast<int32_t>(x), static_cast<int32_t>(y) },
159                             { U32(width), U32(height) });
160     mViewportState = vk::PipelineViewportStateCreateInfo{}.
161            setViewportCount( U32(mViewports.size()) ).
162            setPViewports( mViewports.data() ).
163            setPScissors( &mScissors ).
164            setScissorCount( 1 );
165
166     // replace viewport state
167     mInfo.setPViewportState( &mViewportState );
168   }
169
170   /**
171    *
172    * @param topology
173    * @param restartEnable
174    */
175   void SetInputAssemblyState( vk::PrimitiveTopology topology, bool restartEnable )
176   {
177     mInputAssemblyState = vk::PipelineInputAssemblyStateCreateInfo{};
178     mInputAssemblyState.setPrimitiveRestartEnable( restartEnable );
179     mInputAssemblyState.setTopology( topology );
180     mInfo.setPInputAssemblyState( &mInputAssemblyState );
181   }
182
183   void SetRasterizationState()
184   {
185     mRasterizationState = vk::PipelineRasterizationStateCreateInfo{};
186     mRasterizationState.setCullMode( vk::CullModeFlagBits::eNone );
187     mRasterizationState.setDepthBiasClamp( 0.0f );
188     mRasterizationState.setDepthBiasEnable( false );
189     mRasterizationState.setDepthClampEnable( false );
190     mRasterizationState.setFrontFace( vk::FrontFace::eCounterClockwise );
191     mRasterizationState.setPolygonMode( vk::PolygonMode::eFill );
192     mRasterizationState.setRasterizerDiscardEnable( false );
193     mRasterizationState.setLineWidth( 1.0f );
194     mInfo.setPRasterizationState( & mRasterizationState );
195   }
196
197   void SetColorBlendState()
198   {
199     mAttachementNoBlendState = vk::PipelineColorBlendAttachmentState{};
200     //mAttachementNoBlendState.setBlendEnable( true );
201     mAttachementNoBlendState.setColorWriteMask( vk::ColorComponentFlagBits::eR |
202                                                   vk::ColorComponentFlagBits::eG |
203                                                   vk::ColorComponentFlagBits::eB |
204                                                   vk::ColorComponentFlagBits::eA );
205
206     mColorBlendState.setBlendConstants( { 1.0f, 1.0f, 1.0f, 1.0f });
207     mColorBlendState = vk::PipelineColorBlendStateCreateInfo{};
208     mColorBlendState.setAttachmentCount( 1 );
209     mColorBlendState.setPAttachments( &mAttachementNoBlendState );
210     mInfo.setPColorBlendState(&mColorBlendState);
211   }
212
213   /**
214    * Sets the shader. Must be set before compiling the pipeline, compiled pipeline
215    * becomes immutable.
216    * @param shader
217    * @param stage
218    * @return
219    */
220   bool SetShader( ShaderRef shader, Shader::Type stage )
221   {
222     assert( !mPipeline && "Pipeline cannot be changed anymore!");
223
224     // check if shader isn't orphaned for some reason
225     if( !mGraphics.FindShader( *shader ) )
226     {
227       return false;
228     }
229
230     auto info = vk::PipelineShaderStageCreateInfo{}.
231                                                      setModule( *shader ).
232                                                      setStage( static_cast<vk::ShaderStageFlagBits>( stage ) ).
233                                                      setPName( "main" );
234     mShaderStageCreateInfo.push_back( info );
235     mShaderResources.push_back( shader );
236
237     mInfo.setPStages( mShaderStageCreateInfo.data() );
238     mInfo.setStageCount( static_cast<uint32_t>(mShaderStageCreateInfo.size()) );
239
240     return false;
241   }
242
243   /**
244    * Creates deferred pipeline layout. Since not all the shader modules
245    * are supplied in one go the layout creation first must instantiate
246    * correct descriptor set layouts.
247    *
248    * @todo: Store SPIRV data of shader modules in the cache rather than
249    * parsing every time
250    */
251 #pragma GCC diagnostic push
252 #pragma GCC diagnostic ignored "-Wframe-larger-than="
253   void CreatePipelineLayout()
254   {
255     // pull desciptor set layouts from shaders
256     auto layoutInfo = vk::PipelineLayoutCreateInfo{};
257
258     using DSLayoutBindingArray = std::vector<vk::DescriptorSetLayoutBinding>;
259
260     std::vector<DSLayoutBindingArray> allDescriptorSetLayouts;
261
262     // concatenate all bindings
263     // TODO: @todo validate if there are weird overlaps!
264     for( auto&& shader : mShaderResources )
265     {
266       const auto& reflection = shader->GetSPIRVReflection();
267       auto layouts = reflection.GenerateDescriptorSetLayoutCreateInfo();
268
269       if(allDescriptorSetLayouts.size() < layouts.size())
270       {
271         allDescriptorSetLayouts.resize(layouts.size());
272       }
273
274       for( auto i = 0u; i < layouts.size(); ++i )
275       {
276         auto currIndex = allDescriptorSetLayouts[i].size();
277         allDescriptorSetLayouts[i].insert( allDescriptorSetLayouts[i].end(),
278         layouts[i].pBindings, layouts[i].pBindings + layouts[i].bindingCount );
279         for( auto j = 0u; j < layouts[i].bindingCount; ++j )
280         {
281           allDescriptorSetLayouts[i][j+currIndex].setStageFlags( GetShaderStage( shader ) );
282         }
283       }
284     }
285
286     // create descriptor set layouts for the pipeline
287     std::vector<vk::DescriptorSetLayout> dsLayouts{};
288     dsLayouts.resize( allDescriptorSetLayouts.size() );
289     mDSCreateInfoArray.clear();
290     for( auto i = 0u; i < allDescriptorSetLayouts.size(); ++i )
291     {
292       auto info = vk::DescriptorSetLayoutCreateInfo{}.
293                     setBindingCount( static_cast<uint32_t>(allDescriptorSetLayouts[i].size()) ).
294                     setPBindings( allDescriptorSetLayouts[i].data() );
295
296       mDSCreateInfoArray.push_back( info );
297       dsLayouts[i] = VkAssert( mGraphics.GetDevice().createDescriptorSetLayout( info, mGraphics.GetAllocator() ) );
298     }
299
300     // create pipeline layout
301     layoutInfo.setPSetLayouts( dsLayouts.data() );
302     layoutInfo.setSetLayoutCount( static_cast<uint32_t>(dsLayouts.size()) );
303
304     mPipelineLayout = VkAssert( mGraphics.GetDevice().createPipelineLayout( layoutInfo, mGraphics.GetAllocator() ) );
305
306     mDSLayoutArray = dsLayouts;
307     mInfo.setLayout( mPipelineLayout );
308   }
309 #pragma GCC diagnostic pop
310
311   vk::ShaderStageFlagBits GetShaderStage( ShaderRef shader )
312   {
313     for( auto&& stage : mShaderStageCreateInfo )
314     {
315       if( stage.module == *shader )
316       {
317         return stage.stage;
318       }
319     }
320     return vk::ShaderStageFlagBits{};
321   }
322
323   bool Compile()
324   {
325     return Initialise() == vk::Result::eSuccess;
326   }
327
328   bool ValidateShaderModules()
329   {
330     for( auto i = 0u; i < mInfo.stageCount; ++i )
331     {
332       const auto& stage = mInfo.pStages[i];
333       auto shaderHandle = mGraphics.FindShader( stage.module );
334       if( shaderHandle )
335       {
336         bool tracked { false };
337         for(auto&& sh : mShaderResources )
338         {
339           if( sh == shaderHandle )
340           {
341             tracked = true;
342           }
343         }
344         if(!tracked)
345         {
346           mShaderResources.push_back(shaderHandle);
347         }
348       }
349       else
350       {
351         return false; // invalid shader! Can't track it
352       }
353     }
354     return true;
355   }
356
357
358   vk::GraphicsPipelineCreateInfo  mInfo           {    };
359   vk::Pipeline                    mPipeline       { nullptr };
360   uint32_t                        mModified       { 0u };
361   Graphics&                       mGraphics;
362
363   // resources
364   std::vector<ShaderRef>     mShaderResources;
365
366   vk::PipelineViewportStateCreateInfo mViewportState {};
367   std::vector<vk::Viewport> mViewports {};
368   vk::Rect2D mScissors {};
369
370   std::vector<vk::PipelineShaderStageCreateInfo> mShaderStageCreateInfo;
371   vk::PipelineLayout mPipelineLayout{};
372   std::vector<vk::DescriptorSetLayoutCreateInfo>    mDSCreateInfoArray{};
373   std::vector<vk::DescriptorSetLayout>              mDSLayoutArray{};
374
375   // vertex input state
376   vk::PipelineVertexInputStateCreateInfo            mVertexInputState {};
377   std::vector<vk::VertexInputAttributeDescription>  mAttrDesc;
378   std::vector<vk::VertexInputBindingDescription>    mBindingDesc;
379
380   // vertex input assembly state
381   vk::PipelineInputAssemblyStateCreateInfo          mInputAssemblyState {};
382
383   // rasterization state
384   vk::PipelineRasterizationStateCreateInfo          mRasterizationState {};
385
386   // Dpeth/stencil state
387   vk::PipelineDepthStencilStateCreateInfo           mDepthStencilState {};
388
389   // Multisample state
390   vk::PipelineMultisampleStateCreateInfo            mMultisampleState {};
391
392   // Color blend
393   vk::PipelineColorBlendStateCreateInfo             mColorBlendState {};
394   vk::PipelineColorBlendAttachmentState             mAttachementNoBlendState {};
395 };
396
397 /*********************************************************************
398  * Class Pipeline
399  *
400  */
401
402 PipelineRef Pipeline::New( Graphics& graphics, const vk::GraphicsPipelineCreateInfo& info )
403 {
404   auto pipeline = Handle<Pipeline>( new Pipeline(graphics, info) );
405   graphics.AddPipeline(pipeline);
406   return pipeline;
407 }
408
409 Pipeline::~Pipeline() = default;
410
411 Pipeline::Pipeline( Graphics& graphics, const vk::GraphicsPipelineCreateInfo& info )
412 {
413   mImpl = MakeUnique<Pipeline::Impl>( graphics, info );
414 }
415
416 vk::Pipeline Pipeline::GetVkPipeline() const
417 {
418   return mImpl->GetVkPipeline();
419 }
420
421 bool Pipeline::OnDestroy()
422 {
423   return false;
424 }
425
426 void Pipeline::SetViewport( float x, float y, float width, float height )
427 {
428   mImpl->SetViewport( x, y, width, height );
429 }
430
431 bool Pipeline::SetShader( ShaderRef shader, Shader::Type stage )
432 {
433   return mImpl->SetShader( shader, stage );
434 }
435
436 void Pipeline::SetVertexInputState(std::vector<vk::VertexInputAttributeDescription> attrDesc,
437                          std::vector<vk::VertexInputBindingDescription> bindingDesc)
438 {
439   mImpl->SetVertexInputState( attrDesc, bindingDesc );
440 }
441
442 void Pipeline::SetInputAssemblyState( vk::PrimitiveTopology topology, bool restartEnable )
443 {
444   mImpl->SetInputAssemblyState( topology, restartEnable );
445 }
446
447 bool Pipeline::Compile()
448 {
449   return mImpl->Compile();
450 }
451
452 vk::PipelineLayout Pipeline::GetVkPipelineLayout() const
453 {
454   return mImpl->mPipelineLayout;
455 }
456
457 const std::vector<vk::DescriptorSetLayoutCreateInfo>& Pipeline::GetVkDescriptorSetLayoutCreateInfo() const
458 {
459   return mImpl->mDSCreateInfoArray;
460 }
461
462 const std::vector<vk::DescriptorSetLayout>& Pipeline::GetVkDescriptorSetLayouts() const
463 {
464   return mImpl->mDSLayoutArray;
465 }
466
467 } // namespace Vulkan
468
469 } // namespace Graphics
470
471 } // namespace Dali