diff options
author | Jaebaek Seo <duke.acacia@gmail.com> | 2018-11-26 14:37:40 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-11-26 14:37:40 -0500 |
commit | da1d01dfca44f24ab1e344f7c531d57735a499ac (patch) | |
tree | 0ed84a1470d281119ad2b15659c352839b6be05a | |
parent | eb5fc8cf5d299c180170cc0d3b339d5c4a82c855 (diff) | |
download | amber-da1d01dfca44f24ab1e344f7c531d57735a499ac.tar.gz |
Vulkan: add SSBO (#63)
Add SSBO and Vulkan objects to use descriptors.
Fixes #11
-rw-r--r-- | src/command.h | 6 | ||||
-rw-r--r-- | src/vkscript/command_parser_test.cc | 8 | ||||
-rw-r--r-- | src/vulkan/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/vulkan/descriptor.cc | 90 | ||||
-rw-r--r-- | src/vulkan/descriptor.h | 36 | ||||
-rw-r--r-- | src/vulkan/engine_vulkan.cc | 8 | ||||
-rw-r--r-- | src/vulkan/graphics_pipeline.cc | 14 | ||||
-rw-r--r-- | src/vulkan/pipeline.cc | 210 | ||||
-rw-r--r-- | src/vulkan/pipeline.h | 25 | ||||
-rw-r--r-- | src/vulkan/storage_buffer_descriptor.cc | 127 | ||||
-rw-r--r-- | src/vulkan/storage_buffer_descriptor.h | 54 | ||||
-rw-r--r-- | tests/cases/ssbo_with_graphics_pipeline.amber | 58 |
12 files changed, 620 insertions, 17 deletions
diff --git a/src/command.h b/src/command.h index b2e8540..72c2981 100644 --- a/src/command.h +++ b/src/command.h @@ -329,7 +329,11 @@ class BufferCommand : public Command { void SetDatumType(const DatumType& type) { datum_type_ = type; } const DatumType& GetDatumType() const { return datum_type_; } - void SetValues(std::vector<Value>&& values) { values_ = std::move(values); } + void SetValues(std::vector<Value>&& values) { + values_ = std::move(values); + size_ = static_cast<uint32_t>(values_.size() * datum_type_.SizeInBytes()) / + datum_type_.ColumnCount() / datum_type_.RowCount(); + } const std::vector<Value>& GetValues() const { return values_; } private: diff --git a/src/vkscript/command_parser_test.cc b/src/vkscript/command_parser_test.cc index 8ab8e30..27f63d7 100644 --- a/src/vkscript/command_parser_test.cc +++ b/src/vkscript/command_parser_test.cc @@ -2588,6 +2588,7 @@ TEST_F(CommandParserTest, SSBOSubdataWithFloat) { EXPECT_EQ(static_cast<uint32_t>(0), cmd->GetDescriptorSet()); EXPECT_EQ(6U, cmd->GetBinding()); EXPECT_EQ(2U, cmd->GetOffset()); + EXPECT_EQ(12U, cmd->GetSize()); ASSERT_TRUE(cmd->IsSubdata()); const auto& type = cmd->GetDatumType(); @@ -2620,6 +2621,7 @@ TEST_F(CommandParserTest, SSBOSubdataWithDescriptorSet) { EXPECT_EQ(6U, cmd->GetBinding()); EXPECT_EQ(2U, cmd->GetOffset()); ASSERT_TRUE(cmd->IsSubdata()); + EXPECT_EQ(12U, cmd->GetSize()); const auto& type = cmd->GetDatumType(); EXPECT_TRUE(type.IsFloat()); @@ -2651,6 +2653,7 @@ TEST_F(CommandParserTest, SSBOSubdataWithInts) { EXPECT_EQ(6U, cmd->GetBinding()); EXPECT_EQ(2U, cmd->GetOffset()); ASSERT_TRUE(cmd->IsSubdata()); + EXPECT_EQ(6U, cmd->GetSize()); const auto& type = cmd->GetDatumType(); EXPECT_TRUE(type.IsInt16()); @@ -2682,6 +2685,7 @@ TEST_F(CommandParserTest, SSBOSubdataWithMultipleVectors) { EXPECT_EQ(6U, cmd->GetBinding()); EXPECT_EQ(2U, cmd->GetOffset()); ASSERT_TRUE(cmd->IsSubdata()); + EXPECT_EQ(12U, cmd->GetSize()); const auto& type = cmd->GetDatumType(); EXPECT_TRUE(type.IsInt16()); @@ -2782,6 +2786,7 @@ TEST_F(CommandParserTest, Uniform) { auto* cmd = cmds[0]->AsBuffer(); EXPECT_TRUE(cmd->IsPushConstant()); EXPECT_EQ(2U, cmd->GetOffset()); + EXPECT_EQ(12U, cmd->GetSize()); const auto& type = cmd->GetDatumType(); EXPECT_TRUE(type.IsFloat()); @@ -2810,6 +2815,7 @@ TEST_F(CommandParserTest, UniformWithContinuation) { auto* cmd = cmds[0]->AsBuffer(); EXPECT_TRUE(cmd->IsPushConstant()); EXPECT_EQ(2U, cmd->GetOffset()); + EXPECT_EQ(24U, cmd->GetSize()); const auto& type = cmd->GetDatumType(); EXPECT_TRUE(type.IsFloat()); @@ -2877,6 +2883,7 @@ TEST_F(CommandParserTest, UniformUBO) { EXPECT_EQ(static_cast<uint32_t>(0), cmd->GetDescriptorSet()); EXPECT_EQ(2U, cmd->GetBinding()); EXPECT_EQ(1U, cmd->GetOffset()); + EXPECT_EQ(12U, cmd->GetSize()); const auto& type = cmd->GetDatumType(); EXPECT_TRUE(type.IsFloat()); @@ -2907,6 +2914,7 @@ TEST_F(CommandParserTest, UniformUBOWithDescriptorSet) { EXPECT_EQ(3U, cmd->GetDescriptorSet()); EXPECT_EQ(2U, cmd->GetBinding()); EXPECT_EQ(1U, cmd->GetOffset()); + EXPECT_EQ(12U, cmd->GetSize()); const auto& type = cmd->GetDatumType(); EXPECT_TRUE(type.IsFloat()); diff --git a/src/vulkan/CMakeLists.txt b/src/vulkan/CMakeLists.txt index 8df5759..9c41e39 100644 --- a/src/vulkan/CMakeLists.txt +++ b/src/vulkan/CMakeLists.txt @@ -25,6 +25,7 @@ set(VULKAN_ENGINE_SOURCES image.cc pipeline.cc graphics_pipeline.cc + storage_buffer_descriptor.cc vertex_buffer.cc ) diff --git a/src/vulkan/descriptor.cc b/src/vulkan/descriptor.cc index 294e3b6..bdbbe29 100644 --- a/src/vulkan/descriptor.cc +++ b/src/vulkan/descriptor.cc @@ -49,10 +49,96 @@ VkDescriptorType ToVkDescriptorType(DescriptorType type) { return VK_DESCRIPTOR_TYPE_SAMPLER; } -Descriptor::Descriptor(DescriptorType type, uint32_t desc_set, uint32_t binding) - : type_(type), descriptor_set_(desc_set), binding_(binding) {} +Descriptor::Descriptor(DescriptorType type, + VkDevice device, + uint32_t desc_set, + uint32_t binding) + : descriptor_set_(desc_set), + binding_(binding), + type_(type), + device_(device) {} Descriptor::~Descriptor() = default; +VkWriteDescriptorSet Descriptor::GetWriteDescriptorSet( + VkDescriptorSet descriptor_set, + VkDescriptorType descriptor_type) const { + VkWriteDescriptorSet write = {}; + write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write.dstSet = descriptor_set; + write.dstBinding = binding_; + write.dstArrayElement = 0; + write.descriptorCount = 1; + write.descriptorType = descriptor_type; + return write; +} + +Result Descriptor::UpdateDescriptorSetForBuffer( + VkDescriptorSet descriptor_set, + VkDescriptorType descriptor_type, + const VkDescriptorBufferInfo& buffer_info) { + VkWriteDescriptorSet write = + GetWriteDescriptorSet(descriptor_set, descriptor_type); + switch (descriptor_type) { + case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: + case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: + case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: + case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: + write.pBufferInfo = &buffer_info; + break; + default: + return Result( + "Vulkan::UpdateDescriptorSetForBuffer not descriptor based on " + "buffer"); + } + + vkUpdateDescriptorSets(device_, 1, &write, 0, nullptr); + return {}; +} + +Result Descriptor::UpdateDescriptorSetForImage( + VkDescriptorSet descriptor_set, + VkDescriptorType descriptor_type, + const VkDescriptorImageInfo& image_info) { + VkWriteDescriptorSet write = + GetWriteDescriptorSet(descriptor_set, descriptor_type); + switch (descriptor_type) { + case VK_DESCRIPTOR_TYPE_SAMPLER: + case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: + case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: + case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: + case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: + write.pImageInfo = &image_info; + break; + default: + return Result( + "Vulkan::UpdateDescriptorSetForImage not descriptor based on image"); + } + + vkUpdateDescriptorSets(device_, 1, &write, 0, nullptr); + return {}; +} + +Result Descriptor::UpdateDescriptorSetForBufferView( + VkDescriptorSet descriptor_set, + VkDescriptorType descriptor_type, + const VkBufferView& texel_view) { + VkWriteDescriptorSet write = + GetWriteDescriptorSet(descriptor_set, descriptor_type); + switch (descriptor_type) { + case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: + case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: + write.pTexelBufferView = &texel_view; + break; + default: + return Result( + "Vulkan::UpdateDescriptorSetForImage not descriptor based on buffer " + "view"); + } + + vkUpdateDescriptorSets(device_, 1, &write, 0, nullptr); + return {}; +} + } // namespace vulkan } // namespace amber diff --git a/src/vulkan/descriptor.h b/src/vulkan/descriptor.h index ea24733..be370a5 100644 --- a/src/vulkan/descriptor.h +++ b/src/vulkan/descriptor.h @@ -41,7 +41,10 @@ VkDescriptorType ToVkDescriptorType(DescriptorType type); class Descriptor { public: - Descriptor(DescriptorType type, uint32_t desc_set, uint32_t binding); + Descriptor(DescriptorType type, + VkDevice device, + uint32_t desc_set, + uint32_t binding); ~Descriptor(); @@ -80,10 +83,37 @@ class Descriptor { return type_ == DescriptorType::kDynamicStorageBuffer; } - private: - DescriptorType type_ = DescriptorType::kSampledImage; + bool IsDataAlreadySent() { return is_data_already_sent_; } + + virtual Result UpdateDescriptorSet(VkDescriptorSet descriptor_set) = 0; + virtual void SendDataToGPUIfNeeded(VkCommandBuffer command) = 0; + virtual void Shutdown() = 0; + + protected: + Result UpdateDescriptorSetForBuffer( + VkDescriptorSet descriptor_set, + VkDescriptorType descriptor_type, + const VkDescriptorBufferInfo& buffer_info); + Result UpdateDescriptorSetForImage(VkDescriptorSet descriptor_set, + VkDescriptorType descriptor_type, + const VkDescriptorImageInfo& image_info); + Result UpdateDescriptorSetForBufferView(VkDescriptorSet descriptor_set, + VkDescriptorType descriptor_type, + const VkBufferView& texel_view); + + void SetDataSent() { is_data_already_sent_ = true; } + uint32_t descriptor_set_ = 0; uint32_t binding_ = 0; + + private: + VkWriteDescriptorSet GetWriteDescriptorSet( + VkDescriptorSet descriptor_set, + VkDescriptorType descriptor_type) const; + + DescriptorType type_ = DescriptorType::kSampledImage; + bool is_data_already_sent_ = false; + VkDevice device_ = VK_NULL_HANDLE; }; } // namespace vulkan diff --git a/src/vulkan/engine_vulkan.cc b/src/vulkan/engine_vulkan.cc index 74fa9f1..abad862 100644 --- a/src/vulkan/engine_vulkan.cc +++ b/src/vulkan/engine_vulkan.cc @@ -18,6 +18,7 @@ #include <cassert> #include "src/make_unique.h" +#include "src/vulkan/descriptor.h" #include "src/vulkan/format_data.h" #include "src/vulkan/graphics_pipeline.h" @@ -288,8 +289,11 @@ Result EngineVulkan::DoProcessCommands(uint32_t* stride, return r; } -Result EngineVulkan::DoBuffer(const BufferCommand*) { - return Result("Vulkan::DoBuffer Not Implemented"); +Result EngineVulkan::DoBuffer(const BufferCommand* command) { + if (!command->IsSSBO()) + return Result("Vulkan::DoBuffer non-SSBO descriptor not implemented"); + + return pipeline_->AddDescriptor(command); } } // namespace vulkan diff --git a/src/vulkan/graphics_pipeline.cc b/src/vulkan/graphics_pipeline.cc index 91bcb96..2b61bdc 100644 --- a/src/vulkan/graphics_pipeline.cc +++ b/src/vulkan/graphics_pipeline.cc @@ -199,7 +199,7 @@ Result GraphicsPipeline::CreateVkGraphicsPipeline( if (pipeline_ != VK_NULL_HANDLE) return Result("Vulkan::Pipeline already created"); - Result r = CreatePipelineLayout(); + Result r = CreateVkDescriptorRelatedObjects(); if (!r.IsSuccess()) return r; @@ -470,11 +470,15 @@ Result GraphicsPipeline::Draw(const DrawArraysCommand* command) { return r; } - Result r = SendBufferDataIfNeeded(); + Result r = command_->BeginIfNotInRecording(); + if (!r.IsSuccess()) + return r; + + r = SendBufferDataIfNeeded(); if (!r.IsSuccess()) return r; - r = command_->BeginIfNotInRecording(); + r = SendDescriptorDataToGPUIfNeeded(); if (!r.IsSuccess()) return r; @@ -483,8 +487,8 @@ Result GraphicsPipeline::Draw(const DrawArraysCommand* command) { ActivateRenderPassIfNeeded(); - vkCmdBindPipeline(command_->GetCommandBuffer(), - VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_); + BindVkDescriptorSets(); + BindVkPipeline(); if (vertex_buffer_) vertex_buffer_->BindToCommandBuffer(command_->GetCommandBuffer()); diff --git a/src/vulkan/pipeline.cc b/src/vulkan/pipeline.cc index e16c277..5c92ef0 100644 --- a/src/vulkan/pipeline.cc +++ b/src/vulkan/pipeline.cc @@ -14,11 +14,14 @@ #include "src/vulkan/pipeline.h" +#include <algorithm> #include <limits> +#include <utility> #include "src/command.h" #include "src/make_unique.h" #include "src/vulkan/graphics_pipeline.h" +#include "src/vulkan/storage_buffer_descriptor.h" namespace amber { namespace vulkan { @@ -45,15 +48,127 @@ Result Pipeline::InitializeCommandBuffer(VkCommandPool pool, VkQueue queue) { void Pipeline::Shutdown() { // TODO(jaebaek): destroy pipeline_cache_ and pipeline_ + DestoryDescriptorPools(); + DestoryDescriptorSetLayouts(); command_->Shutdown(); vkDestroyPipelineLayout(device_, pipeline_layout_, nullptr); } +void Pipeline::DestoryDescriptorSetLayouts() { + for (size_t i = 0; i < descriptor_set_layouts_.size(); ++i) { + vkDestroyDescriptorSetLayout(device_, descriptor_set_layouts_[i], nullptr); + } + descriptor_set_layouts_.clear(); +} + +Result Pipeline::CreateDescriptorSetLayouts() { + std::sort(descriptors_.begin(), descriptors_.end()); + + size_t i = 0; + while (i < descriptors_.size()) { + std::vector<VkDescriptorSetLayoutBinding> bindings; + for (const uint32_t current_desc = descriptors_[i]->GetDescriptorSet(); + i < descriptors_.size() && + current_desc == descriptors_[i]->GetDescriptorSet(); + ++i) { + bindings.emplace_back(); + bindings.back().binding = descriptors_[i]->GetBinding(); + bindings.back().descriptorType = + ToVkDescriptorType(descriptors_[i]->GetType()); + bindings.back().descriptorCount = 1; + // TODO(jaebaek): Amber script must contain which stages use each + // descriptor. Set .stageFlags attribute based on it. + bindings.back().stageFlags = VK_SHADER_STAGE_ALL; + // TODO(jaebaek): Properly set .pImmutableSamplers attribute. + } + + VkDescriptorSetLayoutCreateInfo desc_info = {}; + desc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + desc_info.bindingCount = bindings.size(); + desc_info.pBindings = bindings.data(); + + VkDescriptorSetLayout desc_layout = VK_NULL_HANDLE; + if (vkCreateDescriptorSetLayout(device_, &desc_info, nullptr, + &desc_layout) != VK_SUCCESS) { + return Result("Vulkan::Calling vkCreateDescriptorSetLayout Fail"); + } + descriptor_set_layouts_.push_back(desc_layout); + } + + return {}; +} + +void Pipeline::DestoryDescriptorPools() { + for (size_t i = 0; i < descriptor_pools_.size(); ++i) { + vkDestroyDescriptorPool(device_, descriptor_pools_[i], nullptr); + } + descriptor_pools_.clear(); +} + +Result Pipeline::CreateDescriptorPools() { + size_t i = 0; + while (i < descriptors_.size()) { + std::vector<VkDescriptorPoolSize> pool_sizes; + for (const uint32_t current_desc = descriptors_[i]->GetDescriptorSet(); + i < descriptors_.size() && + current_desc == descriptors_[i]->GetDescriptorSet(); + ++i) { + auto type = ToVkDescriptorType(descriptors_[i]->GetType()); + auto it = find_if(pool_sizes.begin(), pool_sizes.end(), + [&type](const VkDescriptorPoolSize& size) { + return size.type == type; + }); + if (it != pool_sizes.end()) { + it->descriptorCount += 1; + continue; + } + + pool_sizes.emplace_back(); + pool_sizes.back().type = type; + pool_sizes.back().descriptorCount = 1; + } + + VkDescriptorPoolCreateInfo pool_info = {}; + pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + pool_info.maxSets = 1; + pool_info.poolSizeCount = pool_sizes.size(); + pool_info.pPoolSizes = pool_sizes.data(); + + VkDescriptorPool desc_pool = VK_NULL_HANDLE; + if (vkCreateDescriptorPool(device_, &pool_info, nullptr, &desc_pool) != + VK_SUCCESS) { + return Result("Vulkan::Calling vkCreateDescriptorPool Fail"); + } + descriptor_pools_.push_back(desc_pool); + } + + return {}; +} + +Result Pipeline::CreateDescriptorSets() { + for (size_t i = 0; i < descriptor_set_layouts_.size(); ++i) { + VkDescriptorSetAllocateInfo desc_set_info = {}; + desc_set_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + desc_set_info.descriptorPool = descriptor_pools_[i]; + desc_set_info.descriptorSetCount = 1; + desc_set_info.pSetLayouts = &descriptor_set_layouts_[i]; + + VkDescriptorSet desc_set = VK_NULL_HANDLE; + if (vkAllocateDescriptorSets(device_, &desc_set_info, &desc_set) != + VK_SUCCESS) { + return Result("Vulkan::Calling vkAllocateDescriptorSets Fail"); + } + descriptor_sets_.push_back(desc_set); + } + + return {}; +} + Result Pipeline::CreatePipelineLayout() { VkPipelineLayoutCreateInfo pipeline_layout_info = {}; pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipeline_layout_info.setLayoutCount = 0; - pipeline_layout_info.pSetLayouts = nullptr; + pipeline_layout_info.setLayoutCount = descriptor_set_layouts_.size(); + pipeline_layout_info.pSetLayouts = descriptor_set_layouts_.data(); // TODO(jaebaek): Push constant for pipeline_layout_info. if (vkCreatePipelineLayout(device_, &pipeline_layout_info, nullptr, @@ -64,5 +179,96 @@ Result Pipeline::CreatePipelineLayout() { return {}; } +Result Pipeline::CreateVkDescriptorRelatedObjects() { + // TODO(jaebaek): Update SSBO dynamically. + Result r = CreateDescriptorSetLayouts(); + if (!r.IsSuccess()) + return r; + + r = CreateDescriptorPools(); + if (!r.IsSuccess()) + return r; + + r = CreateDescriptorSets(); + if (!r.IsSuccess()) + return r; + + r = CreatePipelineLayout(); + if (!r.IsSuccess()) + return r; + + for (size_t i = 0, j = 0; + i < descriptors_.size() && j < descriptor_sets_.size(); ++j) { + for (const uint32_t current_desc = descriptors_[i]->GetDescriptorSet(); + i < descriptors_.size() && + current_desc == descriptors_[i]->GetDescriptorSet(); + ++i) { + r = descriptors_[i]->UpdateDescriptorSet(descriptor_sets_[j]); + if (!r.IsSuccess()) + return r; + } + } + + return {}; +} + +Result Pipeline::AddDescriptor(const BufferCommand* buffer_command) { + if (!buffer_command->IsSSBO()) + return Result("Vulkan::AddDescriptor non-SSBO not implemented"); + + auto ssbo = MakeUnique<StorageBufferDescriptor>( + device_, buffer_command->GetDescriptorSet(), buffer_command->GetBinding(), + buffer_command->GetSize(), memory_properties_); + + Result r = ssbo->Initialize(buffer_command->GetDatumType().GetType(), + buffer_command->GetValues()); + if (!r.IsSuccess()) + return r; + + descriptors_.push_back(std::move(ssbo)); + + return {}; +} + +Result Pipeline::SendDescriptorDataToGPUIfNeeded() { + if (descriptors_.size() == 0) + return {}; + + bool data_send_needed = false; + for (const auto& desc : descriptors_) { + if (!desc->IsDataAlreadySent()) { + data_send_needed = true; + break; + } + } + + if (!data_send_needed) + return {}; + + Result r = command_->BeginIfNotInRecording(); + if (!r.IsSuccess()) + return r; + + for (const auto& desc : descriptors_) + desc->SendDataToGPUIfNeeded(command_->GetCommandBuffer()); + + return {}; +} + +void Pipeline::BindVkDescriptorSets() { + vkCmdBindDescriptorSets(command_->GetCommandBuffer(), + IsGraphics() ? VK_PIPELINE_BIND_POINT_GRAPHICS + : VK_PIPELINE_BIND_POINT_COMPUTE, + pipeline_layout_, 0, descriptor_sets_.size(), + descriptor_sets_.data(), 0, nullptr); +} + +void Pipeline::BindVkPipeline() { + vkCmdBindPipeline(command_->GetCommandBuffer(), + IsGraphics() ? VK_PIPELINE_BIND_POINT_GRAPHICS + : VK_PIPELINE_BIND_POINT_COMPUTE, + pipeline_); +} + } // namespace vulkan } // namespace amber diff --git a/src/vulkan/pipeline.h b/src/vulkan/pipeline.h index 38a234a..18c787b 100644 --- a/src/vulkan/pipeline.h +++ b/src/vulkan/pipeline.h @@ -21,9 +21,13 @@ #include "amber/result.h" #include "src/engine.h" #include "src/vulkan/command.h" +#include "src/vulkan/descriptor.h" #include "vulkan/vulkan.h" namespace amber { + +class BufferCommand; + namespace vulkan { class GraphicsPipeline; @@ -37,6 +41,8 @@ class Pipeline { GraphicsPipeline* AsGraphics(); + Result AddDescriptor(const BufferCommand*); + virtual void Shutdown(); protected: @@ -44,21 +50,36 @@ class Pipeline { VkDevice device, const VkPhysicalDeviceMemoryProperties& properties); Result InitializeCommandBuffer(VkCommandPool pool, VkQueue queue); + Result CreateVkDescriptorRelatedObjects(); - Result CreatePipelineLayout(); + Result SendDescriptorDataToGPUIfNeeded(); + void BindVkPipeline(); + void BindVkDescriptorSets(); VkPipelineCache pipeline_cache_ = VK_NULL_HANDLE; VkPipeline pipeline_ = VK_NULL_HANDLE; VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE; - std::vector<VkDescriptorSetLayout> descriptor_set_layout_; + std::vector<VkDescriptorSetLayout> descriptor_set_layouts_; + std::vector<VkDescriptorPool> descriptor_pools_; + std::vector<VkDescriptorSet> descriptor_sets_; VkDevice device_ = VK_NULL_HANDLE; VkPhysicalDeviceMemoryProperties memory_properties_; std::unique_ptr<CommandBuffer> command_; private: + Result CreatePipelineLayout(); + + Result CreateDescriptorSetLayouts(); + Result CreateDescriptorPools(); + Result CreateDescriptorSets(); + + void DestoryDescriptorSetLayouts(); + void DestoryDescriptorPools(); + PipelineType pipeline_type_; + std::vector<std::unique_ptr<Descriptor>> descriptors_; }; } // namespace vulkan diff --git a/src/vulkan/storage_buffer_descriptor.cc b/src/vulkan/storage_buffer_descriptor.cc new file mode 100644 index 0000000..3202bae --- /dev/null +++ b/src/vulkan/storage_buffer_descriptor.cc @@ -0,0 +1,127 @@ +// Copyright 2018 The Amber Authors. +// +// 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 "src/vulkan/storage_buffer_descriptor.h" + +#include <vector> + +#include "src/make_unique.h" + +namespace amber { +namespace vulkan { +namespace { + +// TODO(jaebaek): Make this as a protected method of Descriptor. +template <typename T> +void SetUintValueForBuffer(void* memory, const std::vector<Value>& values) { + T* ptr = static_cast<T*>(memory); + for (size_t i = 0; i < values.size(); ++i) { + *ptr = static_cast<T>(values[i].AsUint64()); + ++ptr; + } +} + +// TODO(jaebaek): Make this as a protected method of Descriptor. +template <typename T> +void SetFloatValueForBuffer(void* memory, const std::vector<Value>& values) { + T* ptr = static_cast<T*>(memory); + for (size_t i = 0; i < values.size(); ++i) { + *ptr = static_cast<T>(values[i].AsDouble()); + ++ptr; + } +} + +} // namespace + +StorageBufferDescriptor::StorageBufferDescriptor( + VkDevice device, + uint32_t desc_set, + uint32_t binding, + size_t size, + const VkPhysicalDeviceMemoryProperties& properties) + : Descriptor(DescriptorType::kStorageBuffer, device, desc_set, binding), + buffer_(MakeUnique<Buffer>(device, size, properties)) {} + +StorageBufferDescriptor::~StorageBufferDescriptor() = default; + +Result StorageBufferDescriptor::Initialize(DataType type, + const std::vector<Value>& values) { + Result r = buffer_->Initialize(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT); + if (!r.IsSuccess()) + return r; + + switch (type) { + case DataType::kInt8: + case DataType::kUint8: + SetUintValueForBuffer<uint8_t>(buffer_->HostAccessibleMemoryPtr(), + values); + break; + case DataType::kInt16: + case DataType::kUint16: + SetUintValueForBuffer<uint16_t>(buffer_->HostAccessibleMemoryPtr(), + values); + break; + case DataType::kInt32: + case DataType::kUint32: + SetUintValueForBuffer<uint32_t>(buffer_->HostAccessibleMemoryPtr(), + values); + break; + case DataType::kInt64: + case DataType::kUint64: + SetUintValueForBuffer<uint64_t>(buffer_->HostAccessibleMemoryPtr(), + values); + break; + case DataType::kFloat: + SetFloatValueForBuffer<float>(buffer_->HostAccessibleMemoryPtr(), values); + break; + case DataType::kDouble: + SetFloatValueForBuffer<double>(buffer_->HostAccessibleMemoryPtr(), + values); + break; + default: + return Result("StorageBufferDescriptor::Initialize unknown data type"); + } + + return {}; +} + +void StorageBufferDescriptor::SendDataToGPUIfNeeded(VkCommandBuffer command) { + // TODO(jaebaek): VkRunner script allows data updating after initialiation. + // Support updating data. + if (IsDataAlreadySent()) + return; + + buffer_->CopyToDevice(command); + SetDataSent(); +} + +Result StorageBufferDescriptor::UpdateDescriptorSet( + VkDescriptorSet descriptor_set) { + VkDescriptorBufferInfo buffer_info = {}; + buffer_info.buffer = buffer_->GetVkBuffer(); + buffer_info.offset = 0; + buffer_info.range = VK_WHOLE_SIZE; + + return Descriptor::UpdateDescriptorSetForBuffer( + descriptor_set, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, buffer_info); +} + +void StorageBufferDescriptor::Shutdown() { + buffer_->Shutdown(); +} + +} // namespace vulkan +} // namespace amber diff --git a/src/vulkan/storage_buffer_descriptor.h b/src/vulkan/storage_buffer_descriptor.h new file mode 100644 index 0000000..e8af632 --- /dev/null +++ b/src/vulkan/storage_buffer_descriptor.h @@ -0,0 +1,54 @@ +// Copyright 2018 The Amber Authors. +// +// 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. + +#ifndef SRC_VULKAN_STORAGE_BUFFER_DESCRIPTOR_H_ +#define SRC_VULKAN_STORAGE_BUFFER_DESCRIPTOR_H_ + +#include <memory> +#include <vector> + +#include "amber/result.h" +#include "src/datum_type.h" +#include "src/value.h" +#include "src/vulkan/buffer.h" +#include "src/vulkan/descriptor.h" +#include "vulkan/vulkan.h" + +namespace amber { +namespace vulkan { + +class StorageBufferDescriptor : public Descriptor { + public: + StorageBufferDescriptor(VkDevice device, + uint32_t desc_set, + uint32_t binding, + size_t size, + const VkPhysicalDeviceMemoryProperties& properties); + ~StorageBufferDescriptor(); + + Result Initialize(DataType type, const std::vector<Value>& values); + + // Descriptor + void SendDataToGPUIfNeeded(VkCommandBuffer command) override; + Result UpdateDescriptorSet(VkDescriptorSet descriptor_set) override; + void Shutdown() override; + + private: + std::unique_ptr<Buffer> buffer_; +}; + +} // namespace vulkan +} // namespace amber + +#endif // SRC_VULKAN_STORAGE_BUFFER_DESCRIPTOR_H_ diff --git a/tests/cases/ssbo_with_graphics_pipeline.amber b/tests/cases/ssbo_with_graphics_pipeline.amber new file mode 100644 index 0000000..4fb70c9 --- /dev/null +++ b/tests/cases/ssbo_with_graphics_pipeline.amber @@ -0,0 +1,58 @@ +# Copyright 2018 The Amber Authors. +# +# 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 +# +# https://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. + +[vertex shader] +#version 430 + +layout(location = 0) in vec4 position; +layout(location = 1) in vec4 vert_color; +layout(location = 0) out vec4 frag_color; + +layout(set = 0, binding = 0) buffer block1 { + vec4 add_on; +}; + +void main() { + gl_Position = position; + frag_color = vert_color + add_on; +} + +[fragment shader] +#version 430 + +layout(location = 0) in vec4 frag_color; +layout(location = 0) out vec4 final_color; + +void main() { + final_color = frag_color; +} + +[vertex data] +# position vert_color +0/R32G32_SFLOAT 1/R32G32B32A32_SFLOAT + +# R32 G32 R32 G32 B32 B32 + -1.0 -1.0 0.5 0.25 0.125 0 + 1.0 1.0 0.5 0.25 0.125 0 + -1.0 1.0 0.5 0.25 0.125 0 + + -1.0 -1.0 0.5 0.25 0.125 0 + 1.0 1.0 0.5 0.25 0.125 0 + 1.0 -1.0 0.5 0.25 0.125 0 + +[test] +ssbo 0 subdata vec4 0 0.1 0.2 0.3 0.4 +clear +draw arrays TRIANGLE_LIST 0 6 +relative probe rect rgba (0.0, 0.0, 1.0, 1.0) (0.6, 0.45, 0.425, 0.4) |