From 2bdc7ebc7ac2fd685158b400e2b9a86dd93f5aee Mon Sep 17 00:00:00 2001 From: "adam.b" Date: Tue, 5 Jun 2018 13:06:00 +0100 Subject: [PATCH] [Vulkan] Added Pipeline object to the API. - Added Pipeline object to the graphics API - Decoupling of pipeline state and resources - Supporting more complex blending - Depth test support - Supporting viewport, topology etc. - Added internal graphics API pipeline cache Change-Id: I0bee6e3710379f777f75439423476fa72f0709cc Signed-off-by: David Steele --- dali/graphics-api/graphics-api-controller.h | 19 +- dali/graphics-api/graphics-api-pipeline-factory.h | 74 +++ dali/graphics-api/graphics-api-pipeline.h | 50 ++ dali/graphics-api/graphics-api-render-command.h | 21 +- dali/graphics-api/graphics-api-types.h | 443 ++++++++++++++++ dali/graphics-api/graphics-api-utility.h | 24 +- dali/graphics/file.list | 5 +- .../api/internal/vulkan-api-pipeline-impl.cpp | 586 +++++++++++++++++++++ .../vulkan/api/internal/vulkan-api-pipeline-impl.h | 99 ++++ .../vulkan/api/internal/vulkan-pipeline-cache.cpp | 123 +++++ .../vulkan/api/internal/vulkan-pipeline-cache.h | 87 +++ .../vulkan/api/vulkan-api-buffer-factory.h | 3 +- dali/graphics/vulkan/api/vulkan-api-controller.cpp | 62 ++- dali/graphics/vulkan/api/vulkan-api-controller.h | 13 +- .../vulkan/api/vulkan-api-pipeline-factory.cpp | 186 +++++++ .../vulkan/api/vulkan-api-pipeline-factory.h | 103 ++++ dali/graphics/vulkan/api/vulkan-api-pipeline.cpp | 64 +++ dali/graphics/vulkan/api/vulkan-api-pipeline.h | 75 +++ .../vulkan/api/vulkan-api-render-command.cpp | 356 +------------ .../vulkan/api/vulkan-api-render-command.h | 57 +- dali/graphics/vulkan/api/vulkan-api-shader.h | 6 +- .../vulkan/gpu-memory/vulkan-gpu-memory-handle.cpp | 2 +- dali/graphics/vulkan/vulkan-graphics.cpp | 22 +- dali/graphics/vulkan/vulkan-graphics.h | 17 +- dali/graphics/vulkan/vulkan-pipeline-cache.cpp | 123 ----- dali/graphics/vulkan/vulkan-pipeline-cache.h | 71 --- dali/graphics/vulkan/vulkan-swapchain.cpp | 13 +- .../update/graphics/graphics-algorithms.cpp | 10 +- .../update/rendering/scene-graph-renderer.cpp | 133 +++-- .../update/rendering/scene-graph-renderer.h | 3 +- 30 files changed, 2153 insertions(+), 697 deletions(-) create mode 100644 dali/graphics-api/graphics-api-pipeline-factory.h create mode 100644 dali/graphics-api/graphics-api-pipeline.h create mode 100644 dali/graphics-api/graphics-api-types.h create mode 100644 dali/graphics/vulkan/api/internal/vulkan-api-pipeline-impl.cpp create mode 100644 dali/graphics/vulkan/api/internal/vulkan-api-pipeline-impl.h create mode 100644 dali/graphics/vulkan/api/internal/vulkan-pipeline-cache.cpp create mode 100644 dali/graphics/vulkan/api/internal/vulkan-pipeline-cache.h create mode 100644 dali/graphics/vulkan/api/vulkan-api-pipeline-factory.cpp create mode 100644 dali/graphics/vulkan/api/vulkan-api-pipeline-factory.h create mode 100644 dali/graphics/vulkan/api/vulkan-api-pipeline.cpp create mode 100644 dali/graphics/vulkan/api/vulkan-api-pipeline.h delete mode 100644 dali/graphics/vulkan/vulkan-pipeline-cache.cpp delete mode 100644 dali/graphics/vulkan/vulkan-pipeline-cache.h diff --git a/dali/graphics-api/graphics-api-controller.h b/dali/graphics-api/graphics-api-controller.h index 7251111..a5825c0 100644 --- a/dali/graphics-api/graphics-api-controller.h +++ b/dali/graphics-api/graphics-api-controller.h @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include namespace Dali @@ -75,9 +77,9 @@ public: virtual Accessor CreateFramebuffer( const BaseFactory& factory ) = 0; /** - * @brief Get a render list + * Creates new pipeline */ - virtual void GetRenderItemList() = 0; + virtual std::unique_ptr CreatePipeline( const BaseFactory& factory ) = 0; /** * @brief Returns texture factory @@ -92,12 +94,19 @@ public: virtual ShaderFactory& GetShaderFactory() const = 0; /** - * @brief Returns shader factory - * @return - */ + * @brief Returns buffer factory + * @return + */ virtual BufferFactory& GetBufferFactory() const = 0; /** + * @brief Returns pipeline factory + * @return + */ + virtual PipelineFactory& GetPipelineFactory() = 0; + + + /** * @brief alAllocates render command ( depends on implementation ); * @return */ diff --git a/dali/graphics-api/graphics-api-pipeline-factory.h b/dali/graphics-api/graphics-api-pipeline-factory.h new file mode 100644 index 0000000..301544d --- /dev/null +++ b/dali/graphics-api/graphics-api-pipeline-factory.h @@ -0,0 +1,74 @@ +#ifndef DALI_GRAPHICS_API_PIPELINE_FACTORY_H +#define DALI_GRAPHICS_API_PIPELINE_FACTORY_H + +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include + +namespace Dali +{ +namespace Graphics +{ +namespace API +{ +class PipelineCache; + +/** + * @brief Interface class for ShaderFactory types in the graphics API. + */ +class PipelineFactory : public BaseFactory +{ +public: + + // not copyable + PipelineFactory(const PipelineFactory&) = delete; + PipelineFactory& operator=(const PipelineFactory&) = delete; + + virtual ~PipelineFactory() = default; + + virtual PipelineFactory& SetColorBlendState( const ColorBlendState& state ) = 0; + + virtual PipelineFactory& SetShaderState( const ShaderState& state ) = 0; + + virtual PipelineFactory& SetViewportState( const ViewportState& state ) = 0; + + virtual PipelineFactory& SetBasePipeline( Pipeline& pipeline ) = 0; + + virtual PipelineFactory& SetDepthStencilState( DepthStencilState state ) = 0; + + virtual PipelineFactory& SetRasterizationState( const RasterizationState& state ) = 0; + + virtual PipelineFactory& SetVertexInputState( const VertexInputState& state ) = 0; + + virtual PipelineFactory& SetInputAssemblyState( const InputAssemblyState& state ) = 0; + +protected: + /// @brief default constructor + PipelineFactory() = default; + + PipelineFactory(PipelineFactory&&) = default; + PipelineFactory& operator=(PipelineFactory&&) = default; +}; + +} // namespace API +} // namespace Graphics +} // namespace Dali + +#endif // DALI_GRAPHICS_API_PIPELINE_FACTORY_H + diff --git a/dali/graphics-api/graphics-api-pipeline.h b/dali/graphics-api/graphics-api-pipeline.h new file mode 100644 index 0000000..cf16a72 --- /dev/null +++ b/dali/graphics-api/graphics-api-pipeline.h @@ -0,0 +1,50 @@ +#ifndef DALI_GRAPHICS_API_PIPELINE_H +#define DALI_GRAPHICS_API_PIPELINE_H + +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include + +namespace Dali +{ +namespace Graphics +{ +namespace API +{ + +class Pipeline +{ +public: + // not copyable + Pipeline(const Pipeline&) = delete; + Pipeline& operator=(const Pipeline&) = delete; + + virtual ~Pipeline() = default; + +protected: + + Pipeline(Pipeline&&) = default; + Pipeline& operator=(Pipeline&&) = default; + + Pipeline() = default; + +}; +} +} +} +#endif // DALI_GRAPHICS_API_PIPELINE_H diff --git a/dali/graphics-api/graphics-api-render-command.h b/dali/graphics-api/graphics-api-render-command.h index a911c35..aaf78ad 100644 --- a/dali/graphics-api/graphics-api-render-command.h +++ b/dali/graphics-api/graphics-api-render-command.h @@ -550,9 +550,9 @@ public: /** * Resource binding API */ - RenderCommand& BindVertexBuffers( std::vector&& bindings ) + RenderCommand& BindVertexBuffers( std::vector>&& buffers ) { - mVertexBufferBindings = std::move( bindings ); + mVertexBufferBindings = std::move( buffers ); return *this; } @@ -604,9 +604,9 @@ public: return *this; } - RenderCommand& BindPipeline( const Accessor& pipeline ) + RenderCommand& BindPipeline( const Pipeline& pipeline ) { - mPipeline = pipeline; + mPipeline = &pipeline; return *this; } @@ -649,7 +649,7 @@ public: } // Getters - const std::vector& GetVertexBufferBindings() const + const std::vector>& GetVertexBufferBindings() const { return mVertexBufferBindings; } @@ -689,23 +689,26 @@ public: return mRenderState; } - Accessor GetPipeline() const + const Pipeline* GetPipeline() const { return mPipeline; } -protected: +public: - std::vector mVertexBufferBindings; + // list of resources + std::vector> mVertexBufferBindings; std::vector mUniformBufferBindings; std::vector mTextureBindings; std::vector mSamplerBindings; + + IndexBufferBinding mIndexBufferBinding; RenderTargetBinding mRenderTargetBinding; DrawCommand mDrawCommand; std::vector mPushConstantsBindings; RenderState mRenderState; - Accessor mPipeline; + const Pipeline* mPipeline; }; diff --git a/dali/graphics-api/graphics-api-types.h b/dali/graphics-api/graphics-api-types.h new file mode 100644 index 0000000..c59d134 --- /dev/null +++ b/dali/graphics-api/graphics-api-types.h @@ -0,0 +1,443 @@ +#ifndef DALI_GRAPHICS_API_TYPES_H +#define DALI_GRAPHICS_API_TYPES_H + +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include + +namespace Dali +{ +namespace Graphics +{ +namespace API +{ +class Shader; +using Extension = void*; + +/** + * Describes vertex attribute input rate + */ +enum class VertexInputRate +{ + PER_VERTEX, /// Attribute read per vertex + PER_INSTANCE /// Attribute read per instance +}; + +/** + * Vertex input format + * When UNDEFINED, the reflection is used to determine what + * the actual format is. + */ +enum class VertexInputFormat +{ + UNDEFINED, + FVECTOR2, + FVECTOR3, + FVECTOR4, + IVECTOR2, + IVECTOR3, + IVECTOR4, + FLOAT, + INTEGER, +}; + +/** + * Logic operators + */ +enum class LogicOp +{}; + +/** + * Blend factors + */ +enum class BlendFactor +{ + ZERO = 0, + ONE = 1, + SRC_COLOR = 2, + ONE_MINUS_SRC_COLOR = 3, + DST_COLOR = 4, + ONE_MINUS_DST_COLOR = 5, + SRC_ALPHA = 6, + ONE_MINUS_SRC_ALPHA = 7, + DST_ALPHA = 8, + ONE_MINUS_DST_ALPHA = 9, + CONSTANT_COLOR = 10, + ONE_MINUS_CONSTANT_COLOR = 11, + CONSTANT_ALPHA = 12, + ONE_MINUS_CONSTANT_ALPHA = 13, + SRC_ALPHA_SATURATE = 14, + SRC1_COLOR = 15, + ONE_MINUS_SRC1_COLOR = 16, + SRC1_ALPHA = 17, + ONE_MINUS_SRC1_ALPHA = 18, +}; + +/** + * Blend operators + */ +enum class BlendOp +{ + ADD = 0, + SUBTRACT = 1, + REVERSE_SUBTRACT = 2, + MIN = 3, + MAX = 4, +}; + +/** + * Compare operators + */ +enum class CompareOp +{ + NEVER, + LESS, + EQUAL, + LESS_OR_EQUAL, + GREATER, + NOT_EQUAL, + GREATER_OR_EQUAL, + ALWAYS +}; + +/** + * Stencil operators + */ +enum class StencilOp +{ + KEEP, + ZERO, + REPLACE, + INCREMENT_AND_CLAMP, + DECREMENT_AND_CLAMP, + INVERT, + INCREMENT_AND_WRAP, + DECREMENT_AND_WRAP +}; + +/** + * Backface culling modes + */ +enum class CullMode +{ + NONE, + FRONT, + BACK, + FRONT_AND_BACK +}; + +/** + * Polygon drawing modes + */ +enum class PolygonMode +{ + FILL, + LINE, + POINT +}; + +/** + * Front face direction + */ +enum class FrontFace +{ + COUNTER_CLOCKWISE, + CLOCKWISE +}; + +/** + * Topology + */ +enum class PrimitiveTopology +{ + POINT_LIST, + LINE_LIST, + LINE_STRIP, + TRIANGLE_LIST, + TRIANGLE_STRIP, + TRIANGLE_FAN +}; + +/** + * Describes pipeline's color blend state + */ +struct ColorBlendState +{ + bool logicOpEnable = false; + LogicOp logicOp = {}; + float blendConstants[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + bool blendEnable = false; + BlendFactor srcColorBlendFactor = BlendFactor::ZERO; + BlendFactor dstColorBlendFactor = BlendFactor::ZERO; + BlendOp colorBlendOp = {}; + BlendFactor srcAlphaBlendFactor = BlendFactor::ZERO; + BlendFactor dstAlphaBlendFactor = BlendFactor::ZERO; + BlendOp alphaBlendOp = {}; + uint32_t colorComponentWriteBits = { 0u }; + + Extension extension = { nullptr }; + + ColorBlendState& SetLogicOpEnable( bool value ) + { + logicOpEnable = value; + return *this; + } + + ColorBlendState& SetLogicOp( LogicOp value ) + { + logicOp = value; + return *this; + } + + ColorBlendState& SetBlendConstants( float value[4] ) + { + std::copy( value, value+4, blendConstants ); + return *this; + } + + ColorBlendState& SetBlendEnable( bool value ) + { + blendEnable = value; + return *this; + } + + ColorBlendState& SetSrcColorBlendFactor( BlendFactor value ) + { + srcColorBlendFactor = value; + return *this; + } + + ColorBlendState& SetDstColorBlendFactor( BlendFactor value ) + { + dstColorBlendFactor = value; + return *this; + } + + ColorBlendState& SetColorBlendOp( BlendOp value ) + { + colorBlendOp = value; + return *this; + } + + ColorBlendState& SetSrcAlphaBlendFactor( BlendFactor value ) + { + srcAlphaBlendFactor = value; + return *this; + } + + ColorBlendState& SetDstAlphaBlendFactor( BlendFactor value ) + { + dstAlphaBlendFactor = value; + return *this; + } + + ColorBlendState& SetAlphaBlendOp( BlendOp value ) + { + alphaBlendOp = value; + return *this; + } + + ColorBlendState& SetColorComponentsWriteBits( uint32_t value ) + { + colorComponentWriteBits = value; + return *this; + } +}; + +/** + * Describes pipeline's shaading stages + */ +struct ShaderState +{ + Shader* shaderProgram { nullptr }; + + Extension extension { nullptr }; + + ShaderState& SetShaderProgram( Shader& value ) + { + shaderProgram = &value; + return *this; + } +}; + +/** + * Describes pipeline's viewport and scissor state + */ +struct ViewportState +{ + Viewport viewport { 0.0, 0.0, 0.0, 0.0 }; + Rect2D scissor { 0, 0, 0, 0 }; + bool scissorTestEnable { false }; + + Extension extension { nullptr }; + + + ViewportState& SetViewport( const Viewport& value ) + { + viewport = value; + return *this; + } + + ViewportState& SetScissor( const Rect2D& value ) + { + scissor = value; + return *this; + } + + ViewportState& SetScissorTestEnable( bool value ) + { + scissorTestEnable = value; + return *this; + } +}; + +/** + * Describes pipeline's viewport and scissor state + */ +struct DepthStencilState +{ + bool depthTestEnable { false }; + bool depthWriteEnable { false }; + CompareOp depthCompareOp {}; + bool stencilTestEnable { false }; + + + Extension extension { nullptr }; + + + DepthStencilState& SetDepthTestEnable( bool value ) + { + depthTestEnable = value; + return *this; + } + + DepthStencilState& SetDepthWriteEnable( bool value ) + { + depthWriteEnable = value; + return *this; + } + + DepthStencilState& SetDepthCompareOp( CompareOp value) + { + depthCompareOp = value; + return *this; + } + +}; + +/** + * RasterizationState + */ +struct RasterizationState +{ + CullMode cullMode {}; + PolygonMode polygonMode {}; + PrimitiveTopology topology {}; + FrontFace frontFace {}; + + Extension extension { nullptr }; + + RasterizationState& SetCullMode( CullMode value ) + { + cullMode = value; + return *this; + } + + RasterizationState& SetPolygonMode( PolygonMode value ) + { + polygonMode = value; + return *this; + } + + RasterizationState& SetFrontFace( FrontFace value ) + { + frontFace = value; + return *this; + } +}; + +/** + * + */ +struct InputAssemblyState +{ + PrimitiveTopology topology {}; + bool primitiveRestartEnable { false }; + + Extension extension { nullptr }; + + InputAssemblyState& SetTopology( PrimitiveTopology value ) + { + topology = value; + return *this; + } + + InputAssemblyState& SetPrimitiveRestartEnable( bool value ) + { + primitiveRestartEnable = value; + return *this; + } +}; + +/** + * + */ +struct VertexInputState +{ + VertexInputState() = default; + + struct Binding + { + Binding( uint32_t _stride, VertexInputRate _inputRate ) + : stride( _stride ), inputRate( _inputRate ) {} + uint32_t stride; + VertexInputRate inputRate; + }; + + struct Attribute + { + Attribute( uint32_t _location, uint32_t _binding, uint32_t _offset, VertexInputFormat _format ) + : location( _location ), + binding( _binding ), + offset( _offset ), + format( _format ) + {} + + uint32_t location; + uint32_t binding; + uint32_t offset; + VertexInputFormat format; + }; + + VertexInputState( std::vector _bufferBindings, std::vector _attributes ) + : bufferBindings( _bufferBindings ), attributes( _attributes ) + { + } + + std::vector bufferBindings {}; + std::vector attributes {}; + + Extension extension { nullptr }; +}; + +} // API +} // Graphics +} // Dali + +#endif //DALI_GRAPHICS_API_TYPES_H diff --git a/dali/graphics-api/graphics-api-utility.h b/dali/graphics-api/graphics-api-utility.h index f2906f3..b4017e5 100644 --- a/dali/graphics-api/graphics-api-utility.h +++ b/dali/graphics-api/graphics-api-utility.h @@ -3,7 +3,7 @@ #define DALI_GRAPHICS_API_UTILITY_H /* - * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * Copyright (c) 2018 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,8 @@ */ // EXTERNAL INCLUDES +#include +#include namespace Dali { @@ -36,6 +38,26 @@ struct RectSize { size_t height = 0; }; +struct Rect2D { + int32_t x = 0; + int32_t y = 0; + uint32_t width = 0; + uint32_t height = 0; +}; + +/** + * Structure represents area of viewport + */ +struct Viewport +{ + float x = 0.0f; + float y = 0.0f; + float width = 0.0f; + float height = 0.0f; + float minDepth = 0.0f; + float maxDepth = 0.0f; +}; + } // namespace API } // namespace Graphics } // namespace Dali diff --git a/dali/graphics/file.list b/dali/graphics/file.list index 648d87b..41f0676 100644 --- a/dali/graphics/file.list +++ b/dali/graphics/file.list @@ -14,7 +14,6 @@ graphics_src_files = \ $(graphics_src_dir)/vulkan/vulkan-image-view.cpp \ $(graphics_src_dir)/vulkan/vulkan-command-buffer.cpp \ $(graphics_src_dir)/vulkan/vulkan-pipeline.cpp \ - $(graphics_src_dir)/vulkan/vulkan-pipeline-cache.cpp \ $(graphics_src_dir)/vulkan/vulkan-buffer.cpp \ $(graphics_src_dir)/vulkan/vulkan-debug.cpp \ $(graphics_src_dir)/vulkan/vulkan-graphics.cpp \ @@ -31,6 +30,10 @@ graphics_src_files = \ $(graphics_src_dir)/vulkan/api/vulkan-api-texture-factory.cpp \ $(graphics_src_dir)/vulkan/api/vulkan-api-shader-factory.cpp \ $(graphics_src_dir)/vulkan/api/vulkan-api-render-command.cpp \ + $(graphics_src_dir)/vulkan/api/vulkan-api-pipeline.cpp \ + $(graphics_src_dir)/vulkan/api/vulkan-api-pipeline-factory.cpp \ $(graphics_src_dir)/vulkan/api/internal/vulkan-ubo-manager.cpp \ + $(graphics_src_dir)/vulkan/api/internal/vulkan-pipeline-cache.cpp \ $(graphics_src_dir)/vulkan/api/internal/vulkan-ubo-pool.cpp \ + $(graphics_src_dir)/vulkan/api/internal/vulkan-api-pipeline-impl.cpp \ $(graphics_src_dir)/vulkan/spirv/vulkan-spirv.cpp diff --git a/dali/graphics/vulkan/api/internal/vulkan-api-pipeline-impl.cpp b/dali/graphics/vulkan/api/internal/vulkan-api-pipeline-impl.cpp new file mode 100644 index 0000000..b985d50 --- /dev/null +++ b/dali/graphics/vulkan/api/internal/vulkan-api-pipeline-impl.cpp @@ -0,0 +1,586 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +namespace Dali +{ +namespace Graphics +{ +namespace VulkanAPI +{ +namespace Internal +{ +using Vulkan::VkAssert; +namespace +{ +constexpr vk::BlendOp ConvertBlendOp( Dali::Graphics::API::BlendOp blendOp ) +{ + switch( blendOp ) + { + case API::BlendOp::ADD: + return vk::BlendOp::eAdd; + case API::BlendOp::SUBTRACT: + return vk::BlendOp::eSubtract; + case API::BlendOp::REVERSE_SUBTRACT: + return vk::BlendOp::eReverseSubtract; + case API::BlendOp::MIN: + return vk::BlendOp::eMin; + case API::BlendOp::MAX: + return vk::BlendOp::eMax; + } + return vk::BlendOp{}; +} + +constexpr vk::BlendFactor ConvertBlendFactor( Dali::Graphics::API::BlendFactor blendFactor ) +{ + switch( blendFactor ) + { + case API::BlendFactor::ZERO: + return vk::BlendFactor::eZero; + case API::BlendFactor::ONE: + return vk::BlendFactor::eOne; + case API::BlendFactor::SRC_COLOR: + return vk::BlendFactor::eSrcColor; + case API::BlendFactor::ONE_MINUS_SRC_COLOR: + return vk::BlendFactor::eOneMinusSrcAlpha; + case API::BlendFactor::DST_COLOR: + return vk::BlendFactor::eDstColor; + case API::BlendFactor::ONE_MINUS_DST_COLOR: + return vk::BlendFactor::eOneMinusDstColor; + case API::BlendFactor::SRC_ALPHA: + return vk::BlendFactor::eSrcAlpha; + case API::BlendFactor::ONE_MINUS_SRC_ALPHA: + return vk::BlendFactor::eOneMinusSrcAlpha; + case API::BlendFactor::DST_ALPHA: + return vk::BlendFactor::eDstAlpha; + case API::BlendFactor::ONE_MINUS_DST_ALPHA: + return vk::BlendFactor::eOneMinusDstAlpha; + case API::BlendFactor::CONSTANT_COLOR: + return vk::BlendFactor::eConstantColor; + case API::BlendFactor::ONE_MINUS_CONSTANT_COLOR: + return vk::BlendFactor::eOneMinusConstantColor; + case API::BlendFactor::CONSTANT_ALPHA: + return vk::BlendFactor::eConstantAlpha; + case API::BlendFactor::ONE_MINUS_CONSTANT_ALPHA: + return vk::BlendFactor::eOneMinusConstantAlpha; + case API::BlendFactor::SRC_ALPHA_SATURATE: + return vk::BlendFactor::eSrcAlphaSaturate; + case API::BlendFactor::SRC1_COLOR: + return vk::BlendFactor::eSrc1Color; + case API::BlendFactor::ONE_MINUS_SRC1_COLOR: + return vk::BlendFactor::eOneMinusSrc1Color; + case API::BlendFactor::SRC1_ALPHA: + return vk::BlendFactor::eSrc1Alpha; + case API::BlendFactor::ONE_MINUS_SRC1_ALPHA: + return vk::BlendFactor::eOneMinusSrc1Alpha; + } + return vk::BlendFactor{}; +} + +constexpr vk::CompareOp ConvertCompareOp( Dali::Graphics::API::CompareOp compareOp) +{ + switch (compareOp) + { + case API::CompareOp::NEVER: + return vk::CompareOp::eNever; + case API::CompareOp::LESS: + return vk::CompareOp::eLess; + case API::CompareOp::EQUAL: + return vk::CompareOp::eEqual; + case API::CompareOp::LESS_OR_EQUAL: + return vk::CompareOp::eLessOrEqual; + case API::CompareOp::GREATER: + return vk::CompareOp::eGreater; + case API::CompareOp::NOT_EQUAL: + return vk::CompareOp::eNotEqual; + case API::CompareOp::GREATER_OR_EQUAL: + return vk::CompareOp::eGreaterOrEqual; + case API::CompareOp::ALWAYS: + return vk::CompareOp::eAlways; + } + return vk::CompareOp{}; +} + +constexpr vk::PrimitiveTopology ConvertPrimitiveTopology( Dali::Graphics::API::PrimitiveTopology topology) +{ + using Dali::Graphics::API::Pipeline; + switch (topology) + { + case API::PrimitiveTopology::POINT_LIST: + return vk::PrimitiveTopology::ePointList; + case API::PrimitiveTopology::LINE_LIST: + return vk::PrimitiveTopology::eLineList; + case API::PrimitiveTopology::LINE_STRIP: + return vk::PrimitiveTopology::eLineStrip; + case API::PrimitiveTopology::TRIANGLE_LIST: + return vk::PrimitiveTopology::eTriangleList; + case API::PrimitiveTopology::TRIANGLE_STRIP: + return vk::PrimitiveTopology::eTriangleStrip; + case API::PrimitiveTopology::TRIANGLE_FAN: + return vk::PrimitiveTopology::eTriangleFan; + } + return vk::PrimitiveTopology{}; +} + +constexpr vk::CullModeFlagBits ConvertCullMode( Dali::Graphics::API::CullMode cullMode) +{ + switch (cullMode) + { + case API::CullMode::NONE: + return vk::CullModeFlagBits::eNone; + case API::CullMode::FRONT: + return vk::CullModeFlagBits::eFront; + case API::CullMode::BACK: + return vk::CullModeFlagBits::eBack; + case API::CullMode::FRONT_AND_BACK: + return vk::CullModeFlagBits::eFrontAndBack; + } + return vk::CullModeFlagBits{}; +} + +constexpr vk::PolygonMode ConvertPolygonMode( Dali::Graphics::API::PolygonMode polygonMode) +{ + switch (polygonMode) + { + case API::PolygonMode::FILL: + return vk::PolygonMode::eFill; + case API::PolygonMode::LINE: + return vk::PolygonMode::eLine; + case API::PolygonMode::POINT: + return vk::PolygonMode::ePoint; + } + return vk::PolygonMode{}; +} + +constexpr vk::FrontFace ConvertFrontFace( Dali::Graphics::API::FrontFace frontFace) +{ + switch (frontFace) + { + case API::FrontFace::CLOCKWISE: + return vk::FrontFace::eClockwise; + case API::FrontFace::COUNTER_CLOCKWISE: + return vk::FrontFace::eCounterClockwise; + } + return vk::FrontFace{}; +} + +} + +struct Pipeline::PipelineCreateInfo +{ + PipelineFactory::Info info; +}; + +struct Pipeline::VulkanPipelineState +{ + VulkanPipelineState() = default; + ~VulkanPipelineState() = default; + + vk::PipelineColorBlendStateCreateInfo colorBlend; + std::vector colorBlendAttachmentState; + + vk::PipelineDepthStencilStateCreateInfo depthStencil; + vk::PipelineInputAssemblyStateCreateInfo inputAssembly; + vk::PipelineMultisampleStateCreateInfo multisample; + vk::PipelineRasterizationStateCreateInfo rasterization; + vk::PipelineTessellationStateCreateInfo tesselation; + vk::PipelineVertexInputStateCreateInfo vertexInput; + + struct ViewportState + { + vk::PipelineViewportStateCreateInfo createInfo; + std::vector viewports; + std::vector scissors; + } viewport; + + Vulkan::RefCountedPipeline pipeline{}; +}; + +Pipeline::Pipeline( Vulkan::Graphics& graphics, Controller& controller, const PipelineFactory* factory ) +: mGraphics( controller.GetGraphics() ), + mController( controller ) +{ + mHashCode = factory->GetHashCode(); + + // copy info + mCreateInfo = std::unique_ptr(new PipelineCreateInfo({factory->GetCreateInfo()})); + + mPipelineCache = factory->mPipelineCache; + + Initialise(); +} + +Pipeline::~Pipeline() +{ + // deleting pipeline +} + +uint32_t GetLocationIndex( const std::vector& attribs, uint32_t location ) +{ + auto retval = 0u; + + for( auto&& attr : attribs ) + { + if( attr.location == location ) + { + return retval; + } + retval++; + } + return -1u; +} + +bool Pipeline::Initialise() +{ + mVulkanPipelineState = std::unique_ptr( new VulkanPipelineState() ); + + // get shaders + const auto& shader = static_cast(mCreateInfo->info.shaderState.shaderProgram); + auto vertexShader = shader->GetShader(vk::ShaderStageFlagBits::eVertex); + auto fragmentShader = shader->GetShader(vk::ShaderStageFlagBits::eFragment); + + // retrieve input attributes descriptions + std::vector attribs{}; + vertexShader->GetSPIRVReflection() + .GetVertexInputAttributes(attribs); + + std::vector attributeDescriptions{}; + std::vector bindingDescriptions{}; + + const auto& bufferBindings = mCreateInfo->info.vertexInputState.bufferBindings; + const auto& attributes = mCreateInfo->info.vertexInputState.attributes; + + // vertex buffer bindings match order of buffers + for( uint32_t bindingIndex = 0u; bindingIndex < bufferBindings.size(); ++bindingIndex ) + { + bindingDescriptions.emplace_back(vk::VertexInputBindingDescription{} + .setBinding(bindingIndex) + .setInputRate( + bufferBindings[bindingIndex].inputRate == API::VertexInputRate::PER_VERTEX + ? vk::VertexInputRate::eVertex + : vk::VertexInputRate::eInstance) + .setStride(bufferBindings[bindingIndex].stride)); + } + + // create attribute descriptions + if( !attribs.empty() && attribs.size() == attribs.size() ) + { + for (auto&& vb : attributes ) + { + attributeDescriptions.emplace_back(vk::VertexInputAttributeDescription{} + .setBinding(vb.binding) + .setFormat(attribs[GetLocationIndex( attribs, vb.location)].format) + .setLocation(vb.location ) + .setOffset(vb.offset)); + } + } + else // incompatible pipeline + { + return false; + } + + // prepare vertex input state + auto vertexInputState = vk::PipelineVertexInputStateCreateInfo{} + .setVertexBindingDescriptionCount(Vulkan::U32(bindingDescriptions.size())) + .setPVertexBindingDescriptions(bindingDescriptions.data()) + .setVertexAttributeDescriptionCount(Vulkan::U32(attributeDescriptions.size())) + .setPVertexAttributeDescriptions(attributeDescriptions.data()); + + std::vector shaderStages = + { + vk::PipelineShaderStageCreateInfo{} + .setModule(vertexShader->GetVkHandle()) + .setStage(vk::ShaderStageFlagBits::eVertex) + .setPName("main"), + vk::PipelineShaderStageCreateInfo{} + .setModule(fragmentShader->GetVkHandle()) + .setStage(vk::ShaderStageFlagBits::eFragment) + .setPName("main") + }; + + // @todo use RenderTarget + auto swapchain = mGraphics.GetSwapchainForFBID(0); + auto fb = swapchain->GetCurrentFramebuffer(); + + vk::GraphicsPipelineCreateInfo pipelineInfo; + pipelineInfo + .setSubpass(0) + .setRenderPass(fb->GetRenderPassVkHandle()) // based on render target + .setBasePipelineHandle(nullptr) + .setBasePipelineIndex(0) + .setLayout(PreparePipelineLayout()) + .setPColorBlendState(PrepareColorBlendStateCreateInfo()) + .setPDepthStencilState(PrepareDepthStencilStateCreateInfo()) + .setPDynamicState(nullptr) + .setPInputAssemblyState(PrepareInputAssemblyStateCreateInfo()) + .setPMultisampleState(PrepareMultisampleStateCreateInfo()) + .setPRasterizationState(PrepareRasterizationStateCreateInfo()) + .setPTessellationState(PrepareTesselationStateCreateInfo()) + //.setPVertexInputState(PrepareVertexInputStateCreateInfo()) + .setPVertexInputState(&vertexInputState) + .setPViewportState(PrepareViewportStateCreateInfo()) + .setPStages(shaderStages.data()) + .setStageCount(Vulkan::U32(shaderStages.size())); + + auto pipeline = Vulkan::Pipeline::New(mGraphics, pipelineInfo); + + pipeline->Compile(); + + mVulkanPipelineState->pipeline = pipeline; + return true; +} + + + +const vk::PipelineColorBlendStateCreateInfo* Pipeline::PrepareColorBlendStateCreateInfo() +{ + const auto& factoryInfo = mCreateInfo->info; + + // blending enabled + bool blendEnable = factoryInfo.colorBlendState.blendEnable; + + // color write mask + vk::ColorComponentFlags colorWriteMask{}; + colorWriteMask |= ( factoryInfo.colorBlendState.colorComponentWriteBits & 1 ) ? vk::ColorComponentFlagBits::eR : vk::ColorComponentFlagBits{}; + colorWriteMask |= ( factoryInfo.colorBlendState.colorComponentWriteBits & 2 ) ? vk::ColorComponentFlagBits::eG : vk::ColorComponentFlagBits{}; + colorWriteMask |= ( factoryInfo.colorBlendState.colorComponentWriteBits & 4 ) ? vk::ColorComponentFlagBits::eB : vk::ColorComponentFlagBits{}; + colorWriteMask |= ( factoryInfo.colorBlendState.colorComponentWriteBits & 8 ) ? vk::ColorComponentFlagBits::eA : vk::ColorComponentFlagBits{}; + + auto srcColorBlendFactor = ConvertBlendFactor( factoryInfo.colorBlendState.srcColorBlendFactor ); + auto dstColorBlendFactor = ConvertBlendFactor( factoryInfo.colorBlendState.dstColorBlendFactor ); + auto srcAlphaBlendFactor = ConvertBlendFactor( factoryInfo.colorBlendState.srcAlphaBlendFactor ); + auto dstAlphaBlendFactor = ConvertBlendFactor( factoryInfo.colorBlendState.dstAlphaBlendFactor ); + auto colorBlendOp = ConvertBlendOp( factoryInfo.colorBlendState.colorBlendOp ); + auto alphaBlendOp = ConvertBlendOp( factoryInfo.colorBlendState.alphaBlendOp ); + + auto blendAttachmentState = vk::PipelineColorBlendAttachmentState{} + .setBlendEnable( vk::Bool32( blendEnable ) ) + .setColorWriteMask( colorWriteMask ) + .setSrcColorBlendFactor( srcColorBlendFactor ) + .setDstColorBlendFactor( dstColorBlendFactor ) + .setSrcAlphaBlendFactor( srcAlphaBlendFactor ) + .setDstAlphaBlendFactor( dstAlphaBlendFactor ) + .setColorBlendOp( colorBlendOp ) + .setAlphaBlendOp( alphaBlendOp ); + + mVulkanPipelineState->colorBlendAttachmentState.emplace_back( blendAttachmentState ); + + mVulkanPipelineState->colorBlend + .setBlendConstants( { factoryInfo.colorBlendState.blendConstants[0], + factoryInfo.colorBlendState.blendConstants[1], + factoryInfo.colorBlendState.blendConstants[2], + factoryInfo.colorBlendState.blendConstants[3] } ) + .setAttachmentCount( 1 ) + .setPAttachments( mVulkanPipelineState->colorBlendAttachmentState.data() ); + + return &mVulkanPipelineState->colorBlend; +} + +const vk::PipelineDepthStencilStateCreateInfo* Pipeline::PrepareDepthStencilStateCreateInfo() +{ + const auto& dsInfo = mCreateInfo->info.depthStencilState; + return &(mVulkanPipelineState->depthStencil + .setDepthTestEnable( vk::Bool32(dsInfo.depthTestEnable) ) + .setDepthWriteEnable( vk::Bool32(dsInfo.depthWriteEnable) ) + .setDepthCompareOp( ConvertCompareOp( dsInfo.depthCompareOp )) + .setDepthBoundsTestEnable( false ) + .setStencilTestEnable( false )); //@ todo stencil test +} + +const vk::PipelineInputAssemblyStateCreateInfo* Pipeline::PrepareInputAssemblyStateCreateInfo() +{ + const auto& iaInfo = mCreateInfo->info.inputAssemblyState; + //@todo support topology and restart + return &(mVulkanPipelineState->inputAssembly + .setPrimitiveRestartEnable( vk::Bool32( iaInfo.primitiveRestartEnable ) ) + .setTopology( ConvertPrimitiveTopology( iaInfo.topology ) )); +} + +const vk::PipelineMultisampleStateCreateInfo* Pipeline::PrepareMultisampleStateCreateInfo() +{ + return &(mVulkanPipelineState->multisample + .setSampleShadingEnable( vk::Bool32(false) ) + .setRasterizationSamples( vk::SampleCountFlagBits::e1 ) + .setAlphaToCoverageEnable( vk::Bool32(false) ) + .setMinSampleShading( 1.0f ) + .setPSampleMask( nullptr )); +} + +const vk::PipelineRasterizationStateCreateInfo* Pipeline::PrepareRasterizationStateCreateInfo() +{ + const auto& rsInfo = mCreateInfo->info.rasterizationState; + return &(mVulkanPipelineState->rasterization + .setCullMode( ConvertCullMode( rsInfo.cullMode ) ) + .setDepthBiasClamp( 0.0f ) + .setDepthBiasEnable( vk::Bool32(false) ) + .setDepthClampEnable( vk::Bool32(false) ) + .setFrontFace( ConvertFrontFace( rsInfo.frontFace ) ) + .setPolygonMode( ConvertPolygonMode( rsInfo.polygonMode ) ) + .setRasterizerDiscardEnable( vk::Bool32(false) ) + .setLineWidth( 1.0f )); +} + +const vk::PipelineViewportStateCreateInfo* Pipeline::PrepareViewportStateCreateInfo() +{ + const auto& vpInfo = mCreateInfo->info.viewportState; + + auto width = vpInfo.viewport.width; + auto height = vpInfo.viewport.height; + + if( !uint32_t(width) ) + { + width = float(mGraphics.GetSwapchainForFBID(0)->GetCurrentFramebuffer()->GetWidth()); + height = float(mGraphics.GetSwapchainForFBID(0)->GetCurrentFramebuffer()->GetHeight()); + } + + // viewports + mVulkanPipelineState->viewport.viewports.emplace_back( vpInfo.viewport.x, vpInfo.viewport.y, width, height ); + mVulkanPipelineState->viewport.viewports[0].setMinDepth( vpInfo.viewport.minDepth ); + mVulkanPipelineState->viewport.viewports[0].setMaxDepth( vpInfo.viewport.maxDepth ); + + // scissors + // todo: add scissor support + mVulkanPipelineState->viewport.scissors.emplace_back( vk::Rect2D( + { static_cast(0), static_cast(0) }, + { Vulkan::U32(width), Vulkan::U32(height) } ) + ); + + auto& viewState = mVulkanPipelineState->viewport; + + return &(mVulkanPipelineState->viewport.createInfo. + setViewportCount( Vulkan::U32(viewState.viewports.size()) ). + setPViewports( viewState.viewports.data() ). + setPScissors( viewState.scissors.data() ). + setScissorCount( Vulkan::U32(viewState.scissors.size())) ); +} + +const vk::PipelineTessellationStateCreateInfo* Pipeline::PrepareTesselationStateCreateInfo() +{ + return nullptr; +} + +const vk::PipelineLayout Pipeline::PreparePipelineLayout() +{ + // descriptor set layout + const auto& shader = static_cast(mCreateInfo->info.shaderState.shaderProgram); + auto vertexShader = shader->GetShader(vk::ShaderStageFlagBits::eVertex); + auto fragmentShader = shader->GetShader(vk::ShaderStageFlagBits::eFragment); + + auto vshDsLayouts = vertexShader->GetSPIRVReflection() + .GenerateDescriptorSetLayoutCreateInfo(); + auto fshDsLayouts = fragmentShader->GetSPIRVReflection() + .GenerateDescriptorSetLayoutCreateInfo(); + + decltype(vshDsLayouts) layouts; + layouts.resize(std::max(vshDsLayouts.size(), fshDsLayouts.size())); + + std::vector dsLayouts; + + for (auto i = 0u; i < layouts.size(); ++i) + { + std::vector dsBindings; + + // concatenate bindings per set + if (vshDsLayouts[i].bindingCount) + { + dsBindings.insert( + dsBindings.end(), vshDsLayouts[i].pBindings, vshDsLayouts[i].pBindings + vshDsLayouts[i].bindingCount); + } + if (fshDsLayouts[i].bindingCount) + { + dsBindings.insert( + dsBindings.end(), fshDsLayouts[i].pBindings, fshDsLayouts[i].pBindings + fshDsLayouts[i].bindingCount); + } + + layouts[i].pBindings = dsBindings.data(); + layouts[i].bindingCount = Vulkan::U32(dsBindings.size()); + + + dsLayouts.emplace_back(VkAssert(mGraphics.GetDevice() + .createDescriptorSetLayout(layouts[i], mGraphics.GetAllocator()))); + + } + + mVkDescriptorSetLayouts = dsLayouts; + + // create layout + auto pipelineLayoutCreateInfo = vk::PipelineLayoutCreateInfo{} + .setSetLayoutCount(Vulkan::U32(dsLayouts.size())) + .setPSetLayouts(dsLayouts.data()) + .setPPushConstantRanges(nullptr) + .setPushConstantRangeCount(0); + + return VkAssert(mGraphics.GetDevice().createPipelineLayout(pipelineLayoutCreateInfo, mGraphics.GetAllocator())); +} + +void Pipeline::Reference() +{ + ++mRefCounter; +} + +void Pipeline::Dereference() +{ + if(mRefCounter) + { + if (--mRefCounter == 0) + { + Destroy(); + } + } +} + +void Pipeline::Destroy() +{ + if(mPipelineCache) + { + mPipelineCache->RemovePipeline( this ); + } +} + +uint32_t Pipeline::GetHashCode() const +{ + return mHashCode; +} + +Vulkan::RefCountedPipeline Pipeline::GetVkPipeline() const +{ + return mVulkanPipelineState->pipeline; +} + +const std::vector& Pipeline::GetVkDescriptorSetLayouts() const +{ + return mVkDescriptorSetLayouts; +} + +} // Internal +} // VulkanAPI +} // Graphics +} // Dal + diff --git a/dali/graphics/vulkan/api/internal/vulkan-api-pipeline-impl.h b/dali/graphics/vulkan/api/internal/vulkan-api-pipeline-impl.h new file mode 100644 index 0000000..5b7d07c --- /dev/null +++ b/dali/graphics/vulkan/api/internal/vulkan-api-pipeline-impl.h @@ -0,0 +1,99 @@ +#ifndef DALI_GRAPHICS_VULKAN_API_PIPELINE_IMPL_H +#define DALI_GRAPHICS_VULKAN_API_PIPELINE_IMPL_H + +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include + +namespace Dali +{ +namespace Graphics +{ +namespace Vulkan +{ +class Graphics; +} + +namespace VulkanAPI +{ +class Pipeline; +class Controller; +class PipelineFactory; +class PipelineCache; +namespace Internal +{ +class Pipeline +{ +public: + + Pipeline( Vulkan::Graphics& graphics, Controller& controller, const PipelineFactory* factory ); + ~Pipeline(); + + uint32_t GetHashCode() const; + + bool Initialise(); + + void Reference(); + + void Dereference(); + + void Destroy(); + + Vulkan::RefCountedPipeline GetVkPipeline() const; + + const std::vector& GetVkDescriptorSetLayouts() const; + +private: + + const vk::PipelineColorBlendStateCreateInfo* PrepareColorBlendStateCreateInfo(); + const vk::PipelineDepthStencilStateCreateInfo* PrepareDepthStencilStateCreateInfo(); + const vk::PipelineInputAssemblyStateCreateInfo* PrepareInputAssemblyStateCreateInfo(); + const vk::PipelineMultisampleStateCreateInfo* PrepareMultisampleStateCreateInfo(); + const vk::PipelineRasterizationStateCreateInfo* PrepareRasterizationStateCreateInfo(); + const vk::PipelineTessellationStateCreateInfo* PrepareTesselationStateCreateInfo(); + const vk::PipelineViewportStateCreateInfo* PrepareViewportStateCreateInfo(); + const vk::PipelineLayout PreparePipelineLayout(); + + + Vulkan::Graphics& mGraphics; + Controller& mController; + uint32_t mHashCode; + + std::atomic_int mRefCounter{ 0u }; + + // wrapper for copy of cSreate data + struct PipelineCreateInfo; + std::unique_ptr mCreateInfo; + + struct VulkanPipelineState; + std::unique_ptr mVulkanPipelineState; + + std::vector mVkDescriptorSetLayouts; + + PipelineCache* mPipelineCache; +}; + + +} + +} +} +} + +#endif //DALI_GRAPHICS_VULKAN_API_PIPELINE_IMPL_H diff --git a/dali/graphics/vulkan/api/internal/vulkan-pipeline-cache.cpp b/dali/graphics/vulkan/api/internal/vulkan-pipeline-cache.cpp new file mode 100644 index 0000000..bfff32b --- /dev/null +++ b/dali/graphics/vulkan/api/internal/vulkan-pipeline-cache.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include + +namespace Dali +{ +namespace Graphics +{ +namespace VulkanAPI +{ + +PipelineCache::PipelineCache( Vulkan::Graphics& graphics, Controller& controller ) +{ + +} + +PipelineCache::~PipelineCache() = default; + +Internal::Pipeline* PipelineCache::GetPipeline( const VulkanAPI::PipelineFactory& factory ) const +{ + auto hashCode = factory.GetHashCode(); + auto iter = mCacheMap.find( hashCode ); + if( iter == mCacheMap.end() ) + { + return nullptr; + } + + auto& entries = iter->second; + + // return quickly if there's only one entry + if( entries.size() == 1 ) + { + return entries[0].pipelineImpl.get(); + } + + for( auto&& entry : entries ) + { + if( !std::memcmp( &entry.info, &factory.GetCreateInfo(), sizeof(entry.info) )) + { + return entry.pipelineImpl.get(); + } + } + + return nullptr; +} + +bool PipelineCache::SavePipeline( const VulkanAPI::PipelineFactory& factory, std::unique_ptr pipeline ) +{ + // hash factory + auto hashCode = factory.GetHashCode(); + auto iter = mCacheMap.find( hashCode ); + std::vector* cacheEntries { nullptr }; + + if( iter == mCacheMap.end() ) + { + mCacheMap[hashCode] = std::vector{}; + cacheEntries = &mCacheMap[hashCode]; + } + else + { + cacheEntries = &iter->second; + } + + // pass the ownership to the cache + CacheEntry entry; + entry.pipelineImpl = std::move(pipeline); + entry.info = std::unique_ptr( new PipelineFactory::Info(factory.GetCreateInfo()) ); + cacheEntries->push_back( std::move(entry) ); + return true; +} + +bool PipelineCache::RemovePipeline( Internal::Pipeline* pipeline ) +{ + auto hashCode = pipeline->GetHashCode(); + auto iter = mCacheMap.find( hashCode ); + if( iter == mCacheMap.end() ) + { + return false; + } + + // delete pipeline + // todo: for now use brute force, later - safe delete + if( iter->second.size() == 1 ) + { + iter->second.clear(); + } + else + { + uint32_t i = 0; + for( auto&& entry : iter->second ) + { + if( entry.pipelineImpl.get() == pipeline ) + { + iter->second.erase( iter->second.begin()+i ); + break; + } + ++i; + } + } + + return true; +} + +} // VulkanAPI +} // Graphics +} // Dali diff --git a/dali/graphics/vulkan/api/internal/vulkan-pipeline-cache.h b/dali/graphics/vulkan/api/internal/vulkan-pipeline-cache.h new file mode 100644 index 0000000..cf40806 --- /dev/null +++ b/dali/graphics/vulkan/api/internal/vulkan-pipeline-cache.h @@ -0,0 +1,87 @@ +#ifndef DALI_GRAPHICS_VULKAN_API_PIPELINE_CACHE_H +#define DALI_GRAPHICS_VULKAN_API_PIPELINE_CACHE_H + +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include + +#include +#include + +namespace Dali +{ +namespace Graphics +{ +namespace Vulkan +{ +class Graphics; +} // Vulkan + +namespace VulkanAPI +{ +namespace Internal +{ +class Pipeline; +} // Internal + +class Controller; +class PipelineFactory; + +class PipelineCache +{ +public: + + PipelineCache( Vulkan::Graphics& graphics, Controller& controller ); + + ~PipelineCache(); + + /** + * Finds a pipeline based on the factory setup + * @return pipeline implementation or nullptr if pipeline isn't part of cache + */ + Internal::Pipeline* GetPipeline( const VulkanAPI::PipelineFactory& factory ) const; + + /** + * Saves pipeline in the cache + * @param pipeline + * @return + */ + bool SavePipeline( const VulkanAPI::PipelineFactory& factory, std::unique_ptr pipeline ); + + /** + * Removes unused pipeline + */ + bool RemovePipeline( Internal::Pipeline* pipeline ); + + +private: + + struct CacheEntry + { + std::unique_ptr pipelineImpl; + std::unique_ptr info {}; // to compare if hash collision occurs + }; + + std::map> mCacheMap; +}; +} // VulkanAPI +} // Graphics +} // Dali + +#endif // DALI_GRAPHICS_VULKAN_API_PIPELINE_CACHE_H diff --git a/dali/graphics/vulkan/api/vulkan-api-buffer-factory.h b/dali/graphics/vulkan/api/vulkan-api-buffer-factory.h index d1a5f9a..7bb8d62 100644 --- a/dali/graphics/vulkan/api/vulkan-api-buffer-factory.h +++ b/dali/graphics/vulkan/api/vulkan-api-buffer-factory.h @@ -18,9 +18,10 @@ * */ +#include #include #include -#include + namespace Dali { diff --git a/dali/graphics/vulkan/api/vulkan-api-controller.cpp b/dali/graphics/vulkan/api/vulkan-api-controller.cpp index 69deed0..23b71bd 100644 --- a/dali/graphics/vulkan/api/vulkan-api-controller.cpp +++ b/dali/graphics/vulkan/api/vulkan-api-controller.cpp @@ -25,16 +25,11 @@ #include #include #include -#include -#include #include #include #include #include #include -#include -#include - // API #include @@ -43,13 +38,12 @@ #include #include #include +#include #include +#include #include -#include -#include - namespace Dali { namespace Graphics @@ -78,9 +72,12 @@ struct Controller::Impl mShaderFactory = std::make_unique( mGraphics ); mTextureFactory = std::make_unique( mGraphics ); mBufferFactory = std::make_unique( mOwner ); + mPipelineFactory = std::make_unique( mOwner ); mUboManager = std::make_unique( mOwner ); + mDefaultPipelineCache = std::make_unique( mGraphics, mOwner ); + return true; } @@ -131,7 +128,7 @@ struct Controller::Impl std::unique_ptr AllocateRenderCommand() { - return std::make_unique( mOwner, mGraphics, *(mPipelineCache.get()) ); + return std::make_unique( mOwner, mGraphics ); } /** @@ -152,13 +149,7 @@ struct Controller::Impl mBufferTransferRequests.clear(); } - // Prepare pipelines - for( auto&& command : commands ) - { - // prepare pipelines - auto apiCommand = static_cast(command); - apiCommand->PreparePipeline(); - } + std::vector cmdBufRefs{}; // Update uniform buffers for( auto&& command : commands ) @@ -170,6 +161,13 @@ struct Controller::Impl mUboManager->UnmapAllBuffers(); + // bind resources + for( auto&& command : commands ) + { + auto apiCommand = static_cast(command); + apiCommand->PrepareResources(); + } + // set up writes for( auto&& command : commands ) { @@ -182,13 +180,13 @@ struct Controller::Impl auto cmdbuf = mGraphics.CreateCommandBuffer( false );//mCommandPool->NewCommandBuffer( false ); cmdbuf->Reset(); cmdbuf->Begin( vk::CommandBufferUsageFlagBits::eRenderPassContinue ); - cmdbuf->BindGraphicsPipeline( apiCommand->GetPipeline() ); + cmdbuf->BindGraphicsPipeline( apiCommand->GetVulkanPipeline() ); // bind vertex buffers auto binding = 0u; for( auto&& vb : apiCommand->GetVertexBufferBindings() ) { - cmdbuf->BindVertexBuffer( binding++, static_cast(vb.buffer.Get()).GetBufferRef(), vb.offset ); + cmdbuf->BindVertexBuffer( binding++, static_cast( vb.Get() ).GetBufferRef(), 0 ); } // note: starting set = 0 @@ -226,6 +224,8 @@ struct Controller::Impl ObjectOwner mShadersOwner; ObjectOwner mBuffersOwner; + std::unique_ptr mDefaultPipelineCache; + Vulkan::Graphics& mGraphics; Controller& mOwner; Vulkan::GpuMemoryAllocator& mDefaultAllocator; @@ -233,11 +233,10 @@ struct Controller::Impl std::unique_ptr mTextureFactory; std::unique_ptr mShaderFactory; std::unique_ptr mBufferFactory; + std::unique_ptr mPipelineFactory; std::vector> mBufferTransferRequests; - std::unique_ptr mPipelineCache; - std::unique_ptr mUboManager; // Accumulate all the secondary command buffers of the frame here to avoid them being overwritten @@ -281,6 +280,19 @@ API::Accessor Controller::CreateSampler( const API::BaseFactory Controller::CreatePipeline( const API::BaseFactory& factory ) +{ + auto& pipelineFactory = const_cast(dynamic_cast( factory )); + + // if no custom cache, use default one + if(!pipelineFactory.mPipelineCache) + { + pipelineFactory.mPipelineCache = mImpl->mDefaultPipelineCache.get(); + } + + return mImpl->mPipelineFactory->Create(); +} + API::Accessor Controller::CreateFramebuffer( const API::BaseFactory& factory ) { return { nullptr }; @@ -305,10 +317,6 @@ Controller::~Controller() = default; Controller::Controller() = default; Controller& Controller::operator=( Controller&& ) noexcept = default; -void Controller::GetRenderItemList() -{ -} - void Controller::BeginFrame() { mImpl->BeginFrame(); @@ -334,6 +342,12 @@ API::BufferFactory& Controller::GetBufferFactory() const return mImpl->GetBufferFactory(); } +API::PipelineFactory& Controller::GetPipelineFactory() +{ + mImpl->mPipelineFactory->Reset(); + return *mImpl->mPipelineFactory; +} + Vulkan::Graphics& Controller::GetGraphics() const { return mImpl->mGraphics; diff --git a/dali/graphics/vulkan/api/vulkan-api-controller.h b/dali/graphics/vulkan/api/vulkan-api-controller.h index 1580d86..ed182ed 100644 --- a/dali/graphics/vulkan/api/vulkan-api-controller.h +++ b/dali/graphics/vulkan/api/vulkan-api-controller.h @@ -93,6 +93,11 @@ public: /** * @brief Create a new object */ + std::unique_ptr CreatePipeline( const API::BaseFactory& factory ) override; + + /** + * @brief Create a new object + */ API::Accessor CreateFramebuffer( const API::BaseFactory& factory ) override; std::unique_ptr CreateBuffer( size_t numberOfElements, size_t elementSize ) override; @@ -101,16 +106,10 @@ public: std::unique_ptr AllocateRenderCommand() override; - /** - * @brief Get a render list - */ - void GetRenderItemList() override; - void BeginFrame() override; void EndFrame() override; - // VULKAN only public: @@ -129,6 +128,8 @@ public: API::BufferFactory& GetBufferFactory() const override; + API::PipelineFactory& GetPipelineFactory() override; + public: // not copyable Controller( const Controller& ) = delete; diff --git a/dali/graphics/vulkan/api/vulkan-api-pipeline-factory.cpp b/dali/graphics/vulkan/api/vulkan-api-pipeline-factory.cpp new file mode 100644 index 0000000..075778f --- /dev/null +++ b/dali/graphics/vulkan/api/vulkan-api-pipeline-factory.cpp @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include + +namespace Dali +{ +namespace Graphics +{ +namespace VulkanAPI +{ + +namespace +{ +/** + * Hashing binary data, it may not be the best algorithm + * @return + */ +uint32_t HashBinary(const void *dataObj, uint32_t size) +{ + const uint8_t *data = reinterpret_cast(dataObj); + uint32_t hash = 5381u; + uint32_t c; + for (uint32_t i = 0; i < size; ++i) + { + c = *data++; + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + } + return hash; +} + +uint32_t HashPipeline(const VulkanAPI::PipelineFactory::Info &info) +{ + uint32_t dsHash = HashBinary( &info.depthStencilState, sizeof(info.depthStencilState) ); + uint32_t cbHash = HashBinary( &info.colorBlendState, sizeof(info.colorBlendState) ); + uint32_t shHash = HashBinary( &info.shaderState, sizeof(info.shaderState) ); + uint32_t vpHash = HashBinary( &info.viewportState, sizeof(info.viewportState) ); + uint32_t rsHash = HashBinary( &info.rasterizationState, sizeof(info.rasterizationState) ); + uint32_t iaHash = HashBinary( &info.inputAssemblyState, sizeof(info.inputAssemblyState) ); + + // vertex input contains std containers so has to be hashed differently + uint32_t viStateBindingsHash = HashBinary( info.vertexInputState.bufferBindings.data(), uint32_t(sizeof( API::VertexInputState::Binding )*info.vertexInputState.bufferBindings.size()) ); + uint32_t viStateAttributesHash = HashBinary( info.vertexInputState.attributes.data(), uint32_t(sizeof( API::VertexInputState::Attribute )*info.vertexInputState.attributes.size()) ); + + // rehash all + std::array allHashes = { + dsHash, cbHash, shHash, vpHash, rsHash, iaHash, viStateBindingsHash, viStateAttributesHash + }; + + return HashBinary( allHashes.data(), uint32_t(allHashes.size() * sizeof(uint32_t))); +} + +} + +PipelineFactory::PipelineFactory( Controller& controller ) +: mController( controller ), + mGraphics( controller.GetGraphics() ), + mHashCode( 0u ) +{ +} + +API::PipelineFactory& PipelineFactory::SetPipelineCache(VulkanAPI::PipelineCache& pipelineCache) +{ + mPipelineCache = dynamic_cast(&pipelineCache); + return *this; +} + + +API::PipelineFactory& PipelineFactory::SetColorBlendState(const API::ColorBlendState& state ) +{ + mInfo.colorBlendState = state; + mHashCode = 0u; + return *this; +} + + +API::PipelineFactory& PipelineFactory::SetShaderState( const API::ShaderState& state ) +{ + mInfo.shaderState = state; + mHashCode = 0u; + return *this; +} + +API::PipelineFactory& PipelineFactory::SetViewportState( const API::ViewportState& state ) +{ + mInfo.viewportState = state; + mHashCode = 0u; + return *this; +} + +API::PipelineFactory& PipelineFactory::SetBasePipeline(API::Pipeline& pipeline) +{ + mBasePipeline = dynamic_cast(&pipeline); + mHashCode = 0u; + return *this; +} + +API::PipelineFactory& PipelineFactory::SetDepthStencilState( API::DepthStencilState state ) +{ + mInfo.depthStencilState = state; + mHashCode = 0u; + return *this; +} + +API::PipelineFactory& PipelineFactory::SetRasterizationState( const API::RasterizationState& state ) +{ + mInfo.rasterizationState = state; + mHashCode = 0u; + return *this; +} + +API::PipelineFactory& PipelineFactory::SetVertexInputState( const API::VertexInputState& state ) +{ + mInfo.vertexInputState = state; + mHashCode = 0u; + return *this; +} + +API::PipelineFactory& PipelineFactory::SetInputAssemblyState( const API::InputAssemblyState& state ) +{ + mInfo.inputAssemblyState = state; + mHashCode = 0u; + return *this; +} + +std::unique_ptr PipelineFactory::Create() const +{ + // todo: validate pipeline + + // check cache + if( mPipelineCache ) + { + auto ptr = mPipelineCache->GetPipeline( *this ); + // if pipeline is already in cache, attach implementation and return unique ptr + if( ptr ) + { + return std::unique_ptr( new VulkanAPI::Pipeline( ptr ) ); + } + } + + return std::unique_ptr( new VulkanAPI::Pipeline( mGraphics, mController, this ) ); +} + +void PipelineFactory::Reset() +{ + mInfo.depthStencilState = {}; + mInfo.colorBlendState = {}; + mInfo.shaderState = {}; + mInfo.viewportState = {}; + mInfo.rasterizationState = {}; + mInfo.vertexInputState = {}; + mInfo.inputAssemblyState = {}; + mPipelineCache = nullptr; + mBasePipeline = nullptr; +} + +uint32_t PipelineFactory::GetHashCode() const +{ + if( !mHashCode ) + { + mHashCode = HashPipeline( GetCreateInfo() ); + } + return mHashCode; +} + +} +} +} \ No newline at end of file diff --git a/dali/graphics/vulkan/api/vulkan-api-pipeline-factory.h b/dali/graphics/vulkan/api/vulkan-api-pipeline-factory.h new file mode 100644 index 0000000..3656281 --- /dev/null +++ b/dali/graphics/vulkan/api/vulkan-api-pipeline-factory.h @@ -0,0 +1,103 @@ +#ifndef DALI_GRAPHICS_VULKAN_API_PIPELINE_FACTORY_H +#define DALI_GRAPHICS_VULKAN_API_PIPELINE_FACTORY_H + +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include + +namespace Dali +{ +namespace Graphics +{ + +namespace Vulkan +{ +class Graphics; +} + +namespace VulkanAPI +{ +class Controller; +class Pipeline; +class PipelineCache; +/** + * @brief Interface class for ShaderFactory types in the graphics API. + */ +class PipelineFactory : public API::PipelineFactory +{ +public: + + PipelineFactory( Controller& controller ); + + API::PipelineFactory& SetPipelineCache( VulkanAPI::PipelineCache& pipelineCache ); + + API::PipelineFactory& SetColorBlendState( const API::ColorBlendState& state ) override; + + API::PipelineFactory& SetShaderState( const API::ShaderState& state ) override; + + API::PipelineFactory& SetViewportState( const API::ViewportState& state ) override; + + API::PipelineFactory& SetBasePipeline( API::Pipeline& pipeline ) override; + + API::PipelineFactory& SetDepthStencilState( API::DepthStencilState state ) override; + + API::PipelineFactory& SetRasterizationState( const API::RasterizationState& state ) override; + + API::PipelineFactory& SetVertexInputState( const API::VertexInputState& state ) override; + + API::PipelineFactory& SetInputAssemblyState( const API::InputAssemblyState& state ) override; + + // To be called when getting new factory + void Reset(); + + std::unique_ptr Create() const override; + + uint32_t GetHashCode() const; + + struct Info + { + API::DepthStencilState depthStencilState; + API::ColorBlendState colorBlendState; + API::ShaderState shaderState; + API::ViewportState viewportState; + API::RasterizationState rasterizationState; + API::VertexInputState vertexInputState; + API::InputAssemblyState inputAssemblyState; + }; + + const Info& GetCreateInfo() const + { + return mInfo; + } + +public: + + Info mInfo; + Controller& mController; + Vulkan::Graphics& mGraphics; + VulkanAPI::PipelineCache* mPipelineCache; + VulkanAPI::Pipeline* mBasePipeline; + mutable uint32_t mHashCode; +}; + +} // namespace API +} // namespace Graphics +} // namespace Dali + +#endif // DALI_GRAPHICS_VULKAN_API_PIPELINE_FACTORY_H + diff --git a/dali/graphics/vulkan/api/vulkan-api-pipeline.cpp b/dali/graphics/vulkan/api/vulkan-api-pipeline.cpp new file mode 100644 index 0000000..9fa9816 --- /dev/null +++ b/dali/graphics/vulkan/api/vulkan-api-pipeline.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include + +namespace Dali +{ +namespace Graphics +{ +namespace VulkanAPI +{ + +Pipeline::Pipeline( Vulkan::Graphics& graphics, Controller& controller, const PipelineFactory* factory ) +{ + mPipelineImpl = new Internal::Pipeline( graphics, controller, factory ); + + // ownership on the implementation is given away to cache + factory->mPipelineCache->SavePipeline( *factory, std::unique_ptr( mPipelineImpl ) ); + + mPipelineImpl->Reference(); +} + +Pipeline::~Pipeline() +{ + mPipelineImpl->Dereference(); +} + +Pipeline::Pipeline( Internal::Pipeline* impl ) : +mPipelineImpl( impl ) +{ + mPipelineImpl->Reference(); +} + +Vulkan::RefCountedPipeline Pipeline::GetVkPipeline() const +{ + return mPipelineImpl->GetVkPipeline(); +} + +const std::vector& Pipeline::GetVkDescriptorSetLayouts() const +{ + return mPipelineImpl->GetVkDescriptorSetLayouts(); +} + + +} +} +} diff --git a/dali/graphics/vulkan/api/vulkan-api-pipeline.h b/dali/graphics/vulkan/api/vulkan-api-pipeline.h new file mode 100644 index 0000000..220d0eb --- /dev/null +++ b/dali/graphics/vulkan/api/vulkan-api-pipeline.h @@ -0,0 +1,75 @@ +#ifndef DALI_GRAPHICS_VULKAN_API_PIPELINE_H +#define DALI_GRAPHICS_VULKAN_API_PIPELINE_H + +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include + +namespace Dali +{ +namespace Graphics +{ +namespace Vulkan +{ +class Graphics; +class PipelineCache; +} + +namespace VulkanAPI +{ +namespace Internal +{ +class Pipeline; +} + +class Controller; +class PipelineFactory; +/** + * Pipeline due to its nature ( it's cached, single ownership ) is only an interface + */ +class Pipeline : public API::Pipeline +{ +public: + + Pipeline( Vulkan::Graphics& graphics, Controller& controller, const PipelineFactory* factory ); + + ~Pipeline() override; + + // non-copyable + Pipeline( const Pipeline& ) = delete; + Pipeline& operator=( const Pipeline& ) = delete; + + // movable + Pipeline( Pipeline&& ) = default; + Pipeline& operator=( Pipeline&& ) = default; + + Pipeline( Internal::Pipeline* impl ); + + Vulkan::RefCountedPipeline GetVkPipeline() const; + + const std::vector& GetVkDescriptorSetLayouts() const; + +private: + Internal::Pipeline* mPipelineImpl; +}; +} +} +} + +#endif // DALI_GRAPHICS_VULKAN_API_PIPELINE_H diff --git a/dali/graphics/vulkan/api/vulkan-api-render-command.cpp b/dali/graphics/vulkan/api/vulkan-api-render-command.cpp index d9608e5..374849f 100644 --- a/dali/graphics/vulkan/api/vulkan-api-render-command.cpp +++ b/dali/graphics/vulkan/api/vulkan-api-render-command.cpp @@ -16,21 +16,24 @@ */ #include + #include + #include #include +#include #include #include #include #include #include -#include #include #include #include #include #include #include + #include #include @@ -48,221 +51,26 @@ using Vulkan::VkAssert; namespace VulkanAPI { -struct RenderCommand::VulkanPipelineState -{ - VulkanPipelineState() = default; - ~VulkanPipelineState() = default; - - vk::PipelineColorBlendStateCreateInfo colorBlend; - std::vector colorBlendAttachmentState; - - vk::PipelineDepthStencilStateCreateInfo depthStencil; - vk::PipelineInputAssemblyStateCreateInfo inputAssembly; - vk::PipelineMultisampleStateCreateInfo multisample; - vk::PipelineRasterizationStateCreateInfo rasterization; - vk::PipelineTessellationStateCreateInfo tesselation; - vk::PipelineVertexInputStateCreateInfo vertexInput; - - struct ViewportState - { - vk::PipelineViewportStateCreateInfo createInfo; - std::vector viewports; - std::vector scissors; - } viewport; -}; - RenderCommand::~RenderCommand() = default; -RenderCommand::RenderCommand( VulkanAPI::Controller& controller, Vulkan::Graphics& graphics, Vulkan::PipelineCache& pipelineCache ) -: mController( controller ), mGraphics( graphics ), mPipelineCache( pipelineCache ), mCommandBuffer(), mPipeline(), mUpdateFlags( UPDATE_ALL ) -{ -} - -uint32_t GetLocationIndex( const std::vector& attribs, uint32_t location ) +RenderCommand::RenderCommand( VulkanAPI::Controller& controller, Vulkan::Graphics& graphics ) +: mController( controller ), mGraphics( graphics ), mCommandBuffer(), mUpdateFlags( UPDATE_ALL ) { - auto retval = 0u; - - for( auto&& attr : attribs ) - { - if( attr.location == location ) - { - return retval; - } - retval++; - } - return -1u; } - ///@todo: needs pipeline factory rather than pipeline creation in place!!! -bool RenderCommand::PreparePipeline() +void RenderCommand::PrepareResources() { if( mUpdateFlags ) { - auto &pipelineCache = mGraphics.GetPipelineCache(); - - const auto &renderState = GetRenderState(); - const auto &shader = static_cast( renderState.shader - .Get()); - - auto vertexShader = shader.GetShader(vk::ShaderStageFlagBits::eVertex); - auto fragmentShader = shader.GetShader(vk::ShaderStageFlagBits::eFragment); - - auto pipelineRef = pipelineCache.GetPipeline({vertexShader, fragmentShader, renderState.blendState, {}}); - - if (!pipelineRef) + if( !mVulkanPipeline ) { - // retrieve input attributes descriptions - std::vector attribs{}; - vertexShader->GetSPIRVReflection() - .GetVertexInputAttributes(attribs); - std::vector attributeDescriptions{}; - - // prepare vertex buffer bindings - auto bindingIndex{0u}; - std::vector bindingDescriptions{}; - - uint32_t currentBuffer{0xffffffff}; - if( !attribs.empty() && attribs.size() == GetVertexBufferBindings().size() ) - { - for (auto &&vb : GetVertexBufferBindings()) - { - if (currentBuffer != vb.buffer - .GetHandle()) - { - bindingDescriptions.emplace_back(vk::VertexInputBindingDescription{} - .setBinding(bindingIndex) - .setInputRate( - vb.rate == API::RenderCommand::InputAttributeRate::PER_VERTEX - ? vk::VertexInputRate::eVertex - : vk::VertexInputRate::eInstance) - .setStride(vb.stride)); - bindingIndex++; - currentBuffer = Vulkan::U32(vb.buffer - .GetHandle()); - } - - - attributeDescriptions.emplace_back(vk::VertexInputAttributeDescription{} - .setBinding(bindingDescriptions.back() - .binding) - .setFormat(attribs[GetLocationIndex( attribs, vb.location)].format) - .setLocation( vb.location ) - .setOffset(vb.offset)); - } - } - else // incompatible pipeline - { - mUpdateFlags = 0; - return false; - } - - auto vertexInputState = vk::PipelineVertexInputStateCreateInfo{} - .setVertexBindingDescriptionCount(Vulkan::U32(bindingDescriptions.size())) - .setPVertexBindingDescriptions(bindingDescriptions.data()) - .setVertexAttributeDescriptionCount(Vulkan::U32(attributeDescriptions.size())) - .setPVertexAttributeDescriptions(attributeDescriptions.data()); - - // descriptor set layout - auto vshDsLayouts = vertexShader->GetSPIRVReflection() - .GenerateDescriptorSetLayoutCreateInfo(); - auto fshDsLayouts = fragmentShader->GetSPIRVReflection() - .GenerateDescriptorSetLayoutCreateInfo(); - - decltype(vshDsLayouts) layouts; - layouts.resize(std::max(vshDsLayouts.size(), fshDsLayouts.size())); - - std::vector dsLayouts; - - for (auto i = 0u; i < layouts.size(); ++i) - { - std::vector dsBindings; - - // concatenate bindings per set - if (vshDsLayouts[i].bindingCount) - { - dsBindings.insert( - dsBindings.end(), vshDsLayouts[i].pBindings, vshDsLayouts[i].pBindings + vshDsLayouts[i].bindingCount); - } - if (fshDsLayouts[i].bindingCount) - { - dsBindings.insert( - dsBindings.end(), fshDsLayouts[i].pBindings, fshDsLayouts[i].pBindings + fshDsLayouts[i].bindingCount); - } - - layouts[i].pBindings = dsBindings.data(); - layouts[i].bindingCount = Vulkan::U32(dsBindings.size()); - - - dsLayouts.emplace_back(VkAssert(mGraphics.GetDevice() - .createDescriptorSetLayout(layouts[i], mGraphics.GetAllocator()))); - - } - - // create layout - auto pipelineLayoutCreateInfo = vk::PipelineLayoutCreateInfo{} - .setSetLayoutCount(Vulkan::U32(dsLayouts.size())) - .setPSetLayouts(dsLayouts.data()) - .setPPushConstantRanges(nullptr) - .setPushConstantRangeCount(0); - - auto pipelineLayout = VkAssert(mGraphics.GetDevice() - .createPipelineLayout(pipelineLayoutCreateInfo, - mGraphics.GetAllocator())); - - std::vector shaderStages = - { - vk::PipelineShaderStageCreateInfo{} - .setModule(vertexShader->GetVkHandle()) - .setStage(vk::ShaderStageFlagBits::eVertex) - .setPName("main"), - vk::PipelineShaderStageCreateInfo{} - .setModule(fragmentShader->GetVkHandle()) - .setStage(vk::ShaderStageFlagBits::eFragment) - .setPName("main") - }; - - mVulkanPipelineState = std::make_unique(); - - // @todo use RenderTarget - auto swapchain = mGraphics.GetSwapchainForFBID(0); - auto fb = swapchain->GetCurrentFramebuffer(); - vk::GraphicsPipelineCreateInfo pipelineInfo; - pipelineInfo - .setSubpass(0) - .setRenderPass(fb->GetRenderPassVkHandle()) // based on render target - .setBasePipelineHandle(nullptr) - .setBasePipelineIndex(0) - .setLayout(pipelineLayout) - .setPColorBlendState(PrepareColorBlendStateCreateInfo()) - .setPDepthStencilState(PrepareDepthStencilStateCreateInfo()) - .setPDynamicState(nullptr) - .setPInputAssemblyState(PrepareInputAssemblyStateCreateInfo()) - .setPMultisampleState(PrepareMultisampleStateCreateInfo()) - .setPRasterizationState(PrepareRasterizationStateCreateInfo()) - .setPTessellationState(PrepareTesselationStateCreateInfo()) - //.setPVertexInputState(PrepareVertexInputStateCreateInfo()) - .setPVertexInputState(&vertexInputState) - .setPViewportState(PrepareViewportStateCreateInfo()) - .setPStages(shaderStages.data()) - .setStageCount(Vulkan::U32(shaderStages.size())); - - auto pipeline = Vulkan::Pipeline::New(mGraphics, pipelineInfo); - - pipeline->Compile(); - - pipelineCache.AddPipeline(pipeline, Vulkan::PipelineDescription{vertexShader, fragmentShader, renderState.blendState, dsLayouts}); - - pipelineRef = pipeline; - + auto pipeline = dynamic_cast( mPipeline ); + mVkDescriptorSetLayouts.clear(); + mVkDescriptorSetLayouts = pipeline->GetVkDescriptorSetLayouts(); + mVulkanPipeline = pipeline->GetVkPipeline(); } - mPipeline = pipelineRef; - - mVkDescriptorSetLayouts.clear(); - - mVkDescriptorSetLayouts = pipelineCache.GetDescriptorSetLayouts(mPipeline); - // based on pipeline recreate descriptor pool auto poolSizes = std::vector{ vk::DescriptorPoolSize{} @@ -300,7 +108,6 @@ bool RenderCommand::PreparePipeline() mUpdateFlags = 0u; } - return true; } void RenderCommand::UpdateUniformBuffers() @@ -315,139 +122,11 @@ void RenderCommand::UpdateUniformBuffers() } } -const vk::PipelineColorBlendStateCreateInfo* RenderCommand::PrepareColorBlendStateCreateInfo() -{ - //@todo support more attachments - //@todo use data from render state - auto blendAttachmentState = vk::PipelineColorBlendAttachmentState{} - .setBlendEnable( vk::Bool32(mRenderState.blendState.blendingEnabled) ) - .setColorWriteMask( vk::ColorComponentFlagBits::eR | - vk::ColorComponentFlagBits::eG | - vk::ColorComponentFlagBits::eB | - vk::ColorComponentFlagBits::eA ) - .setSrcColorBlendFactor( vk::BlendFactor::eSrcAlpha ) - .setDstColorBlendFactor( vk::BlendFactor::eOneMinusSrcAlpha ) - .setSrcAlphaBlendFactor( vk::BlendFactor::eOne ) - .setDstAlphaBlendFactor( vk::BlendFactor::eOneMinusSrcAlpha ) - .setColorBlendOp( vk::BlendOp::eAdd ) - .setAlphaBlendOp( vk::BlendOp::eAdd ); - - mVulkanPipelineState->colorBlendAttachmentState.emplace_back( blendAttachmentState ); - - mVulkanPipelineState->colorBlend - .setBlendConstants( { 1.0f, 1.0f, 1.0f, 1.0f }) - .setAttachmentCount( 1 ) - .setPAttachments( mVulkanPipelineState->colorBlendAttachmentState.data() ); - - return &mVulkanPipelineState->colorBlend; -} - -const vk::PipelineDepthStencilStateCreateInfo* RenderCommand::PrepareDepthStencilStateCreateInfo() -{ - return &(mVulkanPipelineState->depthStencil - .setDepthBoundsTestEnable( false ) - .setStencilTestEnable( false )); -} - -const vk::PipelineInputAssemblyStateCreateInfo* RenderCommand::PrepareInputAssemblyStateCreateInfo() -{ - auto vkTopology = vk::PrimitiveTopology::eTriangleList; - if( mRenderState.topology == Topology::TRIANGLE_STRIP ) - { - vkTopology = vk::PrimitiveTopology::eTriangleStrip; - } - - //@todo support topology and restart - return &(mVulkanPipelineState->inputAssembly - .setPrimitiveRestartEnable( true ) - .setTopology( vkTopology )); -} - -const vk::PipelineMultisampleStateCreateInfo* RenderCommand::PrepareMultisampleStateCreateInfo() -{ - return &(mVulkanPipelineState->multisample - .setSampleShadingEnable( false ) - .setRasterizationSamples( vk::SampleCountFlagBits::e1) - .setAlphaToCoverageEnable( false ) - .setMinSampleShading( 1.0f ) - .setPSampleMask( nullptr )); -} - -const vk::PipelineRasterizationStateCreateInfo* RenderCommand::PrepareRasterizationStateCreateInfo() -{ - return &(mVulkanPipelineState->rasterization - .setCullMode( vk::CullModeFlagBits::eNone ) - .setDepthBiasClamp( 0.0f ) - .setDepthBiasEnable( false ) - .setDepthClampEnable( false ) - .setFrontFace( vk::FrontFace::eCounterClockwise ) - .setPolygonMode( vk::PolygonMode::eFill ) - .setRasterizerDiscardEnable( false ) - .setLineWidth( 1.0f )); -} - -const vk::PipelineTessellationStateCreateInfo* RenderCommand::PrepareTesselationStateCreateInfo() -{ - return nullptr; -} - -const vk::PipelineVertexInputStateCreateInfo* RenderCommand::PrepareVertexInputStateCreateInfo() -{ - /* - mBindingDesc.clear(); - mAttrDesc.clear(); - mVertexInputState = vk::PipelineVertexInputStateCreateInfo{}; - mVertexInputState.setPVertexAttributeDescriptions( (mAttrDesc = attrDesc).data() ); - mVertexInputState.setPVertexBindingDescriptions( (mBindingDesc = bindingDesc).data() ); - mVertexInputState.setVertexAttributeDescriptionCount( U32(mAttrDesc.size()) ); - mVertexInputState.setVertexBindingDescriptionCount( U32(mBindingDesc.size()) ); - mInfo.setPVertexInputState( &mVertexInputState ); - */ - return nullptr; -} - -const vk::PipelineViewportStateCreateInfo* RenderCommand::PrepareViewportStateCreateInfo() -{ - assert( !mPipeline && "Pipeline cannot be changed anymore!"); - - auto width = mGraphics.GetSwapchainForFBID(0)->GetCurrentFramebuffer()->GetWidth(); - auto height = mGraphics.GetSwapchainForFBID(0)->GetCurrentFramebuffer()->GetHeight(); - - // viewports - mVulkanPipelineState->viewport.viewports.emplace_back( 0, 0, width, height ); - mVulkanPipelineState->viewport.viewports[0].setMinDepth( 0.0f ); - mVulkanPipelineState->viewport.viewports[0].setMaxDepth( 1.0f ); - - // scissors - mVulkanPipelineState->viewport.scissors.emplace_back( vk::Rect2D( - { static_cast(0), static_cast(0) }, - { Vulkan::U32(width), Vulkan::U32(height) } ) - ); - - auto& viewState = mVulkanPipelineState->viewport; - - return &(mVulkanPipelineState->viewport.createInfo. - setViewportCount( Vulkan::U32(viewState.viewports.size()) ). - setPViewports( viewState.viewports.data() ). - setPScissors( viewState.scissors.data() ). - setScissorCount( Vulkan::U32(viewState.scissors.size())) ); -} - const Vulkan::RefCountedCommandBuffer& RenderCommand::GetCommandBuffer() const { return mCommandBuffer; } -const Vulkan::PipelineCache& RenderCommand::GetPipelineCache() const -{ - return mPipelineCache; -} - -const Vulkan::RefCountedPipeline& RenderCommand::GetPipeline() const -{ - return mPipeline; -} - void RenderCommand::AllocateUniformBufferMemory() { // release any existing buffers @@ -471,8 +150,13 @@ void RenderCommand::BindUniformBuffers() auto& ubo = mUboBuffers[i]; auto& pc = mPushConstantsBindings[i]; - DALI_LOG_STREAM( gVulkanFilter, Debug::General, "offset: " << ubo->GetBindingOffset() << ", size: " << ubo->GetBindingSize()); +#ifdef DEBUG_ENABLED + auto offset = ubo->GetBindingOffset(); + auto size = ubo->GetBindingSize(); + + DALI_LOG_STREAM( gVulkanFilter, Debug::General, "offset: " << offset << ", size: " << size); DALI_LOG_STREAM( gVulkanFilter, Debug::General, "[RenderCommand] BindingUBO: binding = " << pc.binding); +#endif mDescriptorSets[0]->WriteUniformBuffer( pc.binding, ubo->GetBuffer(), ubo->GetBindingOffset(), ubo->GetBindingSize() ); } } @@ -493,6 +177,10 @@ const std::vector& RenderCommand::GetDescriptor return mDescriptorSets; } +Vulkan::RefCountedPipeline RenderCommand::GetVulkanPipeline() const +{ + return mVulkanPipeline; +} } // namespace VulkanAPI } // namespace Graphics diff --git a/dali/graphics/vulkan/api/vulkan-api-render-command.h b/dali/graphics/vulkan/api/vulkan-api-render-command.h index 6799ff6..df824dd 100644 --- a/dali/graphics/vulkan/api/vulkan-api-render-command.h +++ b/dali/graphics/vulkan/api/vulkan-api-render-command.h @@ -35,6 +35,7 @@ namespace VulkanAPI { class Controller; class Ubo; +class Pipeline; /** * Render command stores internal command buffer per draw call @@ -56,8 +57,7 @@ public: constexpr static uint32_t UPDATE_ALL = 0xffffffff; RenderCommand( VulkanAPI::Controller& controller, - Vulkan::Graphics& graphics, - Vulkan::PipelineCache& pipelineCache ); + Vulkan::Graphics& graphics ); ~RenderCommand() override; @@ -66,7 +66,7 @@ public: * updates cache * @return */ - bool PreparePipeline(); + void PrepareResources(); /** * Updates uniform buffers @@ -84,6 +84,11 @@ public: void BindTexturesAndSamplers(); /** + * Binds vertex buffers + */ + void BindVertexBuffers(); + + /** * Returns an array of updated descriptor sets * @return */ @@ -96,37 +101,13 @@ public: const Vulkan::RefCountedCommandBuffer& GetCommandBuffer() const; /** - * Returns pipeline cache + * Returns Vulkan backed pipeline * @return */ - const Vulkan::PipelineCache& GetPipelineCache() const; - - /** - * Returns pipeline - * @return - */ - const Vulkan::RefCountedPipeline& GetPipeline() const; - - + Vulkan::RefCountedPipeline GetVulkanPipeline() const; private: - const vk::PipelineColorBlendStateCreateInfo* PrepareColorBlendStateCreateInfo(); - - const vk::PipelineDepthStencilStateCreateInfo* PrepareDepthStencilStateCreateInfo(); - - const vk::PipelineInputAssemblyStateCreateInfo* PrepareInputAssemblyStateCreateInfo(); - - const vk::PipelineMultisampleStateCreateInfo* PrepareMultisampleStateCreateInfo(); - - const vk::PipelineRasterizationStateCreateInfo* PrepareRasterizationStateCreateInfo(); - - const vk::PipelineTessellationStateCreateInfo* PrepareTesselationStateCreateInfo(); - - const vk::PipelineVertexInputStateCreateInfo* PrepareVertexInputStateCreateInfo(); - - const vk::PipelineViewportStateCreateInfo* PrepareViewportStateCreateInfo(); - /** * Allocates UBO memory based on the pipeline. Executed only * once per pipeline @@ -135,25 +116,17 @@ private: private: - /** - * Describes assigned UBO buffers - */ - - struct VulkanPipelineState; - std::unique_ptr mVulkanPipelineState; - - VulkanAPI::Controller& mController; - Vulkan::Graphics& mGraphics; - Vulkan::PipelineCache& mPipelineCache; + VulkanAPI::Controller& mController; + Vulkan::Graphics& mGraphics; Vulkan::RefCountedCommandBuffer mCommandBuffer; - Vulkan::RefCountedPipeline mPipeline; + Vulkan::RefCountedPipeline mVulkanPipeline; Vulkan::RefCountedDescriptorPool mDescriptorPool; - std::vector mVkDescriptorSetLayouts; + std::vector mVkDescriptorSetLayouts; std::vector mDescriptorSets; - std::vector> mUboBuffers; + std::vector> mUboBuffers; uint32_t mUpdateFlags; }; diff --git a/dali/graphics/vulkan/api/vulkan-api-shader.h b/dali/graphics/vulkan/api/vulkan-api-shader.h index 5be6e3a..8c1b54d 100644 --- a/dali/graphics/vulkan/api/vulkan-api-shader.h +++ b/dali/graphics/vulkan/api/vulkan-api-shader.h @@ -43,9 +43,9 @@ public: explicit Shader( Vulkan::Graphics& graphics ); - bool AddShaderModule( Graphics::API::ShaderDetails::PipelineStage pipelineStage, - Graphics::API::ShaderDetails::Language language, - Graphics::API::ShaderDetails::ShaderSource shaderSource ); + bool AddShaderModule( Dali::Graphics::API::ShaderDetails::PipelineStage pipelineStage, + Dali::Graphics::API::ShaderDetails::Language language, + Dali::Graphics::API::ShaderDetails::ShaderSource shaderSource ); Vulkan::RefCountedShader GetShader( vk::ShaderStageFlagBits shaderStage ) const ; diff --git a/dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-handle.cpp b/dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-handle.cpp index 81bd236..fb9e279 100644 --- a/dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-handle.cpp +++ b/dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-handle.cpp @@ -63,7 +63,7 @@ void GpuMemoryBlock::Unmap() void GpuMemoryBlock::Flush() { - NotImplemented(); + } } diff --git a/dali/graphics/vulkan/vulkan-graphics.cpp b/dali/graphics/vulkan/vulkan-graphics.cpp index 5419d3d..52e1ec1 100644 --- a/dali/graphics/vulkan/vulkan-graphics.cpp +++ b/dali/graphics/vulkan/vulkan-graphics.cpp @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -67,7 +66,7 @@ namespace Vulkan const auto VALIDATION_LAYERS = std::vector< const char* >{ //"VK_LAYER_LUNARG_screenshot", // screenshot - "VK_LAYER_RENDERDOC_Capture", + //"VK_LAYER_RENDERDOC_Capture", "VK_LAYER_LUNARG_parameter_validation", // parameter //"VK_LAYER_LUNARG_vktrace", // vktrace ( requires vktrace connection ) //"VK_LAYER_LUNARG_monitor", // monitor @@ -77,7 +76,6 @@ const auto VALIDATION_LAYERS = std::vector< const char* >{ "VK_LAYER_LUNARG_object_tracker", // objects "VK_LAYER_LUNARG_core_validation", // core "VK_LAYER_GOOGLE_unique_objects", // unique objects - "VK_LAYER_GOOGLE_unique_objects", // unique objects "VK_LAYER_LUNARG_standard_validation", // standard }; @@ -97,7 +95,6 @@ Graphics::~Graphics() // communicates ownership more clearly (e.g by not allowing copies). mGfxController.reset(nullptr); mSurfaceFBIDMap.clear(); - mPipelineDatabase.reset(nullptr); #ifndef NDEBUG printf("DESTROYING GRAPHICS CONTEXT--------------------------------\n"); @@ -207,7 +204,6 @@ void Graphics::CreateDevice() } } - mPipelineDatabase = std::make_unique< PipelineCache >( *this ); mResourceCache = MakeUnique< ResourceCache >(); } @@ -648,15 +644,11 @@ Dali::Graphics::API::Controller& Graphics::GetController() return *mGfxController; } -PipelineCache& Graphics::GetPipelineCache() -{ - return *mPipelineDatabase; -} - bool Graphics::IsShuttingDown() { return mShuttingDown; } + // -------------------------------------------------------------------------------------------------------------- // Cache manipulation methods ----------------------------------------------------------------------------------- @@ -794,10 +786,12 @@ Graphics::CreateInstance( const std::vector< const char* >& extensions, .setPpEnabledLayerNames(validationLayers.data()); #if defined(DEBUG_ENABLED) -// if( ! getenv("LOG_VULKAN") ) -// { -// info.setEnabledLayerCount(0); -// } + if( ! getenv("LOG_VULKAN") ) + { + info.setEnabledLayerCount(0); + } +#else + //info.setEnabledLayerCount(0); #endif mInstance = VkAssert(vk::createInstance(info, *mAllocator)); diff --git a/dali/graphics/vulkan/vulkan-graphics.h b/dali/graphics/vulkan/vulkan-graphics.h index 506c4be..699e7f5 100644 --- a/dali/graphics/vulkan/vulkan-graphics.h +++ b/dali/graphics/vulkan/vulkan-graphics.h @@ -2,7 +2,7 @@ #define DALI_GRAPHICS_VULKAN_GRAPHICS /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2018 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,14 +23,16 @@ #endif // INTERNAL INCLUDES -#include #include +#include +#include #include + #include #include #include #include -#include + namespace Dali { @@ -40,7 +42,6 @@ namespace API { class Controller; } - namespace VulkanAPI { class Controller; @@ -66,9 +67,6 @@ class CommandPool; class DescriptorPool; class GpuMemoryManager; - -class PipelineCache; - class ResourceCache; using SurfaceFactory = Dali::Integration::Graphics::SurfaceFactory; @@ -186,8 +184,6 @@ public: // Getters Dali::Graphics::API::Controller& GetController(); - PipelineCache& GetPipelineCache(); - bool IsShuttingDown(); public: //Cache management methods @@ -287,9 +283,6 @@ private: // Members Platform mPlatform{ Platform::UNDEFINED }; - // TODO: rename - std::unique_ptr< PipelineCache > mPipelineDatabase; - std::mutex mMutex; std::unique_ptr< Dali::Graphics::VulkanAPI::Controller > mGfxController; diff --git a/dali/graphics/vulkan/vulkan-pipeline-cache.cpp b/dali/graphics/vulkan/vulkan-pipeline-cache.cpp deleted file mode 100644 index c6855ce..0000000 --- a/dali/graphics/vulkan/vulkan-pipeline-cache.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -// INTERNAL INCLUDES -#include -#include -#include -#include - -namespace Dali -{ -namespace Graphics -{ -namespace Vulkan -{ - -struct PipelineCache::Impl -{ - struct PipelineCacheItem - { - - PipelineCacheItem( RefCountedPipeline _pipeline, const PipelineDescription& _description ) - : pipeline(_pipeline), description(_description) - { - - } - RefCountedPipeline pipeline; - PipelineDescription description; - }; - - Impl( PipelineCache& pipelineCache, Graphics& graphics ) - : mPipelineCache( pipelineCache ), - mGraphics( graphics ) - { - - } - - - /** - * Finds suitable cached pipeline based on pipelineInfo - * @param pipelineInfo - * @return - */ - RefCountedPipeline GetPipeline( const PipelineDescription& description ) - { - for( auto&& item : mPipelines ) - { - if( item.description == description ) - { - return item.pipeline; - } - } - return RefCountedPipeline(); - } - - - bool AddPipeline( RefCountedPipeline pipeline, const PipelineDescription& description ) - { - mPipelines.emplace_back( pipeline, description ); - return true; - } - - std::vector GetDescriptorSetLayouts( const RefCountedPipeline& pipeline ) const - { - auto retval = std::vector{}; - for( auto&& item : mPipelines ) - { - if( item.pipeline == pipeline ) - { - return item.description.descriptorSetLayouts; - } - } - return retval; - } - - ~Impl() = default; - - PipelineCache& mPipelineCache; - Graphics& mGraphics; - - std::vector mPipelines; -}; - -PipelineCache::PipelineCache( Graphics& graphics ) -{ - mImpl = std::make_unique( *this, graphics ); -} - -PipelineCache::~PipelineCache() = default; - -RefCountedPipeline PipelineCache::GetPipeline( const PipelineDescription& desc ) const -{ - return mImpl->GetPipeline( desc ); -} - -bool PipelineCache::AddPipeline( RefCountedPipeline pipeline, const PipelineDescription& desc ) -{ - return mImpl->AddPipeline( pipeline,desc ); -} - -std::vector PipelineCache::GetDescriptorSetLayouts( const RefCountedPipeline& pipeline ) const -{ - return mImpl->GetDescriptorSetLayouts( pipeline ); -} - -} // namespace Vulkan -} // namespace Graphics -} // namespace Dali - diff --git a/dali/graphics/vulkan/vulkan-pipeline-cache.h b/dali/graphics/vulkan/vulkan-pipeline-cache.h deleted file mode 100644 index 3209dcd..0000000 --- a/dali/graphics/vulkan/vulkan-pipeline-cache.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef DALI_GRAPHICS_VULKAN_PIPELINE_CACHE_H -#define DALI_GRAPHICS_VULKAN_PIPELINE_CACHE_H - -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -// INTERNAL INCLUDES -#include -#include -namespace Dali -{ -namespace Graphics -{ -namespace Vulkan -{ -class Graphics; - -struct PipelineDescription -{ - RefCountedShader vertexShader; - RefCountedShader fragmentShader; - - API::RenderCommand::RenderState::BlendState blendState; - - bool operator==(const PipelineDescription& description) const - { - return (vertexShader == description.vertexShader) && - (fragmentShader == description.fragmentShader) && - (std::memcmp( &blendState, &description.blendState, sizeof(blendState) )); - } - - std::vector descriptorSetLayouts; -}; - -class PipelineCache -{ -public: - PipelineCache() = default; - - PipelineCache( Graphics& graphics ); - - ~PipelineCache(); - - RefCountedPipeline GetPipeline( const PipelineDescription& desc ) const; - - bool AddPipeline( RefCountedPipeline pipeline, const PipelineDescription& desc ); - - std::vector GetDescriptorSetLayouts( const RefCountedPipeline& pipeline ) const; - -private: - struct Impl; - std::unique_ptr mImpl; -}; -} // namespace Vulkan -} // namespace Graphics -} // namespace Dali -#endif // DALI_GRAPHICS_VULKAN_PIPELINE_CACHE_H diff --git a/dali/graphics/vulkan/vulkan-swapchain.cpp b/dali/graphics/vulkan/vulkan-swapchain.cpp index 484155c..0d9599c 100644 --- a/dali/graphics/vulkan/vulkan-swapchain.cpp +++ b/dali/graphics/vulkan/vulkan-swapchain.cpp @@ -199,7 +199,7 @@ struct Swapchain::Impl .setImage( vkImage ) .setSubresourceRange( range ) .setSrcAccessMask( vk::AccessFlags{} ) - .setDstAccessMask( vk::AccessFlagBits::eColorAttachmentWrite ) + .setDstAccessMask( vk::AccessFlags{} ) .setOldLayout( vk::ImageLayout::eUndefined ) .setNewLayout( vk::ImageLayout::eColorAttachmentOptimal ); @@ -225,7 +225,7 @@ struct Swapchain::Impl .setImage( vkImage ) .setSubresourceRange( range ) .setSrcAccessMask( vk::AccessFlags{} ) - .setDstAccessMask( vk::AccessFlagBits::eDepthStencilAttachmentWrite ) + .setDstAccessMask( vk::AccessFlags{} )//vk::AccessFlagBits::eDepthStencilAttachmentWrite ) .setOldLayout( vk::ImageLayout::eUndefined ) .setNewLayout( vk::ImageLayout::eDepthStencilAttachmentOptimal ); barriers.emplace_back( depthStencilBarrier ); @@ -485,8 +485,9 @@ struct Swapchain::Impl std::vector barriers; vk::ImageMemoryBarrier barrier; - barrier.setSrcAccessMask( vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eColorAttachmentRead ) - .setDstAccessMask( vk::AccessFlagBits::eColorAttachmentWrite ) + barrier + .setSrcAccessMask( vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eColorAttachmentRead ) + .setDstAccessMask( vk::AccessFlagBits::eShaderWrite ) .setOldLayout( vk::ImageLayout::ePresentSrcKHR ) .setNewLayout( vk::ImageLayout::eColorAttachmentOptimal ) .setSubresourceRange( vk::ImageSubresourceRange{}.setAspectMask( vk::ImageAspectFlagBits::eColor ).setBaseArrayLayer(0) @@ -499,8 +500,8 @@ struct Swapchain::Impl barriers.emplace_back( barrier.setImage( imageView->GetImage()->GetVkHandle() ) ); } - cmdBuf->PipelineBarrier( vk::PipelineStageFlagBits::eBottomOfPipe, - vk::PipelineStageFlagBits::eColorAttachmentOutput, + cmdBuf->PipelineBarrier( vk::PipelineStageFlagBits::eColorAttachmentOutput, + vk::PipelineStageFlagBits::eFragmentShader, vk::DependencyFlags{}, std::vector{}, std::vector{}, diff --git a/dali/internal/update/graphics/graphics-algorithms.cpp b/dali/internal/update/graphics/graphics-algorithms.cpp index a397b83..4b814f3 100644 --- a/dali/internal/update/graphics/graphics-algorithms.cpp +++ b/dali/internal/update/graphics/graphics-algorithms.cpp @@ -112,11 +112,17 @@ void SubmitRenderItemList( Graphics::API::Controller& graphics, Matrix::Multiply(mvp2, mvp, CLIP_MATRIX); sgRenderer->WriteUniform("uModelMatrix", item.mModelMatrix); sgRenderer->WriteUniform("uMvpMatrix", mvp2); + sgRenderer->WriteUniform("uViewMatrix", *viewMatrix); - sgRenderer->WriteUniform("uModelViewMatrix", item.mModelViewMatrix); + sgRenderer->WriteUniform("uModelView", item.mModelViewMatrix); + + + + // sgRenderer->WriteUniform("uNormalMatrix", normal); + sgRenderer->WriteUniform("uProjection", vulkanProjectionMatrix); sgRenderer->WriteUniform("uSize", item.mSize); - sgRenderer->WriteUniform( "uColor", color ); + sgRenderer->WriteUniform("uColor", color ); commandList.push_back(&cmd); } diff --git a/dali/internal/update/rendering/scene-graph-renderer.cpp b/dali/internal/update/rendering/scene-graph-renderer.cpp index a9787a5..6da52cc 100644 --- a/dali/internal/update/rendering/scene-graph-renderer.cpp +++ b/dali/internal/update/rendering/scene-graph-renderer.cpp @@ -38,6 +38,8 @@ #include #include #include +#include + #include namespace // unnamed namespace @@ -159,13 +161,6 @@ void Renderer::Initialize( Integration::Graphics::Graphics& graphics ) mRegenerateUniformMap = REGENERATE_UNIFORM_MAP; } - -void* AllocateUniformBufferMemory( size_t size ) -{ - return nullptr; -} - - void Renderer::UpdateUniformMap( BufferIndex updateBufferIndex, Node& node ) { // Called every frame. @@ -210,6 +205,8 @@ void Renderer::UpdateUniformMap( BufferIndex updateBufferIndex, Node& node ) void Renderer::PrepareRender( BufferIndex updateBufferIndex ) { + using namespace Dali::Graphics::API; + auto &controller = mGraphics->GetController(); // prepare all stuff @@ -226,40 +223,47 @@ void Renderer::PrepareRender( BufferIndex updateBufferIndex ) return; } + using Graphics::API::Pipeline; + + // vertex input state + VertexInputState vi{}; /** * Prepare vertex attribute buffer bindings */ uint32_t bindingIndex{0u}; - uint32_t locationIndex{0u}; - auto vertexAttributeBindings = Graphics::API::RenderCommand::NewVertexAttributeBufferBindings(); - for (auto &&vertexBuffer : mGeometry->GetVertexBuffers()) + std::vector> vertexBuffers{}; + + for(auto&& vertexBuffer : mGeometry->GetVertexBuffers()) { + vertexBuffers.push_back( vertexBuffer->GetGfxObject() ); auto attributeCountInForBuffer = vertexBuffer->GetAttributeCount(); // update vertex buffer if necessary vertexBuffer->Update(controller); + // store buffer binding + vi.bufferBindings + .emplace_back( vertexBuffer->GetFormat()->size, VertexInputRate::PER_VERTEX); + for (auto i = 0u; i < attributeCountInForBuffer; ++i) { - // create binding per attribute - auto binding = Graphics::API::RenderCommand::VertexAttributeBufferBinding{} - .SetOffset((vertexBuffer->GetFormat()->components[i]).offset) - .SetBinding(bindingIndex) - .SetBuffer(vertexBuffer->GetGfxObject()) - .SetInputAttributeRate(Graphics::API::RenderCommand::InputAttributeRate::PER_VERTEX) - .SetLocation(locationIndex + i) - .SetStride(vertexBuffer->GetFormat()->size); - - vertexAttributeBindings.emplace_back(binding); + // create attribute description + vi.attributes + .emplace_back( + gfxShader.Get().GetVertexAttributeLocation( vertexBuffer->GetAttributeName( i ) ), + bindingIndex, (vertexBuffer->GetFormat()->components[i]).offset, + VertexInputFormat::UNDEFINED); + } - locationIndex += attributeCountInForBuffer; + bindingIndex++; } + // Invalid input attributes! if (mShader->GetGfxObject() .Get() .GetVertexAttributeLocations() - .size() != vertexAttributeBindings.size()) + .size() != vi.attributes.size()) return; auto &shader = mShader->GetGfxObject().Get(); @@ -414,38 +418,85 @@ void Renderer::PrepareRender( BufferIndex updateBufferIndex ) // set optional index buffer bool usesIndexBuffer{false}; - auto topology = Graphics::API::RenderCommand::Topology::TRIANGLE_STRIP; - if ((usesIndexBuffer = mGeometry->HasIndexBuffer())) - { - mGfxRenderCommand->BindIndexBuffer(Graphics::API::RenderCommand::IndexBufferBinding() - .SetBuffer(mGeometry->GetIndexBuffer()) - .SetOffset(0) - ); - } - - auto type = mGeometry->GetType(); - - switch (type) + auto topology = PrimitiveTopology::TRIANGLE_STRIP; + auto geometryTopology = mGeometry->GetType(); + switch (geometryTopology) { case Dali::Geometry::Type::TRIANGLE_STRIP: { - topology = Graphics::API::RenderCommand::Topology::TRIANGLE_STRIP; + topology = PrimitiveTopology::TRIANGLE_STRIP; break; } default: { - topology = Graphics::API::RenderCommand::Topology::TRIANGLES; + topology = PrimitiveTopology::TRIANGLE_LIST; } } + if ((usesIndexBuffer = mGeometry->HasIndexBuffer())) + { + mGfxRenderCommand->BindIndexBuffer(Graphics::API::RenderCommand::IndexBufferBinding() + .SetBuffer(mGeometry->GetIndexBuffer()) + .SetOffset(0) + ); + } + + mGfxRenderCommand->PushConstants( std::move(pushConstantsBindings) ); - mGfxRenderCommand->BindVertexBuffers( std::move(vertexAttributeBindings) ); + mGfxRenderCommand->BindVertexBuffers( std::move( vertexBuffers ) ); mGfxRenderCommand->BindTextures( std::move(textureBindings) ); - mGfxRenderCommand->BindRenderState( Graphics::API::RenderCommand::RenderState{} - .SetShader( mShader->GetGfxObject() ) - .SetBlendState( { mBlendMode != BlendMode::OFF }) - .SetTopology( topology )); + // create pipeline + if(!mGfxPipeline) + { + mGfxPipeline = controller.CreatePipeline(controller.GetPipelineFactory() + + // vertex input + .SetVertexInputState( vi ) + + // shaders + .SetShaderState( ShaderState() + .SetShaderProgram( shader )) + + // input assembly + .SetInputAssemblyState( InputAssemblyState() + .SetTopology( topology ) + .SetPrimitiveRestartEnable( true )) + + // viewport ( if zeroes then framebuffer size used ) + .SetViewportState( ViewportState() + .SetViewport( { 0.0, 0.0, 0.0, 0.0, 0.0, 1.0 } )) + + // depth stencil + .SetDepthStencilState( DepthStencilState() + .SetDepthTestEnable( + mDepthTestMode != DepthTestMode::ON ? false : true + ) + .SetDepthWriteEnable( true ) + .SetDepthCompareOp( CompareOp::GREATER_OR_EQUAL )) + + + // color blend + .SetColorBlendState( ColorBlendState() + .SetBlendEnable( mBlendMode != BlendMode::OFF ? true : false ) + .SetColorComponentsWriteBits( 0xff ) + .SetSrcColorBlendFactor( Graphics::API::BlendFactor::SRC_ALPHA ) + .SetDstColorBlendFactor( Graphics::API::BlendFactor::ONE_MINUS_SRC_ALPHA ) + .SetSrcAlphaBlendFactor( Graphics::API::BlendFactor::ONE ) + .SetDstAlphaBlendFactor( Graphics::API::BlendFactor::ONE_MINUS_SRC_ALPHA ) + .SetColorBlendOp( BlendOp::ADD ) + .SetAlphaBlendOp( BlendOp::ADD ) + .SetLogicOpEnable( false )) + + // rasterization + .SetRasterizationState( RasterizationState() + .SetCullMode( CullMode::NONE ) + .SetPolygonMode( PolygonMode::FILL ) + .SetFrontFace( FrontFace::CLOCKWISE ))); + } + + // bind pipeline + mGfxRenderCommand->BindPipeline( *mGfxPipeline.get() ); if(usesIndexBuffer) { mGfxRenderCommand->Draw(std::move(Graphics::API::RenderCommand::DrawCommand{} diff --git a/dali/internal/update/rendering/scene-graph-renderer.h b/dali/internal/update/rendering/scene-graph-renderer.h index e1f1010..e80d6ab 100644 --- a/dali/internal/update/rendering/scene-graph-renderer.h +++ b/dali/internal/update/rendering/scene-graph-renderer.h @@ -30,6 +30,7 @@ #include #include #include +#include #include namespace Dali @@ -462,7 +463,7 @@ private: std::vector> mUboMemory; ///< Transient memory allocated for each UBO std::unique_ptr mGfxRenderCommand; - + std::unique_ptr mGfxPipeline; public: AnimatableProperty< float > mOpacity; ///< The opacity value int mDepthIndex; ///< Used only in PrepareRenderInstructions -- 2.7.4