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.
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>
34 static const vk::ShaderStageFlags DEFAULT_SHADER_STAGES{ vk::ShaderStageFlagBits::eVertex|vk::ShaderStageFlagBits::eFragment };
38 * Class Pipeline::Impl
39 * Internal implementation of the pipeline
45 Impl( Vulkan::Graphics& graphics, const vk::GraphicsPipelineCreateInfo& info ) :
56 mGraphics.GetDevice().destroyPipelineLayout( mPipelineLayout, mGraphics.GetAllocator() );
60 mGraphics.GetDevice().destroyPipeline( mPipeline, mGraphics.GetAllocator() );
68 vk::Pipeline GetVkPipeline() const
73 vk::Result Initialise()
75 if( !ValidateShaderModules() )
77 return vk::Result::eErrorInitializationFailed;
80 CreatePipelineLayout();
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 )
87 SetRenderPass( mGraphics.GetSwapchainForFBID(0u)->
88 GetCurrentFramebuffer()->GetVkRenderPass());
91 SetRasterizationState();
93 SetDepthStencilState();
95 SetMultisampleState();
99 mInfo.setFlags( vk::PipelineCreateFlagBits::eAllowDerivatives );
101 mPipeline = VkAssert( mGraphics.GetDevice().createGraphicsPipeline( nullptr, mInfo, mGraphics.GetAllocator() ) );
104 return vk::Result::eSuccess;
106 return vk::Result::eErrorInitializationFailed;
109 void SetRenderPass( vk::RenderPass renderpass )
111 mInfo.setRenderPass( renderpass );
114 void SetDepthStencilState()
116 mDepthStencilState = vk::PipelineDepthStencilStateCreateInfo{};
117 mDepthStencilState.setDepthBoundsTestEnable( false );
118 mDepthStencilState.setStencilTestEnable( false );
119 mInfo.setPDepthStencilState( & mDepthStencilState );
122 void SetMultisampleState()
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 );
133 void SetVertexInputState(
134 std::vector<vk::VertexInputAttributeDescription> attrDesc,
135 std::vector<vk::VertexInputBindingDescription> bindingDesc)
137 mBindingDesc.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 );
148 * Sets the viewport on uncompiled pipeline
151 void SetViewport( float x, float y, float width, float height )
153 assert( !mPipeline && "Pipeline cannot be changed anymore!");
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 );
168 // replace viewport state
169 mInfo.setPViewportState( &mViewportState );
175 * @param restartEnable
177 void SetInputAssemblyState( vk::PrimitiveTopology topology, bool restartEnable )
179 mInputAssemblyState = vk::PipelineInputAssemblyStateCreateInfo{};
180 mInputAssemblyState.setPrimitiveRestartEnable( restartEnable );
181 mInputAssemblyState.setTopology( topology );
182 mInfo.setPInputAssemblyState( &mInputAssemblyState );
185 void SetRasterizationState()
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 );
199 void SetColorBlendState()
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 );
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);
222 * Sets the shader. Must be set before compiling the pipeline, compiled pipeline
228 bool SetShader( ShaderRef shader, Shader::Type stage )
230 assert( !mPipeline && "Pipeline cannot be changed anymore!");
232 // check if shader isn't orphaned for some reason
233 if( !mGraphics.FindShader( *shader ) )
238 auto info = vk::PipelineShaderStageCreateInfo{}.
239 setModule( *shader ).
240 setStage( static_cast<vk::ShaderStageFlagBits>( stage ) ).
242 mShaderStageCreateInfo.push_back( info );
243 mShaderResources.push_back( shader );
245 mInfo.setPStages( mShaderStageCreateInfo.data() );
246 mInfo.setStageCount( static_cast<uint32_t>(mShaderStageCreateInfo.size()) );
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.
256 * @todo: Store SPIRV data of shader modules in the cache rather than
259 #pragma GCC diagnostic push
260 #pragma GCC diagnostic ignored "-Wframe-larger-than="
261 void CreatePipelineLayout()
263 // pull desciptor set layouts from shaders
264 auto layoutInfo = vk::PipelineLayoutCreateInfo{};
266 using DSLayoutBindingArray = std::vector<vk::DescriptorSetLayoutBinding>;
268 std::vector<DSLayoutBindingArray> allDescriptorSetLayouts;
270 // concatenate all bindings
271 // TODO: @todo validate if there are weird overlaps!
272 for( auto&& shader : mShaderResources )
274 const auto& reflection = shader->GetSPIRVReflection();
275 auto layouts = reflection.GenerateDescriptorSetLayoutCreateInfo();
277 if(allDescriptorSetLayouts.size() < layouts.size())
279 allDescriptorSetLayouts.resize(layouts.size());
282 for( auto i = 0u; i < layouts.size(); ++i )
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 )
289 allDescriptorSetLayouts[i][j+currIndex].setStageFlags( GetShaderStage( shader ) );
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 )
300 auto info = vk::DescriptorSetLayoutCreateInfo{}.
301 setBindingCount( static_cast<uint32_t>(allDescriptorSetLayouts[i].size()) ).
302 setPBindings( allDescriptorSetLayouts[i].data() );
304 mDSCreateInfoArray.push_back( info );
305 dsLayouts[i] = VkAssert( mGraphics.GetDevice().createDescriptorSetLayout( info, mGraphics.GetAllocator() ) );
308 // create pipeline layout
309 layoutInfo.setPSetLayouts( dsLayouts.data() );
310 layoutInfo.setSetLayoutCount( static_cast<uint32_t>(dsLayouts.size()) );
312 mPipelineLayout = VkAssert( mGraphics.GetDevice().createPipelineLayout( layoutInfo, mGraphics.GetAllocator() ) );
314 mDSLayoutArray = dsLayouts;
315 mInfo.setLayout( mPipelineLayout );
317 #pragma GCC diagnostic pop
319 vk::ShaderStageFlagBits GetShaderStage( ShaderRef shader )
321 for( auto&& stage : mShaderStageCreateInfo )
323 if( stage.module == *shader )
328 return vk::ShaderStageFlagBits{};
333 return Initialise() == vk::Result::eSuccess;
336 bool ValidateShaderModules()
338 for( auto i = 0u; i < mInfo.stageCount; ++i )
340 const auto& stage = mInfo.pStages[i];
341 auto shaderHandle = mGraphics.FindShader( stage.module );
344 bool tracked { false };
345 for(auto&& sh : mShaderResources )
347 if( sh == shaderHandle )
354 mShaderResources.push_back(shaderHandle);
359 return false; // invalid shader! Can't track it
366 vk::GraphicsPipelineCreateInfo mInfo { };
367 vk::Pipeline mPipeline { nullptr };
368 uint32_t mModified { 0u };
372 std::vector<ShaderRef> mShaderResources;
374 vk::PipelineViewportStateCreateInfo mViewportState {};
375 std::vector<vk::Viewport> mViewports {};
376 vk::Rect2D mScissors {};
378 std::vector<vk::PipelineShaderStageCreateInfo> mShaderStageCreateInfo;
379 vk::PipelineLayout mPipelineLayout{};
380 std::vector<vk::DescriptorSetLayoutCreateInfo> mDSCreateInfoArray{};
381 std::vector<vk::DescriptorSetLayout> mDSLayoutArray{};
383 // vertex input state
384 vk::PipelineVertexInputStateCreateInfo mVertexInputState {};
385 std::vector<vk::VertexInputAttributeDescription> mAttrDesc;
386 std::vector<vk::VertexInputBindingDescription> mBindingDesc;
388 // vertex input assembly state
389 vk::PipelineInputAssemblyStateCreateInfo mInputAssemblyState {};
391 // rasterization state
392 vk::PipelineRasterizationStateCreateInfo mRasterizationState {};
394 // Dpeth/stencil state
395 vk::PipelineDepthStencilStateCreateInfo mDepthStencilState {};
398 vk::PipelineMultisampleStateCreateInfo mMultisampleState {};
401 vk::PipelineColorBlendStateCreateInfo mColorBlendState {};
402 vk::PipelineColorBlendAttachmentState mAttachementNoBlendState {};
405 /*********************************************************************
410 PipelineRef Pipeline::New( Graphics& graphics, const vk::GraphicsPipelineCreateInfo& info )
412 auto pipeline = Handle<Pipeline>( new Pipeline(graphics, info) );
413 graphics.AddPipeline(pipeline);
417 Pipeline::~Pipeline() = default;
419 Pipeline::Pipeline( Graphics& graphics, const vk::GraphicsPipelineCreateInfo& info )
421 mImpl = MakeUnique<Pipeline::Impl>( graphics, info );
424 vk::Pipeline Pipeline::GetVkPipeline() const
426 return mImpl->GetVkPipeline();
429 bool Pipeline::OnDestroy()
434 void Pipeline::SetViewport( float x, float y, float width, float height )
436 mImpl->SetViewport( x, y, width, height );
439 bool Pipeline::SetShader( ShaderRef shader, Shader::Type stage )
441 return mImpl->SetShader( shader, stage );
444 void Pipeline::SetVertexInputState(std::vector<vk::VertexInputAttributeDescription> attrDesc,
445 std::vector<vk::VertexInputBindingDescription> bindingDesc)
447 mImpl->SetVertexInputState( attrDesc, bindingDesc );
450 void Pipeline::SetInputAssemblyState( vk::PrimitiveTopology topology, bool restartEnable )
452 mImpl->SetInputAssemblyState( topology, restartEnable );
455 bool Pipeline::Compile()
457 return mImpl->Compile();
460 vk::PipelineLayout Pipeline::GetVkPipelineLayout() const
462 return mImpl->mPipelineLayout;
465 const std::vector<vk::DescriptorSetLayoutCreateInfo>& Pipeline::GetVkDescriptorSetLayoutCreateInfo() const
467 return mImpl->mDSCreateInfoArray;
470 const std::vector<vk::DescriptorSetLayout>& Pipeline::GetVkDescriptorSetLayouts() const
472 return mImpl->mDSLayoutArray;
475 } // namespace Vulkan
477 } // namespace Graphics