aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaebaek Seo <duke.acacia@gmail.com>2018-11-26 14:37:40 -0500
committerGitHub <noreply@github.com>2018-11-26 14:37:40 -0500
commitda1d01dfca44f24ab1e344f7c531d57735a499ac (patch)
tree0ed84a1470d281119ad2b15659c352839b6be05a
parenteb5fc8cf5d299c180170cc0d3b339d5c4a82c855 (diff)
downloadamber-da1d01dfca44f24ab1e344f7c531d57735a499ac.tar.gz
Vulkan: add SSBO (#63)
Add SSBO and Vulkan objects to use descriptors. Fixes #11
-rw-r--r--src/command.h6
-rw-r--r--src/vkscript/command_parser_test.cc8
-rw-r--r--src/vulkan/CMakeLists.txt1
-rw-r--r--src/vulkan/descriptor.cc90
-rw-r--r--src/vulkan/descriptor.h36
-rw-r--r--src/vulkan/engine_vulkan.cc8
-rw-r--r--src/vulkan/graphics_pipeline.cc14
-rw-r--r--src/vulkan/pipeline.cc210
-rw-r--r--src/vulkan/pipeline.h25
-rw-r--r--src/vulkan/storage_buffer_descriptor.cc127
-rw-r--r--src/vulkan/storage_buffer_descriptor.h54
-rw-r--r--tests/cases/ssbo_with_graphics_pipeline.amber58
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)