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 );
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);
216 * Sets the shader. Must be set before compiling the pipeline, compiled pipeline
222 bool SetShader( ShaderRef shader, Shader::Type stage )
224 assert( !mPipeline && "Pipeline cannot be changed anymore!");
226 // check if shader isn't orphaned for some reason
227 if( !mGraphics.FindShader( *shader ) )
232 auto info = vk::PipelineShaderStageCreateInfo{}.
233 setModule( *shader ).
234 setStage( static_cast<vk::ShaderStageFlagBits>( stage ) ).
236 mShaderStageCreateInfo.push_back( info );
237 mShaderResources.push_back( shader );
239 mInfo.setPStages( mShaderStageCreateInfo.data() );
240 mInfo.setStageCount( static_cast<uint32_t>(mShaderStageCreateInfo.size()) );
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.
250 * @todo: Store SPIRV data of shader modules in the cache rather than
253 #pragma GCC diagnostic push
254 #pragma GCC diagnostic ignored "-Wframe-larger-than="
255 void CreatePipelineLayout()
257 // pull desciptor set layouts from shaders
258 auto layoutInfo = vk::PipelineLayoutCreateInfo{};
260 using DSLayoutBindingArray = std::vector<vk::DescriptorSetLayoutBinding>;
262 std::vector<DSLayoutBindingArray> allDescriptorSetLayouts;
264 // concatenate all bindings
265 // TODO: @todo validate if there are weird overlaps!
266 for( auto&& shader : mShaderResources )
268 const auto& reflection = shader->GetSPIRVReflection();
269 auto layouts = reflection.GenerateDescriptorSetLayoutCreateInfo();
271 if(allDescriptorSetLayouts.size() < layouts.size())
273 allDescriptorSetLayouts.resize(layouts.size());
276 for( auto i = 0u; i < layouts.size(); ++i )
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 )
283 allDescriptorSetLayouts[i][j+currIndex].setStageFlags( GetShaderStage( shader ) );
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 )
294 auto info = vk::DescriptorSetLayoutCreateInfo{}.
295 setBindingCount( static_cast<uint32_t>(allDescriptorSetLayouts[i].size()) ).
296 setPBindings( allDescriptorSetLayouts[i].data() );
298 mDSCreateInfoArray.push_back( info );
299 dsLayouts[i] = VkAssert( mGraphics.GetDevice().createDescriptorSetLayout( info, mGraphics.GetAllocator() ) );
302 // create pipeline layout
303 layoutInfo.setPSetLayouts( dsLayouts.data() );
304 layoutInfo.setSetLayoutCount( static_cast<uint32_t>(dsLayouts.size()) );
306 mPipelineLayout = VkAssert( mGraphics.GetDevice().createPipelineLayout( layoutInfo, mGraphics.GetAllocator() ) );
308 mDSLayoutArray = dsLayouts;
309 mInfo.setLayout( mPipelineLayout );
311 #pragma GCC diagnostic pop
313 vk::ShaderStageFlagBits GetShaderStage( ShaderRef shader )
315 for( auto&& stage : mShaderStageCreateInfo )
317 if( stage.module == *shader )
322 return vk::ShaderStageFlagBits{};
327 return Initialise() == vk::Result::eSuccess;
330 bool ValidateShaderModules()
332 for( auto i = 0u; i < mInfo.stageCount; ++i )
334 const auto& stage = mInfo.pStages[i];
335 auto shaderHandle = mGraphics.FindShader( stage.module );
338 bool tracked { false };
339 for(auto&& sh : mShaderResources )
341 if( sh == shaderHandle )
348 mShaderResources.push_back(shaderHandle);
353 return false; // invalid shader! Can't track it
360 vk::GraphicsPipelineCreateInfo mInfo { };
361 vk::Pipeline mPipeline { nullptr };
362 uint32_t mModified { 0u };
366 std::vector<ShaderRef> mShaderResources;
368 vk::PipelineViewportStateCreateInfo mViewportState {};
369 std::vector<vk::Viewport> mViewports {};
370 vk::Rect2D mScissors {};
372 std::vector<vk::PipelineShaderStageCreateInfo> mShaderStageCreateInfo;
373 vk::PipelineLayout mPipelineLayout{};
374 std::vector<vk::DescriptorSetLayoutCreateInfo> mDSCreateInfoArray{};
375 std::vector<vk::DescriptorSetLayout> mDSLayoutArray{};
377 // vertex input state
378 vk::PipelineVertexInputStateCreateInfo mVertexInputState {};
379 std::vector<vk::VertexInputAttributeDescription> mAttrDesc;
380 std::vector<vk::VertexInputBindingDescription> mBindingDesc;
382 // vertex input assembly state
383 vk::PipelineInputAssemblyStateCreateInfo mInputAssemblyState {};
385 // rasterization state
386 vk::PipelineRasterizationStateCreateInfo mRasterizationState {};
388 // Dpeth/stencil state
389 vk::PipelineDepthStencilStateCreateInfo mDepthStencilState {};
392 vk::PipelineMultisampleStateCreateInfo mMultisampleState {};
395 vk::PipelineColorBlendStateCreateInfo mColorBlendState {};
396 vk::PipelineColorBlendAttachmentState mAttachementNoBlendState {};
399 /*********************************************************************
404 PipelineRef Pipeline::New( Graphics& graphics, const vk::GraphicsPipelineCreateInfo& info )
406 auto pipeline = Handle<Pipeline>( new Pipeline(graphics, info) );
407 graphics.AddPipeline(pipeline);
411 Pipeline::~Pipeline() = default;
413 Pipeline::Pipeline( Graphics& graphics, const vk::GraphicsPipelineCreateInfo& info )
415 mImpl = MakeUnique<Pipeline::Impl>( graphics, info );
418 vk::Pipeline Pipeline::GetVkPipeline() const
420 return mImpl->GetVkPipeline();
423 bool Pipeline::OnDestroy()
428 void Pipeline::SetViewport( float x, float y, float width, float height )
430 mImpl->SetViewport( x, y, width, height );
433 bool Pipeline::SetShader( ShaderRef shader, Shader::Type stage )
435 return mImpl->SetShader( shader, stage );
438 void Pipeline::SetVertexInputState(std::vector<vk::VertexInputAttributeDescription> attrDesc,
439 std::vector<vk::VertexInputBindingDescription> bindingDesc)
441 mImpl->SetVertexInputState( attrDesc, bindingDesc );
444 void Pipeline::SetInputAssemblyState( vk::PrimitiveTopology topology, bool restartEnable )
446 mImpl->SetInputAssemblyState( topology, restartEnable );
449 bool Pipeline::Compile()
451 return mImpl->Compile();
454 vk::PipelineLayout Pipeline::GetVkPipelineLayout() const
456 return mImpl->mPipelineLayout;
459 const std::vector<vk::DescriptorSetLayoutCreateInfo>& Pipeline::GetVkDescriptorSetLayoutCreateInfo() const
461 return mImpl->mDSCreateInfoArray;
464 const std::vector<vk::DescriptorSetLayout>& Pipeline::GetVkDescriptorSetLayouts() const
466 return mImpl->mDSLayoutArray;
469 } // namespace Vulkan
471 } // namespace Graphics