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