[Vulkan] Sampler and texture support - something is rendering
[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     mAttachementNoBlendState.setSrcColorBlendFactor( vk::BlendFactor::eSrcAlpha );
208     mAttachementNoBlendState.setDstColorBlendFactor( vk::BlendFactor::eOneMinusSrc1Alpha );
209     mAttachementNoBlendState.setSrcAlphaBlendFactor( vk::BlendFactor::eOne );
210     mAttachementNoBlendState.setDstAlphaBlendFactor( vk::BlendFactor::eOneMinusSrc1Alpha );
211     mAttachementNoBlendState.setColorBlendOp( vk::BlendOp::eAdd );
212     mAttachementNoBlendState.setAlphaBlendOp( vk::BlendOp::eAdd );
213
214     mColorBlendState.setBlendConstants( { 1.0f, 1.0f, 1.0f, 1.0f });
215     mColorBlendState = vk::PipelineColorBlendStateCreateInfo{};
216     mColorBlendState.setAttachmentCount( 1 );
217     mColorBlendState.setPAttachments( &mAttachementNoBlendState );
218     mInfo.setPColorBlendState(&mColorBlendState);
219   }
220
221   /**
222    * Sets the shader. Must be set before compiling the pipeline, compiled pipeline
223    * becomes immutable.
224    * @param shader
225    * @param stage
226    * @return
227    */
228   bool SetShader( ShaderRef shader, Shader::Type stage )
229   {
230     assert( !mPipeline && "Pipeline cannot be changed anymore!");
231
232     // check if shader isn't orphaned for some reason
233     if( !mGraphics.FindShader( *shader ) )
234     {
235       return false;
236     }
237
238     auto info = vk::PipelineShaderStageCreateInfo{}.
239                                                      setModule( *shader ).
240                                                      setStage( static_cast<vk::ShaderStageFlagBits>( stage ) ).
241                                                      setPName( "main" );
242     mShaderStageCreateInfo.push_back( info );
243     mShaderResources.push_back( shader );
244
245     mInfo.setPStages( mShaderStageCreateInfo.data() );
246     mInfo.setStageCount( static_cast<uint32_t>(mShaderStageCreateInfo.size()) );
247
248     return false;
249   }
250
251   /**
252    * Creates deferred pipeline layout. Since not all the shader modules
253    * are supplied in one go the layout creation first must instantiate
254    * correct descriptor set layouts.
255    *
256    * @todo: Store SPIRV data of shader modules in the cache rather than
257    * parsing every time
258    */
259 #pragma GCC diagnostic push
260 #pragma GCC diagnostic ignored "-Wframe-larger-than="
261   void CreatePipelineLayout()
262   {
263     // pull desciptor set layouts from shaders
264     auto layoutInfo = vk::PipelineLayoutCreateInfo{};
265
266     using DSLayoutBindingArray = std::vector<vk::DescriptorSetLayoutBinding>;
267
268     std::vector<DSLayoutBindingArray> allDescriptorSetLayouts;
269
270     // concatenate all bindings
271     // TODO: @todo validate if there are weird overlaps!
272     for( auto&& shader : mShaderResources )
273     {
274       const auto& reflection = shader->GetSPIRVReflection();
275       auto layouts = reflection.GenerateDescriptorSetLayoutCreateInfo();
276
277       if(allDescriptorSetLayouts.size() < layouts.size())
278       {
279         allDescriptorSetLayouts.resize(layouts.size());
280       }
281
282       for( auto i = 0u; i < layouts.size(); ++i )
283       {
284         auto currIndex = allDescriptorSetLayouts[i].size();
285         allDescriptorSetLayouts[i].insert( allDescriptorSetLayouts[i].end(),
286         layouts[i].pBindings, layouts[i].pBindings + layouts[i].bindingCount );
287         for( auto j = 0u; j < layouts[i].bindingCount; ++j )
288         {
289           allDescriptorSetLayouts[i][j+currIndex].setStageFlags( GetShaderStage( shader ) );
290         }
291       }
292     }
293
294     // create descriptor set layouts for the pipeline
295     std::vector<vk::DescriptorSetLayout> dsLayouts{};
296     dsLayouts.resize( allDescriptorSetLayouts.size() );
297     mDSCreateInfoArray.clear();
298     for( auto i = 0u; i < allDescriptorSetLayouts.size(); ++i )
299     {
300       auto info = vk::DescriptorSetLayoutCreateInfo{}.
301                     setBindingCount( static_cast<uint32_t>(allDescriptorSetLayouts[i].size()) ).
302                     setPBindings( allDescriptorSetLayouts[i].data() );
303
304       mDSCreateInfoArray.push_back( info );
305       dsLayouts[i] = VkAssert( mGraphics.GetDevice().createDescriptorSetLayout( info, mGraphics.GetAllocator() ) );
306     }
307
308     // create pipeline layout
309     layoutInfo.setPSetLayouts( dsLayouts.data() );
310     layoutInfo.setSetLayoutCount( static_cast<uint32_t>(dsLayouts.size()) );
311
312     mPipelineLayout = VkAssert( mGraphics.GetDevice().createPipelineLayout( layoutInfo, mGraphics.GetAllocator() ) );
313
314     mDSLayoutArray = dsLayouts;
315     mInfo.setLayout( mPipelineLayout );
316   }
317 #pragma GCC diagnostic pop
318
319   vk::ShaderStageFlagBits GetShaderStage( ShaderRef shader )
320   {
321     for( auto&& stage : mShaderStageCreateInfo )
322     {
323       if( stage.module == *shader )
324       {
325         return stage.stage;
326       }
327     }
328     return vk::ShaderStageFlagBits{};
329   }
330
331   bool Compile()
332   {
333     return Initialise() == vk::Result::eSuccess;
334   }
335
336   bool ValidateShaderModules()
337   {
338     for( auto i = 0u; i < mInfo.stageCount; ++i )
339     {
340       const auto& stage = mInfo.pStages[i];
341       auto shaderHandle = mGraphics.FindShader( stage.module );
342       if( shaderHandle )
343       {
344         bool tracked { false };
345         for(auto&& sh : mShaderResources )
346         {
347           if( sh == shaderHandle )
348           {
349             tracked = true;
350           }
351         }
352         if(!tracked)
353         {
354           mShaderResources.push_back(shaderHandle);
355         }
356       }
357       else
358       {
359         return false; // invalid shader! Can't track it
360       }
361     }
362     return true;
363   }
364
365
366   vk::GraphicsPipelineCreateInfo  mInfo           {    };
367   vk::Pipeline                    mPipeline       { nullptr };
368   uint32_t                        mModified       { 0u };
369   Graphics&                       mGraphics;
370
371   // resources
372   std::vector<ShaderRef>     mShaderResources;
373
374   vk::PipelineViewportStateCreateInfo mViewportState {};
375   std::vector<vk::Viewport> mViewports {};
376   vk::Rect2D mScissors {};
377
378   std::vector<vk::PipelineShaderStageCreateInfo> mShaderStageCreateInfo;
379   vk::PipelineLayout mPipelineLayout{};
380   std::vector<vk::DescriptorSetLayoutCreateInfo>    mDSCreateInfoArray{};
381   std::vector<vk::DescriptorSetLayout>              mDSLayoutArray{};
382
383   // vertex input state
384   vk::PipelineVertexInputStateCreateInfo            mVertexInputState {};
385   std::vector<vk::VertexInputAttributeDescription>  mAttrDesc;
386   std::vector<vk::VertexInputBindingDescription>    mBindingDesc;
387
388   // vertex input assembly state
389   vk::PipelineInputAssemblyStateCreateInfo          mInputAssemblyState {};
390
391   // rasterization state
392   vk::PipelineRasterizationStateCreateInfo          mRasterizationState {};
393
394   // Dpeth/stencil state
395   vk::PipelineDepthStencilStateCreateInfo           mDepthStencilState {};
396
397   // Multisample state
398   vk::PipelineMultisampleStateCreateInfo            mMultisampleState {};
399
400   // Color blend
401   vk::PipelineColorBlendStateCreateInfo             mColorBlendState {};
402   vk::PipelineColorBlendAttachmentState             mAttachementNoBlendState {};
403 };
404
405 /*********************************************************************
406  * Class Pipeline
407  *
408  */
409
410 PipelineRef Pipeline::New( Graphics& graphics, const vk::GraphicsPipelineCreateInfo& info )
411 {
412   auto pipeline = Handle<Pipeline>( new Pipeline(graphics, info) );
413   graphics.AddPipeline(pipeline);
414   return pipeline;
415 }
416
417 Pipeline::~Pipeline() = default;
418
419 Pipeline::Pipeline( Graphics& graphics, const vk::GraphicsPipelineCreateInfo& info )
420 {
421   mImpl = MakeUnique<Pipeline::Impl>( graphics, info );
422 }
423
424 vk::Pipeline Pipeline::GetVkPipeline() const
425 {
426   return mImpl->GetVkPipeline();
427 }
428
429 bool Pipeline::OnDestroy()
430 {
431   return false;
432 }
433
434 void Pipeline::SetViewport( float x, float y, float width, float height )
435 {
436   mImpl->SetViewport( x, y, width, height );
437 }
438
439 bool Pipeline::SetShader( ShaderRef shader, Shader::Type stage )
440 {
441   return mImpl->SetShader( shader, stage );
442 }
443
444 void Pipeline::SetVertexInputState(std::vector<vk::VertexInputAttributeDescription> attrDesc,
445                          std::vector<vk::VertexInputBindingDescription> bindingDesc)
446 {
447   mImpl->SetVertexInputState( attrDesc, bindingDesc );
448 }
449
450 void Pipeline::SetInputAssemblyState( vk::PrimitiveTopology topology, bool restartEnable )
451 {
452   mImpl->SetInputAssemblyState( topology, restartEnable );
453 }
454
455 bool Pipeline::Compile()
456 {
457   return mImpl->Compile();
458 }
459
460 vk::PipelineLayout Pipeline::GetVkPipelineLayout() const
461 {
462   return mImpl->mPipelineLayout;
463 }
464
465 const std::vector<vk::DescriptorSetLayoutCreateInfo>& Pipeline::GetVkDescriptorSetLayoutCreateInfo() const
466 {
467   return mImpl->mDSCreateInfoArray;
468 }
469
470 const std::vector<vk::DescriptorSetLayout>& Pipeline::GetVkDescriptorSetLayouts() const
471 {
472   return mImpl->mDSLayoutArray;
473 }
474
475 } // namespace Vulkan
476
477 } // namespace Graphics
478
479 } // namespace Dali