Vulkan pipeline 07/317007/10
authorAdam Bialogonski <adam.b@samsung.com>
Mon, 2 Sep 2024 09:59:13 +0000 (10:59 +0100)
committerAdam Bialogonski <adam.b@samsung.com>
Fri, 6 Sep 2024 12:16:30 +0000 (13:16 +0100)
Base implementation. All states are added but there are TODOs:
- Setting compatible renderpass (via command buffer)
- Setting relevant dynamic states (not sure yet which ones we'll use)
- MSAA state is set default, may not work for rendering
- BlendColor supports only single attachments due to DALi gfx api limitation (we support single state, too)
- No caching in use but the code making a copy of create states is still there.

Change-Id: Ide0ef9f6d3fd0ea81fe2646507c65d7eda4d3753

12 files changed:
dali/internal/graphics/file.list
dali/internal/graphics/vulkan-impl/vulkan-graphics-controller.cpp
dali/internal/graphics/vulkan-impl/vulkan-graphics-controller.h
dali/internal/graphics/vulkan-impl/vulkan-pipeline-impl.cpp [new file with mode: 0644]
dali/internal/graphics/vulkan-impl/vulkan-pipeline-impl.h [new file with mode: 0644]
dali/internal/graphics/vulkan-impl/vulkan-pipeline.cpp [new file with mode: 0644]
dali/internal/graphics/vulkan-impl/vulkan-pipeline.h [new file with mode: 0644]
dali/internal/graphics/vulkan-impl/vulkan-program-impl.cpp
dali/internal/graphics/vulkan-impl/vulkan-program-impl.h
dali/internal/graphics/vulkan-impl/vulkan-reflection.cpp
dali/internal/graphics/vulkan-impl/vulkan-reflection.h
dali/internal/graphics/vulkan-impl/vulkan-spirv.cpp

index 198a56cbd594df14e7256f949110f3b337c13317..9fb43733e7c29f7f74b2bf33045e99199164578a 100644 (file)
@@ -32,6 +32,8 @@ SET( adaptor_graphics_vulkan_src_files
     ${adaptor_graphics_dir}/vulkan-impl/vulkan-image-view-impl.cpp
     ${adaptor_graphics_dir}/vulkan-impl/vulkan-memory.cpp
     ${adaptor_graphics_dir}/vulkan-impl/vulkan-memory-impl.cpp
+    ${adaptor_graphics_dir}/vulkan-impl/vulkan-pipeline.cpp
+    ${adaptor_graphics_dir}/vulkan-impl/vulkan-pipeline-impl.cpp
     ${adaptor_graphics_dir}/vulkan-impl/vulkan-program.cpp
     ${adaptor_graphics_dir}/vulkan-impl/vulkan-program-impl.cpp
     ${adaptor_graphics_dir}/vulkan-impl/vulkan-queue-impl.cpp
index 07d21338ce84e566ef86d487836e6a4d460a7afa..b04cbd58572dd6e6cd2a5a208e5c74105208aeca 100644 (file)
@@ -30,6 +30,7 @@
 #include <dali/internal/graphics/vulkan-impl/vulkan-framebuffer-impl.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-image-impl.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-memory.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-pipeline.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-program.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-render-pass.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-render-target.h>
@@ -191,8 +192,7 @@ struct VulkanGraphicsController::Impl
     if(!mTextureStagingBuffer ||
        mTextureStagingBuffer->GetImpl()->GetSize() < size)
     {
-      auto workerFunc = [&, size](auto workerIndex)
-      {
+      auto workerFunc = [&, size](auto workerIndex) {
         Graphics::BufferCreateInfo createInfo{};
         createInfo.SetSize(size)
           .SetUsage(0u | Dali::Graphics::BufferUsage::TRANSFER_SRC);
@@ -282,8 +282,7 @@ struct VulkanGraphicsController::Impl
         }
         assert(image);
 
-        auto predicate = [&](auto& item) -> bool
-        {
+        auto predicate = [&](auto& item) -> bool {
           return image->GetVkHandle() == item.image.GetVkHandle();
         };
         auto it = std::find_if(requestMap.begin(), requestMap.end(), predicate);
@@ -598,8 +597,7 @@ void VulkanGraphicsController::UpdateTextures(
 
         if(destTexture->GetProperties().directWriteAccessEnabled)
         {
-          auto taskLambda = [pInfo, sourcePtr, sourceInfoPtr, texture](auto workerIndex)
-          {
+          auto taskLambda = [pInfo, sourcePtr, sourceInfoPtr, texture](auto workerIndex) {
             const auto& properties = texture->GetProperties();
 
             if(properties.emulated)
@@ -634,8 +632,7 @@ void VulkanGraphicsController::UpdateTextures(
           // The staging buffer is not allocated yet. The task knows pointer to the pointer which will point
           // at staging buffer right before executing tasks. The function will either perform direct copy
           // or will do suitable conversion if source format isn't supported and emulation is available.
-          auto taskLambda = [ppStagingMemory, currentOffset, pInfo, sourcePtr, texture](auto workerThread)
-          {
+          auto taskLambda = [ppStagingMemory, currentOffset, pInfo, sourcePtr, texture](auto workerThread) {
             char* pStagingMemory = reinterpret_cast<char*>(*ppStagingMemory);
 
             // Try to initialise` texture resources explicitly if they are not yet initialised
@@ -673,8 +670,7 @@ void VulkanGraphicsController::UpdateTextures(
   for(auto& item : updateMap)
   {
     auto pUpdates = &item.second;
-    auto task     = [pUpdates](auto workerIndex)
-    {
+    auto task     = [pUpdates](auto workerIndex) {
       for(auto& update : *pUpdates)
       {
         update.copyTask(workerIndex);
@@ -842,7 +838,7 @@ UniquePtr<Graphics::Framebuffer> VulkanGraphicsController::CreateFramebuffer(con
 
 UniquePtr<Graphics::Pipeline> VulkanGraphicsController::CreatePipeline(const Graphics::PipelineCreateInfo& pipelineCreateInfo, UniquePtr<Graphics::Pipeline>&& oldPipeline)
 {
-  return UniquePtr<Graphics::Pipeline>{};
+  return UniquePtr<Graphics::Pipeline>(new Vulkan::Pipeline(pipelineCreateInfo, *this, nullptr));
 }
 
 UniquePtr<Graphics::Program> VulkanGraphicsController::CreateProgram(const Graphics::ProgramCreateInfo& programCreateInfo, UniquePtr<Graphics::Program>&& oldProgram)
@@ -914,7 +910,7 @@ TextureProperties VulkanGraphicsController::GetTextureProperties(const Graphics:
 
 const Graphics::Reflection& VulkanGraphicsController::GetProgramReflection(const Graphics::Program& program)
 {
-  return *(reinterpret_cast<Graphics::Reflection*>(0));
+  return (static_cast<const Vulkan::Program*>(&program))->GetReflection();
 }
 
 bool VulkanGraphicsController::PipelineEquals(const Graphics::Pipeline& pipeline0, const Graphics::Pipeline& pipeline1) const
@@ -1007,6 +1003,11 @@ void VulkanGraphicsController::DiscardResource(Vulkan::Buffer* buffer)
   // @todo Add discard queues
 }
 
+void VulkanGraphicsController::DiscardResource(Vulkan::Pipeline* buffer)
+{
+  // @todo Add discard queues
+}
+
 void VulkanGraphicsController::DiscardResource(Vulkan::Program* program)
 {
   // @todo Add discard queues
index bcdcd572d21b8aa2d866dce842d065186072b65f..2c76e20b0240d9baacfbcbbb033ff320409dd34d 100644 (file)
@@ -368,6 +368,7 @@ public:
   void Add(Vulkan::RenderTarget* renderTarget);
   void DiscardResource(Vulkan::RenderTarget* renderTarget);
   void DiscardResource(Vulkan::Buffer* buffer);
+  void DiscardResource(Vulkan::Pipeline* buffer);
   void DiscardResource(Vulkan::Program* renderProgram);
   void DiscardResource(Vulkan::Sampler* sampler);
   void DiscardResource(Vulkan::Texture* texture);
diff --git a/dali/internal/graphics/vulkan-impl/vulkan-pipeline-impl.cpp b/dali/internal/graphics/vulkan-impl/vulkan-pipeline-impl.cpp
new file mode 100644 (file)
index 0000000..1e10809
--- /dev/null
@@ -0,0 +1,783 @@
+/*
+ * Copyright (c) 2024 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/graphics/vulkan-impl/vulkan-pipeline-impl.h>
+
+// EXTERNAL INCLUDES
+#include <memory>
+#include <vulkan/vulkan.hpp>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/vulkan-impl/vulkan-graphics-controller.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-program-impl.h>
+#include <dali/internal/graphics/vulkan/vulkan-device.h>
+
+namespace Dali::Graphics::Vulkan
+{
+namespace
+{
+constexpr vk::CompareOp ConvCompareOp(const CompareOp in)
+{
+  switch(in)
+  {
+    case CompareOp::NEVER:
+    {
+      return vk::CompareOp::eNever;
+    }
+    case CompareOp::LESS:
+    {
+      return vk::CompareOp::eLess;
+    }
+    case CompareOp::EQUAL:
+    {
+      return vk::CompareOp::eEqual;
+    }
+    case CompareOp::LESS_OR_EQUAL:
+    {
+      return vk::CompareOp::eLessOrEqual;
+    }
+    case CompareOp::GREATER:
+    {
+      return vk::CompareOp::eGreater;
+    }
+    case CompareOp::NOT_EQUAL:
+    {
+      return vk::CompareOp::eNotEqual;
+    }
+    case CompareOp::GREATER_OR_EQUAL:
+    {
+      return vk::CompareOp::eGreaterOrEqual;
+    }
+    case CompareOp::ALWAYS:
+    {
+      return vk::CompareOp::eAlways;
+    }
+  }
+  return vk::CompareOp{};
+};
+
+constexpr vk::StencilOp ConvStencilOp(const StencilOp in)
+{
+  switch(in)
+  {
+    case StencilOp::DECREMENT_AND_CLAMP:
+    {
+      return vk::StencilOp::eDecrementAndClamp;
+    }
+    case StencilOp::DECREMENT_AND_WRAP:
+    {
+      return vk::StencilOp::eDecrementAndWrap;
+    }
+    case StencilOp::INCREMENT_AND_CLAMP:
+    {
+      return vk::StencilOp::eIncrementAndClamp;
+    }
+    case StencilOp::INCREMENT_AND_WRAP:
+    {
+      return vk::StencilOp::eIncrementAndWrap;
+    }
+    case StencilOp::INVERT:
+    {
+      return vk::StencilOp::eInvert;
+    }
+    case StencilOp::KEEP:
+    {
+      return vk::StencilOp::eKeep;
+    }
+    case StencilOp::REPLACE:
+    {
+      return vk::StencilOp::eReplace;
+    }
+    case StencilOp::ZERO:
+    {
+      return vk::StencilOp::eZero;
+    }
+  }
+  return vk::StencilOp{};
+};
+
+constexpr vk::StencilOpState ConvStencilOpState(const StencilOpState& in)
+{
+  vk::StencilOpState out;
+  out.compareOp   = ConvCompareOp(in.compareOp);
+  out.depthFailOp = ConvStencilOp(in.depthFailOp);
+  out.compareMask = in.compareMask;
+  out.failOp      = ConvStencilOp(in.failOp);
+  out.passOp      = ConvStencilOp(in.passOp);
+  out.reference   = in.reference;
+  out.writeMask   = in.writeMask;
+  return out;
+};
+} // namespace
+
+/**
+ * Copy of pipeline state, can be also used for internal caching
+ */
+struct PipelineImpl::PipelineState
+{
+  PipelineState()  = default;
+  ~PipelineState() = default;
+
+  // for maintaining correct lifecycle, the owned program
+  // wrapper must be created
+  UniquePtr<Program> program;
+
+  ColorBlendState    colorBlendState;
+  DepthStencilState  depthStencilState;
+  ProgramState       programState;
+  ViewportState      viewportState;
+  RasterizationState rasterizationState;
+  VertexInputState   vertexInputState;
+  InputAssemblyState inputAssemblyState;
+
+  PipelineCache* pipelineCache{};
+};
+
+PipelineImpl::PipelineImpl(const Graphics::PipelineCreateInfo& createInfo, VulkanGraphicsController& controller, PipelineCache* pipelineCache)
+: mController(controller)
+{
+  // the creation is deferred so it's needed to copy certain parts of the CreateInfo structure
+  mPipelineState = std::make_unique<PipelineImpl::PipelineState>();
+
+  // Make copies of structured pass by pointers and replace
+  // stored create info structure fields
+  CopyStateIfSet(createInfo.inputAssemblyState, mPipelineState->inputAssemblyState, &mCreateInfo.inputAssemblyState);
+  CopyStateIfSet(createInfo.vertexInputState, mPipelineState->vertexInputState, &mCreateInfo.vertexInputState);
+  CopyStateIfSet(createInfo.rasterizationState, mPipelineState->rasterizationState, &mCreateInfo.rasterizationState);
+  CopyStateIfSet(createInfo.programState, mPipelineState->programState, &mCreateInfo.programState);
+  CopyStateIfSet(createInfo.colorBlendState, mPipelineState->colorBlendState, &mCreateInfo.colorBlendState);
+  CopyStateIfSet(createInfo.depthStencilState, mPipelineState->depthStencilState, &mCreateInfo.depthStencilState);
+  CopyStateIfSet(createInfo.viewportState, mPipelineState->viewportState, &mCreateInfo.viewportState);
+
+  InitializePipeline();
+}
+
+const PipelineCreateInfo& PipelineImpl::GetCreateInfo() const
+{
+  return mCreateInfo;
+}
+
+VulkanGraphicsController& PipelineImpl::GetController() const
+{
+  return mController;
+}
+
+void PipelineImpl::Bind()
+{
+}
+
+void PipelineImpl::Retain()
+{
+  //++mRefCount;
+}
+
+void PipelineImpl::Release()
+{
+  //--mRefCount;
+}
+
+uint32_t PipelineImpl::GetRefCount() const
+{
+  return 0; //mRefCount;
+}
+
+PipelineImpl::~PipelineImpl() = default;
+
+void PipelineImpl::InitializePipeline()
+{
+  auto                           vkDevice    = mController.GetGraphicsDevice().GetLogicalDevice();
+  auto                           programImpl = static_cast<const Vulkan::Program*>(mCreateInfo.programState->program)->GetImplementation();
+  auto&                          reflection  = programImpl->GetReflection();
+  vk::GraphicsPipelineCreateInfo gfxPipelineInfo;
+  gfxPipelineInfo.setLayout(reflection.GetVkPipelineLayout());
+  gfxPipelineInfo.setStageCount(programImpl->GetVkPipelineShaderStageCreateInfoList().size());
+  gfxPipelineInfo.setStages(programImpl->GetVkPipelineShaderStageCreateInfoList());
+  gfxPipelineInfo.setBasePipelineHandle(nullptr);
+  gfxPipelineInfo.setBasePipelineIndex(0);
+
+  // TODO: to resolve
+  gfxPipelineInfo.setRenderPass({});
+  gfxPipelineInfo.setSubpass({});
+
+  // 1. PipelineVertexInputStateCreateInfo
+  vk::PipelineVertexInputStateCreateInfo visInfo;
+  InitializeVertexInputState(visInfo);
+  gfxPipelineInfo.setPVertexInputState(&visInfo);
+
+  // 2. PipelineInputAssemblyStateCreateInfo
+  vk::PipelineInputAssemblyStateCreateInfo iasInfo;
+  InitializeInputAssemblyState(iasInfo);
+  gfxPipelineInfo.setPInputAssemblyState(&iasInfo);
+
+  // 3. PipelineTessellationStateCreateInfo - We don't support this one
+  gfxPipelineInfo.setPTessellationState(nullptr);
+
+  // 4. PipelineViewportStateCreateInfo
+  vk::PipelineViewportStateCreateInfo viewInfo;
+  InitializeViewportState(viewInfo);
+  gfxPipelineInfo.setPViewportState(&viewInfo);
+
+  // 5. PipelineRasterizationStateCreateInfo
+  vk::PipelineRasterizationStateCreateInfo rsInfo;
+  InitializeRasterizationState(rsInfo);
+  gfxPipelineInfo.setPRasterizationState(&rsInfo);
+
+  // 6. PipelineMultisampleStateCreateInfo
+  vk::PipelineMultisampleStateCreateInfo msInfo;
+
+  gfxPipelineInfo.setPMultisampleState(&msInfo);
+
+  // 7. PipelineDepthStencilStateCreateInfo
+  vk::PipelineDepthStencilStateCreateInfo dsInfo;
+  gfxPipelineInfo.setPDepthStencilState(InitializeDepthStencilState(dsInfo) ? &dsInfo : nullptr);
+
+  // 8. PipelineColorBlendStateCreateInfo
+  vk::PipelineColorBlendStateCreateInfo bsInfo;
+  gfxPipelineInfo.setPColorBlendState(&bsInfo);
+
+  // 9. PipelineDynamicStateCreateInfo
+  vk::PipelineDynamicStateCreateInfo dynInfo;
+  dynInfo.setDynamicStates(mDynamicStates);
+  gfxPipelineInfo.setPDynamicState(&dynInfo);
+
+  auto& allocator = mController.GetGraphicsDevice().GetAllocator();
+
+  VkAssert(vkDevice.createGraphicsPipelines(VK_NULL_HANDLE,
+                                            1,
+                                            &gfxPipelineInfo,
+                                            &allocator,
+                                            &mVkPipeline));
+}
+
+void PipelineImpl::InitializeVertexInputState(vk::PipelineVertexInputStateCreateInfo& out)
+{
+  std::vector<vk::VertexInputBindingDescription> bindings;
+  std::transform(mCreateInfo.vertexInputState->bufferBindings.begin(),
+                 mCreateInfo.vertexInputState->bufferBindings.end(),
+                 std::back_inserter(bindings),
+                 [](const VertexInputState::Binding& in) -> vk::VertexInputBindingDescription {
+                   vk::VertexInputBindingDescription out;
+                   out.setInputRate((in.inputRate == VertexInputRate::PER_VERTEX ? vk::VertexInputRate::eVertex : vk::VertexInputRate::eInstance));
+                   out.setBinding(0u); // To be filled later using indices
+                   out.setStride(in.stride);
+                   return out;
+                 });
+
+  // Assign bindings
+  for(auto i = 0u; i < bindings.size(); ++i)
+  {
+    bindings[i].binding = i;
+  }
+
+  std::vector<vk::VertexInputAttributeDescription> attrs;
+  std::transform(mCreateInfo.vertexInputState->attributes.begin(),
+                 mCreateInfo.vertexInputState->attributes.end(),
+                 std::back_inserter(attrs),
+                 [](const VertexInputState::Attribute& in) -> vk::VertexInputAttributeDescription {
+                   vk::VertexInputAttributeDescription out;
+                   out.setBinding(in.binding);
+                   out.setLocation(in.location);
+                   out.setOffset(in.offset);
+                   VertexInputFormat format = in.format;
+                   switch(format)
+                   {
+                     case VertexInputFormat::FVECTOR2:
+                     {
+                       out.setFormat(vk::Format::eR32G32Sfloat);
+                       break;
+                     }
+                     case VertexInputFormat::FVECTOR3:
+                     {
+                       out.setFormat(vk::Format::eR32G32B32Sfloat);
+                       break;
+                     }
+                     case VertexInputFormat::FVECTOR4:
+                     {
+                       out.setFormat(vk::Format::eR32G32B32A32Sfloat);
+                       break;
+                     }
+                     case VertexInputFormat::IVECTOR2:
+                     {
+                       out.setFormat(vk::Format::eR32G32Sint);
+                       break;
+                     }
+                     case VertexInputFormat::IVECTOR3:
+                     {
+                       out.setFormat(vk::Format::eR32G32B32Sint);
+                       break;
+                     }
+                     case VertexInputFormat::IVECTOR4:
+                     {
+                       out.setFormat(vk::Format::eR32G32B32A32Sint);
+                       break;
+                     }
+                     case VertexInputFormat::FLOAT:
+                     {
+                       out.setFormat(vk::Format::eR32Sfloat);
+                       break;
+                     }
+                     case VertexInputFormat::INTEGER:
+                     {
+                       out.setFormat(vk::Format::eR32Sint);
+                       break;
+                     }
+                     case VertexInputFormat::UNDEFINED:
+                     default:
+                     {
+                       out.setFormat(vk::Format::eUndefined);
+                       DALI_LOG_ERROR("Vulkan vertex format undefined!\n");
+                     }
+                   };
+                   return out;
+                 });
+
+  mVertexInputAttributeDescriptionList = attrs;
+  mVertexInputBindingDescriptionList   = bindings;
+  out.setVertexAttributeDescriptions(mVertexInputAttributeDescriptionList);
+  out.setVertexBindingDescriptions(mVertexInputBindingDescriptionList);
+}
+
+void PipelineImpl::InitializeInputAssemblyState(vk::PipelineInputAssemblyStateCreateInfo& out) const
+{
+  auto gfxInputAssembly = mCreateInfo.inputAssemblyState;
+  switch(gfxInputAssembly->topology)
+  {
+    case PrimitiveTopology::POINT_LIST:
+    {
+      out.setTopology(vk::PrimitiveTopology::ePointList);
+      break;
+    }
+    case PrimitiveTopology::LINE_LIST:
+    {
+      out.setTopology(vk::PrimitiveTopology::eLineList);
+      break;
+    }
+    case PrimitiveTopology::LINE_LOOP:
+    {
+      out.setTopology({});
+      DALI_LOG_ERROR("LINE_LOOP topology isn't supported by Vulkan!\n");
+      break;
+    }
+    case PrimitiveTopology::LINE_STRIP:
+    {
+      out.setTopology(vk::PrimitiveTopology::eLineStrip);
+      break;
+    }
+    case PrimitiveTopology::TRIANGLE_LIST:
+    {
+      out.setTopology(vk::PrimitiveTopology::eTriangleList);
+      break;
+    }
+    case PrimitiveTopology::TRIANGLE_STRIP:
+    {
+      out.setTopology(vk::PrimitiveTopology::eTriangleStrip);
+      break;
+    }
+    case PrimitiveTopology::TRIANGLE_FAN:
+    {
+      out.setTopology(vk::PrimitiveTopology::eTriangleFan);
+      break;
+    }
+    default:
+    {
+      DALI_LOG_ERROR("Unknown topology!\n");
+    }
+  }
+  out.setPrimitiveRestartEnable(gfxInputAssembly->primitiveRestartEnable);
+}
+
+void PipelineImpl::InitializeViewportState(vk::PipelineViewportStateCreateInfo& out)
+{
+  auto gfxViewportState = mCreateInfo.viewportState;
+
+  // if there is no gfx viewport state provided then we assume
+  // it's going to be a dynamic state
+  if(gfxViewportState)
+  {
+    // build viewport
+    mViewport.x        = gfxViewportState->viewport.x;
+    mViewport.y        = gfxViewportState->viewport.y;
+    mViewport.width    = gfxViewportState->viewport.width;
+    mViewport.height   = gfxViewportState->viewport.height;
+    mViewport.minDepth = gfxViewportState->viewport.minDepth;
+    mViewport.maxDepth = gfxViewportState->viewport.maxDepth;
+
+    mScissor.offset = vk::Offset2D{gfxViewportState->scissor.x, gfxViewportState->scissor.y};
+    mScissor.extent = vk::Extent2D{gfxViewportState->scissor.width, gfxViewportState->scissor.height};
+
+    out.setViewportCount(1);
+    out.setPViewports(&mViewport);
+    out.setScissorCount(1);
+    out.setPScissors(&mScissor);
+  }
+  else
+  {
+    out.setViewportCount(1);
+    out.setScissorCount(1);
+    // enable dynamic state, otherwise it's an error
+    mDynamicStates.emplace_back(vk::DynamicState::eViewport);
+    mDynamicStates.emplace_back(vk::DynamicState::eScissor);
+  }
+}
+
+void PipelineImpl::InitializeMultisampleState(vk::PipelineMultisampleStateCreateInfo& out)
+{
+  out = vk::PipelineMultisampleStateCreateInfo{}; // TODO: decide what to set when we start rendering something
+}
+
+void PipelineImpl::InitializeRasterizationState(vk::PipelineRasterizationStateCreateInfo& out) const
+{
+  auto gfxRastState = mCreateInfo.rasterizationState;
+
+  out.setFrontFace([gfxRastState]() {
+    return gfxRastState->frontFace == FrontFace::CLOCKWISE ? vk::FrontFace::eClockwise : vk::FrontFace::eCounterClockwise;
+  }());
+
+  out.setPolygonMode([polygonMode = gfxRastState->polygonMode]() {
+    switch(polygonMode)
+    {
+      case PolygonMode::FILL:
+      {
+        return vk::PolygonMode::eFill;
+      }
+      case PolygonMode::LINE:
+      {
+        return vk::PolygonMode::eLine;
+      }
+      case PolygonMode::POINT:
+      {
+        return vk::PolygonMode::ePoint;
+      }
+    }
+    return vk::PolygonMode{};
+  }());
+
+  out.setCullMode([cullMode = gfxRastState->cullMode]() -> vk::CullModeFlagBits {
+    switch(cullMode)
+    {
+      case CullMode::NONE:
+      {
+        return vk::CullModeFlagBits::eNone;
+      }
+      case CullMode::BACK:
+      {
+        return vk::CullModeFlagBits::eBack;
+      }
+      case CullMode::FRONT:
+      {
+        return vk::CullModeFlagBits::eFront;
+      }
+      case CullMode::FRONT_AND_BACK:
+      {
+        return vk::CullModeFlagBits::eFrontAndBack;
+      }
+    }
+    return {};
+  }());
+
+  out.setLineWidth(1.0f);         // Line with hardcoded to 1.0f
+  out.setDepthClampEnable(false); // no depth clamp
+}
+
+bool PipelineImpl::InitializeDepthStencilState(vk::PipelineDepthStencilStateCreateInfo& out)
+{
+  auto& in = mCreateInfo.depthStencilState;
+
+  if(in)
+  {
+    out.setBack(ConvStencilOpState(in->back));
+    out.setFront(ConvStencilOpState(in->front));
+    out.setDepthTestEnable(in->depthTestEnable);
+    out.setDepthWriteEnable(in->depthWriteEnable);
+    out.setDepthBoundsTestEnable(false);
+    out.setMinDepthBounds({});
+    out.setMaxDepthBounds({});
+    out.setStencilTestEnable(in->stencilTestEnable);
+    out.setDepthCompareOp(ConvCompareOp(in->depthCompareOp));
+    return true;
+  }
+  return false;
+}
+
+void PipelineImpl::InitializeColorBlendState(vk::PipelineColorBlendStateCreateInfo& out)
+{
+  auto in = mCreateInfo.colorBlendState;
+
+  auto ConvLogicOp = [](LogicOp in) {
+    switch(in)
+    {
+      case LogicOp::CLEAR:
+      {
+        return vk::LogicOp::eClear;
+      }
+      case LogicOp::AND:
+      {
+        return vk::LogicOp::eAnd;
+      }
+      case LogicOp::AND_REVERSE:
+      {
+        return vk::LogicOp::eAndReverse;
+      }
+      case LogicOp::COPY:
+      {
+        return vk::LogicOp::eCopy;
+      }
+      case LogicOp::AND_INVERTED:
+      {
+        return vk::LogicOp::eAndInverted;
+      }
+      case LogicOp::NO_OP:
+      {
+        return vk::LogicOp::eNoOp;
+      }
+      case LogicOp::XOR:
+      {
+        return vk::LogicOp::eXor;
+      }
+      case LogicOp::OR:
+      {
+        return vk::LogicOp::eOr;
+      }
+      case LogicOp::NOR:
+      {
+        return vk::LogicOp::eNor;
+      }
+      case LogicOp::EQUIVALENT:
+      {
+        return vk::LogicOp::eEquivalent;
+      }
+      case LogicOp::INVERT:
+      {
+        return vk::LogicOp::eInvert;
+      }
+      case LogicOp::OR_REVERSE:
+      {
+        return vk::LogicOp::eOrReverse;
+      }
+      case LogicOp::COPY_INVERTED:
+      {
+        return vk::LogicOp::eCopyInverted;
+      }
+      case LogicOp::OR_INVERTED:
+      {
+        return vk::LogicOp::eOrInverted;
+      }
+      case LogicOp::NAND:
+      {
+        return vk::LogicOp::eNand;
+      }
+      case LogicOp::SET:
+      {
+        return vk::LogicOp::eSet;
+      }
+    }
+    return vk::LogicOp{};
+  };
+
+  auto ConvBlendOp = [](BlendOp in) {
+    switch(in)
+    {
+      case BlendOp::ADD:
+      {
+        return vk::BlendOp::eAdd;
+      }
+      case BlendOp::SUBTRACT:
+      {
+        return vk::BlendOp::eSubtract;
+      }
+      case BlendOp::REVERSE_SUBTRACT:
+      {
+        return vk::BlendOp::eReverseSubtract;
+      }
+      case BlendOp::MIN:
+      {
+        return vk::BlendOp::eMin;
+      }
+      case BlendOp::MAX:
+      {
+        return vk::BlendOp::eMax;
+      }
+      case BlendOp::MULTIPLY:
+      {
+        return vk::BlendOp::eMultiplyEXT;
+      }
+      case BlendOp::SCREEN:
+      {
+        return vk::BlendOp::eScreenEXT;
+      }
+      case BlendOp::OVERLAY:
+      {
+        return vk::BlendOp::eOverlayEXT;
+      }
+      case BlendOp::DARKEN:
+      {
+        return vk::BlendOp::eDarkenEXT;
+      }
+      case BlendOp::LIGHTEN:
+      {
+        return vk::BlendOp::eLightenEXT;
+      }
+      case BlendOp::COLOR_DODGE:
+      {
+        return vk::BlendOp::eColordodgeEXT;
+      }
+      case BlendOp::COLOR_BURN:
+      {
+        return vk::BlendOp::eColorburnEXT;
+      }
+      case BlendOp::HARD_LIGHT:
+      {
+        return vk::BlendOp::eHardlightEXT;
+      }
+      case BlendOp::SOFT_LIGHT:
+      {
+        return vk::BlendOp::eSoftlightEXT;
+      }
+      case BlendOp::DIFFERENCE:
+      {
+        return vk::BlendOp::eDifferenceEXT;
+      }
+      case BlendOp::EXCLUSION:
+      {
+        return vk::BlendOp::eExclusionEXT;
+      }
+      case BlendOp::HUE:
+      {
+        return vk::BlendOp::eHslHueEXT;
+      }
+      case BlendOp::SATURATION:
+      {
+        return vk::BlendOp::eHslSaturationEXT;
+      }
+      case BlendOp::COLOR:
+      {
+        return vk::BlendOp::eHslColorEXT;
+      }
+      case BlendOp::LUMINOSITY:
+      {
+        return vk::BlendOp::eHslLuminosityEXT;
+      }
+    }
+    return vk::BlendOp{};
+  };
+
+  auto ConvBlendFactor = [](BlendFactor in) {
+    switch(in)
+    {
+      case BlendFactor::ZERO:
+      {
+        return vk::BlendFactor::eZero;
+      }
+      case BlendFactor::ONE:
+      {
+        return vk::BlendFactor::eOne;
+      }
+      case BlendFactor::SRC_COLOR:
+      {
+        return vk::BlendFactor::eSrcColor;
+      }
+      case BlendFactor::ONE_MINUS_SRC_COLOR:
+      {
+        return vk::BlendFactor::eOneMinusSrcColor;
+      }
+      case BlendFactor::DST_COLOR:
+      {
+        return vk::BlendFactor::eDstColor;
+      }
+      case BlendFactor::ONE_MINUS_DST_COLOR:
+      {
+        return vk::BlendFactor::eOneMinusDstColor;
+      }
+      case BlendFactor::SRC_ALPHA:
+      {
+        return vk::BlendFactor::eSrcAlpha;
+      }
+      case BlendFactor::ONE_MINUS_SRC_ALPHA:
+      {
+        return vk::BlendFactor::eOneMinusSrcAlpha;
+      }
+      case BlendFactor::DST_ALPHA:
+      {
+        return vk::BlendFactor::eDstAlpha;
+      }
+      case BlendFactor::ONE_MINUS_DST_ALPHA:
+      {
+        return vk::BlendFactor::eOneMinusDstAlpha;
+      }
+      case BlendFactor::CONSTANT_COLOR:
+      {
+        return vk::BlendFactor::eConstantColor;
+      }
+      case BlendFactor::ONE_MINUS_CONSTANT_COLOR:
+      {
+        return vk::BlendFactor::eOneMinusConstantColor;
+      }
+      case BlendFactor::CONSTANT_ALPHA:
+      {
+        return vk::BlendFactor::eConstantAlpha;
+      }
+      case BlendFactor::ONE_MINUS_CONSTANT_ALPHA:
+      {
+        return vk::BlendFactor::eOneMinusConstantAlpha;
+      }
+      case BlendFactor::SRC_ALPHA_SATURATE:
+      {
+        return vk::BlendFactor::eSrcAlphaSaturate;
+      }
+      case BlendFactor::SRC1_COLOR:
+      {
+        return vk::BlendFactor::eSrc1Color;
+      }
+      case BlendFactor::ONE_MINUS_SRC1_COLOR:
+      {
+        return vk::BlendFactor::eOneMinusSrc1Color;
+      }
+      case BlendFactor::SRC1_ALPHA:
+      {
+        return vk::BlendFactor::eSrc1Alpha;
+      }
+      case BlendFactor::ONE_MINUS_SRC1_ALPHA:
+      {
+        return vk::BlendFactor::eOneMinusSrc1Alpha;
+      }
+    }
+    return vk::BlendFactor{};
+  };
+
+  out.setLogicOpEnable(in->logicOpEnable);
+  out.setLogicOp(ConvLogicOp(in->logicOp));
+
+  // We don't know how many attachments we will blend but gfx api assumes single attachment
+  mBlendStateAttachments.clear();
+  mBlendStateAttachments.emplace_back();
+  auto& att = mBlendStateAttachments.back();
+
+  att.setAlphaBlendOp(ConvBlendOp(in->alphaBlendOp));
+  att.setBlendEnable(in->blendEnable);
+  att.setColorBlendOp(ConvBlendOp(in->colorBlendOp));
+  att.setColorWriteMask(vk::ColorComponentFlags(in->colorComponentWriteBits));
+  att.setDstAlphaBlendFactor(ConvBlendFactor(in->dstAlphaBlendFactor));
+  att.setDstColorBlendFactor(ConvBlendFactor(in->dstColorBlendFactor));
+  att.setSrcAlphaBlendFactor(ConvBlendFactor(in->srcAlphaBlendFactor));
+  att.setSrcColorBlendFactor(ConvBlendFactor(in->srcColorBlendFactor));
+  out.setAttachments(mBlendStateAttachments);
+
+  std::copy(in->blendConstants, in->blendConstants + 4, out.blendConstants.begin());
+}
+
+} // namespace Dali::Graphics::Vulkan
diff --git a/dali/internal/graphics/vulkan-impl/vulkan-pipeline-impl.h b/dali/internal/graphics/vulkan-impl/vulkan-pipeline-impl.h
new file mode 100644 (file)
index 0000000..c289378
--- /dev/null
@@ -0,0 +1,155 @@
+#ifndef DALI_GRAPHICS_VULKAN_PIPELINE_IMPL_H
+#define DALI_GRAPHICS_VULKAN_PIPELINE_IMPL_H
+
+/*
+ * Copyright (c) 2024 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/graphics-api/graphics-pipeline-create-info.h>
+#include <dali/graphics-api/graphics-pipeline.h>
+#include <string.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/vulkan-impl/vulkan-graphics-resource.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-pipeline.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-reflection.h>
+
+namespace Dali::Graphics::Vulkan
+{
+class Program;
+class PipelineCache; // TODO
+/**
+ * @brief PipelineImpl is the implementation of Pipeline
+ *
+ * PipelineImpl is owned by the pipeline cache. The client-side
+ * will receive Graphics::Pipeline objects which are only
+ * wrappers for this implementation. The lifecycle of
+ * PipelineImpl is managed by the PipelineCache.
+ */
+class PipelineImpl
+{
+public:
+  /**
+   * @brief Constructor
+   * @param[in] createInfo valid TextureCreateInfo structure
+   * @param[in] controller Reference to the Controller
+   * @param[in] pipelineCache Pointer to valid pipeline cache or nullptr if not using cache
+   */
+  PipelineImpl(const Graphics::PipelineCreateInfo& createInfo, VulkanGraphicsController& controller, PipelineCache* pipelineCache);
+
+  /**
+   * @brief Destructor
+   */
+  ~PipelineImpl();
+
+  /**
+   * @brief Binds pipeline
+   */
+  void Bind();
+
+  /**
+   * @brief Increases ref count
+   */
+  void Retain();
+
+  /**
+   * @brief Decreases ref count
+   */
+  void Release();
+
+  /**
+   * @brief Retrieves ref count
+   * @return Refcount value
+   */
+  [[nodiscard]] uint32_t GetRefCount() const;
+
+  /**
+   * @brief Returns PipelineCreateInfo structure
+   *
+   * @return PipelineCreateInfo structure
+   */
+  [[nodiscard]] const PipelineCreateInfo& GetCreateInfo() const;
+
+  /**
+   * @brief Returns controller
+   *
+   * @return Reference to the Controller
+   */
+  [[nodiscard]] VulkanGraphicsController& GetController() const;
+
+private:
+  void InitializePipeline();
+
+  void InitializeVertexInputState(vk::PipelineVertexInputStateCreateInfo& out);
+  void InitializeInputAssemblyState(vk::PipelineInputAssemblyStateCreateInfo& out) const;
+  void InitializeViewportState(vk::PipelineViewportStateCreateInfo& out);
+  void InitializeMultisampleState(vk::PipelineMultisampleStateCreateInfo& out);
+  void InitializeRasterizationState(vk::PipelineRasterizationStateCreateInfo& out) const;
+  bool InitializeDepthStencilState(vk::PipelineDepthStencilStateCreateInfo& out);
+  void InitializeColorBlendState(vk::PipelineColorBlendStateCreateInfo& out);
+
+  /**
+   * @brief Helper function. Copies state if pointer is set
+   */
+  template<class T>
+  void CopyStateIfSet(const T* sourceState, T& copyState, T** destState)
+  {
+    *destState = nullptr;
+    if(sourceState)
+    {
+      copyState  = *sourceState;
+      *destState = &copyState;
+    }
+  }
+
+  /**
+   * @brief Helper function. Copies const state if pointer is set
+   */
+  template<class T>
+  void CopyStateIfSet(const T* sourceState, T& copyState, const T** destState)
+  {
+    *destState = nullptr;
+    if(sourceState)
+    {
+      copyState  = *sourceState;
+      *destState = &copyState;
+    }
+  }
+
+  struct PipelineState;
+  std::unique_ptr<PipelineState> mPipelineState;
+  VulkanGraphicsController&      mController;
+  PipelineCreateInfo             mCreateInfo;
+
+  // Vertex input state data
+  std::vector<vk::VertexInputBindingDescription>   mVertexInputBindingDescriptionList;
+  std::vector<vk::VertexInputAttributeDescription> mVertexInputAttributeDescriptionList;
+
+  // Viewport state data
+  vk::Viewport mViewport;
+  vk::Rect2D   mScissor;
+
+  // Blend state data (using vector if we support more than one)
+  std::vector<vk::PipelineColorBlendAttachmentState> mBlendStateAttachments;
+
+  std::vector<vk::DynamicState> mDynamicStates;
+
+  vk::Pipeline mVkPipeline;
+};
+
+} // namespace Dali::Graphics::Vulkan
+#endif
\ No newline at end of file
diff --git a/dali/internal/graphics/vulkan-impl/vulkan-pipeline.cpp b/dali/internal/graphics/vulkan-impl/vulkan-pipeline.cpp
new file mode 100644 (file)
index 0000000..6cf4fc4
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2024 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/graphics/vulkan-impl/vulkan-pipeline.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/gl-defines.h>
+#include <memory>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/vulkan-impl/vulkan-graphics-controller.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-pipeline-impl.h>
+// TODO: Caching
+//#include <dali/internal/graphics/vulkan-impl/gles-graphics-pipeline-cache.h"
+#include <dali/internal/graphics/vulkan-impl/vulkan-program.h>
+
+namespace Dali::Graphics::Vulkan
+{
+const PipelineCreateInfo& Pipeline::GetCreateInfo() const
+{
+  return mPipeline->GetCreateInfo();
+}
+
+VulkanGraphicsController& Pipeline::GetController() const
+{
+  return mPipeline->GetController();
+}
+
+Pipeline::~Pipeline() = default;
+
+Pipeline::Pipeline(const Graphics::PipelineCreateInfo& createInfo, VulkanGraphicsController& controller)
+{
+  // Not cached
+  mPipeline = std::make_unique<PipelineImpl>(createInfo, controller, nullptr);
+}
+
+Pipeline::Pipeline(const Graphics::PipelineCreateInfo& createInfo, VulkanGraphicsController& controller, PipelineCache* pipelineCache)
+{
+  // TODO: pipeline caching. pipeline cache can be nullptr and be bypassed for now
+  // This constructor isn't in use currently and will most likely change
+  mPipeline = std::make_unique<PipelineImpl>(createInfo, controller, pipelineCache);
+}
+
+void Pipeline::DiscardResource()
+{
+  // Send pipeline to discard queue if refcount is 0
+  GetController().DiscardResource(this);
+}
+
+void Pipeline::DestroyResource()
+{
+  // Nothing to do here
+}
+
+bool Pipeline::operator==(const PipelineImpl* impl) const
+{
+  return false; // &mPipeline == impl; // TODO: needs caching
+}
+
+} // namespace Dali::Graphics::Vulkan
diff --git a/dali/internal/graphics/vulkan-impl/vulkan-pipeline.h b/dali/internal/graphics/vulkan-impl/vulkan-pipeline.h
new file mode 100644 (file)
index 0000000..2a370bc
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef DALI_GRAPHICS_VULKAN_PIPELINE_H
+#define DALI_GRAPHICS_VULKAN_PIPELINE_H
+
+/*
+ * Copyright (c) 2024 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/graphics-api/graphics-pipeline-create-info.h>
+#include <dali/graphics-api/graphics-pipeline.h>
+#include <string.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/vulkan-impl/vulkan-graphics-resource.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-reflection.h>
+
+namespace Dali::Graphics::Vulkan
+{
+class Program;
+class PipelineImpl;
+class PipelineCache;
+/**
+ * @brief Pipeline class wraps the PipelineImpl
+ */
+class Pipeline : public Graphics::Pipeline
+{
+public:
+  Pipeline() = delete;
+
+  Pipeline(const Graphics::PipelineCreateInfo& createInfo, VulkanGraphicsController& controller);
+
+  /**
+   *
+   * @param createInfo
+   * @param controller
+   * @param pipelineCache
+   */
+  Pipeline(const Graphics::PipelineCreateInfo& createInfo, VulkanGraphicsController& controller, PipelineCache* pipelineCache);
+
+  /**
+   * @brief Destructor
+   */
+  ~Pipeline() override;
+
+  /**
+   * @brief Returns pipeline implementation
+   *
+   * @return Valid pipeline implementation
+   */
+  [[nodiscard]] auto& GetPipeline() const
+  {
+    return mPipeline;
+  }
+
+  /**
+   * @brief Returns create info structure
+   *
+   * @return Valid create info structure
+   */
+  [[nodiscard]] const PipelineCreateInfo& GetCreateInfo() const;
+
+  /**
+   * @brief Returns controller
+   *
+   * @return reference to Controller
+   */
+  [[nodiscard]] VulkanGraphicsController& GetController() const;
+
+  bool operator==(const PipelineImpl* impl) const;
+
+  /**
+   * @brief Run by UniquePtr to discard resource
+   */
+  void DiscardResource();
+
+  /**
+   * @brief Destroy resource
+   *
+   * Despite this class doesn't inherit Resource it must provide
+   * (so it won't duplicate same data) same set of functions
+   * so it can work with resource management functions of Controller.
+   */
+  void DestroyResource();
+
+private:
+  std::unique_ptr<PipelineImpl> mPipeline; // TODO: it may need to be changed when we have caching
+};
+
+} // namespace Dali::Graphics::Vulkan
+#endif
\ No newline at end of file
index 7d09463b6dbaad2a3cf4d7f97ac34110f32cbad1..0a6d8a67dfd903c6693573763f1bea481f7bf793 100644 (file)
@@ -61,6 +61,8 @@ struct ProgramImpl::Impl
   uint32_t                  refCount{0u};
 
   std::unique_ptr<Vulkan::Reflection> reflection{nullptr};
+
+  std::vector<vk::PipelineShaderStageCreateInfo> mPipelineShaderStageCreateInfoList;
 };
 
 ProgramImpl::ProgramImpl(const Graphics::ProgramCreateInfo& createInfo, VulkanGraphicsController& controller)
@@ -89,6 +91,28 @@ ProgramImpl::ProgramImpl(const Graphics::ProgramCreateInfo& createInfo, VulkanGr
     // Build reflection
     mImpl->reflection = std::make_unique<Vulkan::Reflection>(*this, controller);
   }
+
+  // Create shader stages for pipeline creation
+  for(const auto& state : *createInfo.shaderState)
+  {
+    mImpl->mPipelineShaderStageCreateInfoList.emplace_back();
+    auto& info = mImpl->mPipelineShaderStageCreateInfoList.back();
+    info.setModule(static_cast<const Vulkan::Shader*>(state.shader)->GetImplementation()->GetVkShaderModule());
+    if(state.pipelineStage == PipelineStage::VERTEX_SHADER)
+    {
+      info.setStage(vk::ShaderStageFlagBits::eVertex);
+      info.setPName("main");
+    }
+    if(state.pipelineStage == PipelineStage::FRAGMENT_SHADER)
+    {
+      info.setStage(vk::ShaderStageFlagBits::eFragment);
+      info.setPName("main");
+    }
+    else
+    {
+      DALI_ASSERT_ALWAYS(true && "Invalid pipeline shader stage!");
+    }
+  }
 }
 
 ProgramImpl::~ProgramImpl() = default;
@@ -220,4 +244,9 @@ const ProgramCreateInfo& ProgramImpl::GetCreateInfo() const
   return mImpl->createInfo;
 }
 
+[[nodiscard]] const std::vector<vk::PipelineShaderStageCreateInfo>& ProgramImpl::GetVkPipelineShaderStageCreateInfoList() const
+{
+  return mImpl->mPipelineShaderStageCreateInfoList;
+}
+
 }; // namespace Dali::Graphics::Vulkan
index 6d1bef7797ba3239e8b722c6b562871dacdbb876..cf59bf2828d70f33c32d285c2a28c178be0c8e7e 100644 (file)
@@ -20,6 +20,7 @@
 // EXTERNAL INCLUDES
 #include <dali/graphics-api/graphics-program-create-info.h>
 #include <dali/graphics-api/graphics-program.h>
+#include <vulkan/vulkan.hpp>
 
 // INTERNAL INCLUDES
 #include <dali/internal/graphics/vulkan-impl/vulkan-graphics-resource.h>
@@ -121,6 +122,13 @@ public:
    */
   [[nodiscard]] const ProgramCreateInfo& GetCreateInfo() const;
 
+  /**
+   * @brief Returns list of shader stages
+   *
+   * @return List of shader stages
+   */
+  [[nodiscard]] const std::vector<vk::PipelineShaderStageCreateInfo>& GetVkPipelineShaderStageCreateInfoList() const;
+
   /**
    * @brief Returns parameter value specified by parameterId
    *
index d3a0761d2924d04ff8a5843f4bd40c92221f3ec2..799d7dc44a65ff15de3bfdec3a1a176b32ab0455 100644 (file)
@@ -24,6 +24,7 @@
 #include <dali/internal/graphics/vulkan-impl/vulkan-program-impl.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-shader-impl.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-shader.h>
+#include <dali/internal/graphics/vulkan/vulkan-device.h>
 #include <dali/public-api/common/vector-wrapper.h>
 
 // EXTERNAL INCLUDES
@@ -84,7 +85,17 @@ Reflection::Reflection(Vulkan::ProgramImpl& program, VulkanGraphicsController& c
   BuildReflection();
 }
 
-Reflection::~Reflection() = default;
+Reflection::~Reflection()
+{
+  auto  vkDevice  = mController.GetGraphicsDevice().GetLogicalDevice();
+  auto& allocator = mController.GetGraphicsDevice().GetAllocator();
+
+  vkDevice.destroyPipelineLayout(mVkPipelineLayout, allocator);
+  for(auto& dsLayout : mVkDescriptorSetLayoutList)
+  {
+    vkDevice.destroyDescriptorSetLayout(dsLayout, allocator);
+  }
+}
 
 template<typename FN, typename OUT>
 void SPIRVEnumerate(FN& proc, SpvReflectShaderModule* module, std::vector<OUT*>& out)
@@ -257,7 +268,7 @@ void Reflection::BuildReflection()
 
     if(!samplers.empty())
     {
-      mUniformOpaques.insert(samplers.begin(), samplers.end(), mUniformOpaques.end());
+      mUniformOpaques.insert(mUniformOpaques.end(), samplers.begin(), samplers.end());
       // sort samplers by bindings
       std::sort(mUniformOpaques.begin(), mUniformOpaques.end(), [](auto& lhs, auto& rhs) { return lhs.binding < rhs.binding; });
       for(auto i = 0u; i < mUniformOpaques.size(); ++i)
@@ -268,6 +279,34 @@ void Reflection::BuildReflection()
 
     spvReflectDestroyShaderModule(&module);
   }
+
+  auto vkDevice = mController.GetGraphicsDevice().GetLogicalDevice();
+
+  // Create descriptor set layouts
+
+  for(auto& dsLayoutCreateInfo : mVkDescriptorSetLayoutCreateInfoList)
+  {
+    auto dsLayout = vkDevice.createDescriptorSetLayout(dsLayoutCreateInfo,
+                                                       mController.GetGraphicsDevice().GetAllocator());
+
+    mVkDescriptorSetLayoutList.emplace_back(dsLayout.value);
+  }
+
+  // Create pipeline layout
+  vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
+  pipelineLayoutCreateInfo.setSetLayouts(mVkDescriptorSetLayoutList);
+  // TODO: support push-constants, for now pipeline layout ignores push-constant
+
+  vk::PipelineLayout pipelineLayout;
+  VkAssert(vkDevice.createPipelineLayout(&pipelineLayoutCreateInfo, &mController.GetGraphicsDevice().GetAllocator(), &pipelineLayout));
+  mVkPipelineLayout = pipelineLayout;
+
+  // Destroy descriptor set layouts
+}
+
+vk::PipelineLayout Reflection::GetVkPipelineLayout() const
+{
+  return mVkPipelineLayout;
 }
 
 void Reflection::BuildVertexAttributeReflection(SpvReflectShaderModule* spvModule)
index a5626953f33b73a1bfcb66faecce819ddf83c91b..4a45aff8e6f09defc22a298231f4a2f6859215b8 100644 (file)
@@ -204,6 +204,8 @@ public:
 
   void BuildReflection();
 
+  vk::PipelineLayout GetVkPipelineLayout() const;
+
 protected:
   Reflection(Reflection&&) = default;
   Reflection& operator=(Reflection&&) = default;
@@ -226,6 +228,8 @@ private:
   // Vulkan data
   std::vector<vk::DescriptorSetLayoutCreateInfo>           mVkDescriptorSetLayoutCreateInfoList; ///< List of DSlayout create structures
   std::vector<std::vector<vk::DescriptorSetLayoutBinding>> mVkDescriptorSetLayoutBindingList;
+  std::vector<vk::DescriptorSetLayout>                     mVkDescriptorSetLayoutList;
+  vk::PipelineLayout                                       mVkPipelineLayout;
 };
 
 } // namespace Vulkan
index fb6fae6a395986bc161293f7f4799c775f78c36a..54228c0e2f999b228298799f14110a66d837cea6 100644 (file)
@@ -74,9 +74,9 @@ glslang_shader_t* SPIRVGenerator::CompileSource(glslang_stage_t stage, std::stri
     .language                          = GLSLANG_SOURCE_GLSL,
     .stage                             = stage,
     .client                            = GLSLANG_CLIENT_VULKAN,
-    .client_version                    = GLSLANG_TARGET_VULKAN_1_2,
+    .client_version                    = GLSLANG_TARGET_VULKAN_1_0,
     .target_language                   = GLSLANG_TARGET_SPV,
-    .target_language_version           = GLSLANG_TARGET_SPV_1_5,
+    .target_language_version           = GLSLANG_TARGET_SPV_1_0,
     .code                              = cstr,
     .default_version                   = 100,
     .default_profile                   = GLSLANG_NO_PROFILE,