From 57eaf0b935b7cf4ba1d4ede867c479671718da2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ari=20Suonp=C3=A4=C3=A4?= Date: Fri, 15 May 2020 09:04:18 +0300 Subject: [PATCH 1/3] Add support for uniform/storage texel buffers. --- docs/amber_script.md | 8 +- src/amberscript/parser.cc | 8 +- src/amberscript/parser_bind_test.cc | 272 ++++++++++++++++++++++ src/buffer.h | 8 +- src/command.h | 10 +- src/vulkan/buffer_descriptor.cc | 24 +- src/vulkan/descriptor.cc | 4 + src/vulkan/descriptor.h | 8 + src/vulkan/engine_vulkan.cc | 4 + src/vulkan/pipeline.cc | 37 +-- src/vulkan/transfer_buffer.cc | 31 ++- src/vulkan/transfer_buffer.h | 8 +- tests/cases/draw_storagetexelbuffer.amber | 53 +++++ tests/cases/draw_uniformtexelbuffer.amber | 56 +++++ 14 files changed, 502 insertions(+), 29 deletions(-) create mode 100644 tests/cases/draw_storagetexelbuffer.amber create mode 100644 tests/cases/draw_uniformtexelbuffer.amber diff --git a/docs/amber_script.md b/docs/amber_script.md index dd8a34052..f8925c123 100644 --- a/docs/amber_script.md +++ b/docs/amber_script.md @@ -460,6 +460,8 @@ The following commands are all specified within the `PIPELINE` command. #### Buffer Types * `uniform` * `storage` + * `uniform_texel_buffer` + * `storage_texel_buffer` TODO(dsinclair): Sync the BufferTypes with the list of Vulkan Descriptor types. @@ -492,17 +494,17 @@ contain image attachment content, depth/stencil content, uniform buffers, etc. # Attach |buffer_name| as a storage image. The MIP level will have a base # value of |level|. BIND BUFFER {buffer_name} AS storage_image \ - [ BASE_MIP_LEVEL _level_ (default 0) ] + DESCRIPTOR_SET _id_ BINDING _id_ [ BASE_MIP_LEVEL _level_ (default 0) ] # Attach |buffer_name| as a sampled image. The MIP level will have a base # value of |level|. BIND BUFFER {buffer_name} AS sampled_image \ - [ BASE_MIP_LEVEL _level_ (default 0) ] + DESCRIPTOR_SET _id_ BINDING _id_ [ BASE_MIP_LEVEL _level_ (default 0) ] # Attach |buffer_name| as a combined image sampler. A sampler |sampler_name| # must also be specified. The MIP level will have a base value of 0. BIND BUFFER {buffer_name} AS combined_image_sampler SAMPLER {sampler_name} \ - [ BASE_MIP_LEVEL _level_ (default) 0) ] + DESCRIPTOR_SET _id_ BINDING _id_ [ BASE_MIP_LEVEL _level_ (default) 0) ] # Bind the sampler at the given descriptor set and binding. BIND SAMPLER {sampler_name} DESCRIPTOR_SET _id_ BINDING _id_ diff --git a/src/amberscript/parser.cc b/src/amberscript/parser.cc index f1dbb3578..9c0c21902 100644 --- a/src/amberscript/parser.cc +++ b/src/amberscript/parser.cc @@ -945,6 +945,10 @@ Result Parser::ToBufferType(const std::string& name, BufferType* type) { *type = BufferType::kSampledImage; else if (name == "combined_image_sampler") *type = BufferType::kCombinedImageSampler; + else if (name == "uniform_texel_buffer") + *type = BufferType::kUniformTexelBuffer; + else if (name == "storage_texel_buffer") + *type = BufferType::kStorageTexelBuffer; else return Result("unknown buffer_type: " + name); @@ -1045,7 +1049,9 @@ Result Parser::ParsePipelineBind(Pipeline* pipeline) { buffer_type == BufferType::kUniform || buffer_type == BufferType::kStorageImage || buffer_type == BufferType::kSampledImage || - buffer_type == BufferType::kCombinedImageSampler) { + buffer_type == BufferType::kCombinedImageSampler || + buffer_type == BufferType::kUniformTexelBuffer || + buffer_type == BufferType::kStorageTexelBuffer) { // If the buffer type is known, then we proccessed the AS block above // and have to advance to the next token. Otherwise, we're already on // the next token and don't want to advance. diff --git a/src/amberscript/parser_bind_test.cc b/src/amberscript/parser_bind_test.cc index f027b7065..943b1d951 100644 --- a/src/amberscript/parser_bind_test.cc +++ b/src/amberscript/parser_bind_test.cc @@ -2064,6 +2064,278 @@ END)"; r.Error()); } +TEST_F(AmberScriptParserTest, BindBufferUniformTexelBufferCompute) { + std::string in = R"( +SHADER compute compute_shader GLSL +# GLSL Shader +END + +BUFFER texture FORMAT R8G8B8A8_UNORM + +PIPELINE compute pipeline + ATTACH compute_shader + BIND BUFFER texture AS uniform_texel_buffer DESCRIPTOR_SET 0 BINDING 0 +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_TRUE(r.IsSuccess()) << r.Error(); + + auto script = parser.GetScript(); + const auto& pipelines = script->GetPipelines(); + ASSERT_EQ(1U, pipelines.size()); + + const auto* pipeline = pipelines[0].get(); + const auto& bufs = pipeline->GetBuffers(); + ASSERT_EQ(1U, bufs.size()); + EXPECT_EQ(BufferType::kUniformTexelBuffer, bufs[0].type); +} + +TEST_F(AmberScriptParserTest, BindBufferUniformTexelBufferGraphics) { + std::string in = R"( +SHADER vertex vert_shader PASSTHROUGH +SHADER fragment frag_shader GLSL +# GLSL Shader +END + +BUFFER texture FORMAT R8G8B8A8_UNORM +BUFFER framebuffer FORMAT R8G8B8A8_UNORM + +PIPELINE graphics pipeline + ATTACH vert_shader + ATTACH frag_shader + BIND BUFFER texture AS uniform_texel_buffer DESCRIPTOR_SET 0 BINDING 0 + BIND BUFFER framebuffer AS color LOCATION 0 +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_TRUE(r.IsSuccess()) << r.Error(); + + auto script = parser.GetScript(); + const auto& pipelines = script->GetPipelines(); + ASSERT_EQ(1U, pipelines.size()); + + const auto* pipeline = pipelines[0].get(); + const auto& bufs = pipeline->GetBuffers(); + ASSERT_EQ(1U, bufs.size()); + EXPECT_EQ(BufferType::kUniformTexelBuffer, bufs[0].type); +} + +TEST_F(AmberScriptParserTest, + BindBufferUniformTexelBufferMissingDescriptorSetValue) { + std::string in = R"( +SHADER compute compute_shader GLSL +# GLSL Shader +END + +BUFFER texture FORMAT R8G8B8A8_UNORM + +PIPELINE compute pipeline + ATTACH compute_shader + BIND BUFFER texture AS uniform_texel_buffer DESCRIPTOR_SET BINDING 0 +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("10: invalid value for DESCRIPTOR_SET in BIND command", r.Error()); +} + +TEST_F(AmberScriptParserTest, + BindBufferUniformTexelBufferMissingDescriptorSet) { + std::string in = R"( +SHADER compute compute_shader GLSL +# GLSL Shader +END + +BUFFER texture FORMAT R8G8B8A8_UNORM + +PIPELINE compute pipeline + ATTACH compute_shader + BIND BUFFER texture AS uniform_texel_buffer BINDING 0 +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("10: missing DESCRIPTOR_SET or KERNEL for BIND command", r.Error()); +} + +TEST_F(AmberScriptParserTest, BindBufferUniformTexelBufferMissingBindingValue) { + std::string in = R"( +SHADER compute compute_shader GLSL +# GLSL Shader +END + +BUFFER texture FORMAT R8G8B8A8_UNORM + +PIPELINE compute pipeline + ATTACH compute_shader + BIND BUFFER texture AS uniform_texel_buffer DESCRIPTOR_SET 0 BINDING +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("11: invalid value for BINDING in BIND command", r.Error()); +} + +TEST_F(AmberScriptParserTest, BindBufferUniformTexelBufferMissingBinding) { + std::string in = R"( +SHADER compute compute_shader GLSL +# GLSL Shader +END + +BUFFER texture FORMAT R8G8B8A8_UNORM + +PIPELINE compute pipeline + ATTACH compute_shader + BIND BUFFER texture AS uniform_texel_buffer DESCRIPTOR_SET 0 +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("11: missing BINDING for BIND command", r.Error()); +} + +TEST_F(AmberScriptParserTest, BindBufferStorageTexelBufferCompute) { + std::string in = R"( +SHADER compute compute_shader GLSL +# GLSL Shader +END + +BUFFER texture FORMAT R8G8B8A8_UNORM + +PIPELINE compute pipeline + ATTACH compute_shader + BIND BUFFER texture AS storage_texel_buffer DESCRIPTOR_SET 0 BINDING 0 +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_TRUE(r.IsSuccess()) << r.Error(); + + auto script = parser.GetScript(); + const auto& pipelines = script->GetPipelines(); + ASSERT_EQ(1U, pipelines.size()); + + const auto* pipeline = pipelines[0].get(); + const auto& bufs = pipeline->GetBuffers(); + ASSERT_EQ(1U, bufs.size()); + EXPECT_EQ(BufferType::kStorageTexelBuffer, bufs[0].type); +} + +TEST_F(AmberScriptParserTest, BindBufferStorageTexelBufferGraphics) { + std::string in = R"( +SHADER vertex vert_shader PASSTHROUGH +SHADER fragment frag_shader GLSL +# GLSL Shader +END + +BUFFER texture FORMAT R8G8B8A8_UNORM +BUFFER framebuffer FORMAT R8G8B8A8_UNORM + +PIPELINE graphics pipeline + ATTACH vert_shader + ATTACH frag_shader + BIND BUFFER texture AS storage_texel_buffer DESCRIPTOR_SET 0 BINDING 0 + BIND BUFFER framebuffer AS color LOCATION 0 +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_TRUE(r.IsSuccess()) << r.Error(); + + auto script = parser.GetScript(); + const auto& pipelines = script->GetPipelines(); + ASSERT_EQ(1U, pipelines.size()); + + const auto* pipeline = pipelines[0].get(); + const auto& bufs = pipeline->GetBuffers(); + ASSERT_EQ(1U, bufs.size()); + EXPECT_EQ(BufferType::kStorageTexelBuffer, bufs[0].type); +} + +TEST_F(AmberScriptParserTest, + BindBufferStorageTexelBufferMissingDescriptorSetValue) { + std::string in = R"( +SHADER compute compute_shader GLSL +# GLSL Shader +END + +BUFFER texture FORMAT R8G8B8A8_UNORM + +PIPELINE compute pipeline + ATTACH compute_shader + BIND BUFFER texture AS storage_texel_buffer DESCRIPTOR_SET BINDING 0 +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("10: invalid value for DESCRIPTOR_SET in BIND command", r.Error()); +} + +TEST_F(AmberScriptParserTest, + BindBufferStorageTexelBufferMissingDescriptorSet) { + std::string in = R"( +SHADER compute compute_shader GLSL +# GLSL Shader +END + +BUFFER texture FORMAT R8G8B8A8_UNORM + +PIPELINE compute pipeline + ATTACH compute_shader + BIND BUFFER texture AS storage_texel_buffer BINDING 0 +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("10: missing DESCRIPTOR_SET or KERNEL for BIND command", r.Error()); +} + +TEST_F(AmberScriptParserTest, BindBufferStorageTexelBufferMissingBindingValue) { + std::string in = R"( +SHADER compute compute_shader GLSL +# GLSL Shader +END + +BUFFER texture FORMAT R8G8B8A8_UNORM + +PIPELINE compute pipeline + ATTACH compute_shader + BIND BUFFER texture AS storage_texel_buffer DESCRIPTOR_SET 0 BINDING +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("11: invalid value for BINDING in BIND command", r.Error()); +} + +TEST_F(AmberScriptParserTest, BindBufferStorageTexelBufferMissingBinding) { + std::string in = R"( +SHADER compute compute_shader GLSL +# GLSL Shader +END + +BUFFER texture FORMAT R8G8B8A8_UNORM + +PIPELINE compute pipeline + ATTACH compute_shader + BIND BUFFER texture AS storage_texel_buffer DESCRIPTOR_SET 0 +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("11: missing BINDING for BIND command", r.Error()); +} + TEST_F(AmberScriptParserTest, BindSampler) { std::string in = R"( SHADER vertex vert_shader PASSTHROUGH diff --git a/src/buffer.h b/src/buffer.h index 58c4f2260..49bb627fb 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -53,8 +53,12 @@ enum class BufferType : int8_t { kPushConstant, /// A vertex buffer. kVertex, - /// A storage image - kStorageImage + /// A storage image. + kStorageImage, + /// A uniform texel buffer. + kUniformTexelBuffer, + /// A storage texel buffer. + kStorageTexelBuffer }; /// A buffer stores data. The buffer maybe provided from the input script, or diff --git a/src/command.h b/src/command.h index 1c91e08cc..7fd038d1d 100644 --- a/src/command.h +++ b/src/command.h @@ -493,7 +493,9 @@ class BufferCommand : public BindableResourceCommand { kPushConstant, kStorageImage, kSampledImage, - kCombinedImageSampler + kCombinedImageSampler, + kUniformTexelBuffer, + kStorageTexelBuffer }; BufferCommand(BufferType type, Pipeline* pipeline); @@ -510,6 +512,12 @@ class BufferCommand : public BindableResourceCommand { bool IsCombinedImageSampler() const { return buffer_type_ == BufferType::kCombinedImageSampler; } + bool IsUniformTexelBuffer() const { + return buffer_type_ == BufferType::kUniformTexelBuffer; + } + bool IsStorageTexelBuffer() const { + return buffer_type_ == BufferType::kStorageTexelBuffer; + } bool IsPushConstant() const { return buffer_type_ == BufferType::kPushConstant; } diff --git a/src/vulkan/buffer_descriptor.cc b/src/vulkan/buffer_descriptor.cc index da9821ecf..b96a46c13 100644 --- a/src/vulkan/buffer_descriptor.cc +++ b/src/vulkan/buffer_descriptor.cc @@ -47,12 +47,23 @@ Result BufferDescriptor::CreateResourceIfNeeded() { uint32_t size_in_bytes = amber_buffer ? static_cast(amber_buffer->ValuePtr()->size()) : 0; - transfer_buffer_ = MakeUnique(device_, size_in_bytes); + transfer_buffer_ = MakeUnique( + device_, size_in_bytes, + amber_buffer ? amber_buffer->GetFormat() : nullptr); + VkBufferUsageFlags flags = + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + if (IsUniformBuffer()) { + flags |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + } else if (IsStorageBuffer()) { + flags |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + } else if (IsUniformTexelBuffer()) { + flags |= VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT; + } else { + assert(IsStorageTexelBuffer()); + flags |= VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; + } - Result r = transfer_buffer_->Initialize( - (IsStorageBuffer() ? VK_BUFFER_USAGE_STORAGE_BUFFER_BIT - : VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) | - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); + Result r = transfer_buffer_->Initialize(flags); if (!r.IsSuccess()) return r; @@ -86,6 +97,9 @@ void BufferDescriptor::UpdateDescriptorSetIfNeeded( write.descriptorType = GetVkDescriptorType(); write.pBufferInfo = &buffer_info; + if (IsUniformTexelBuffer() || IsStorageTexelBuffer()) + write.pTexelBufferView = transfer_buffer_->GetVkBufferView(); + device_->GetPtrs()->vkUpdateDescriptorSets(device_->GetVkDevice(), 1, &write, 0, nullptr); is_descriptor_set_update_needed_ = false; diff --git a/src/vulkan/descriptor.cc b/src/vulkan/descriptor.cc index 0ee4ba9f4..15d9fa205 100644 --- a/src/vulkan/descriptor.cc +++ b/src/vulkan/descriptor.cc @@ -44,6 +44,10 @@ VkDescriptorType Descriptor::GetVkDescriptorType() const { return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; case DescriptorType::kCombinedImageSampler: return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + case DescriptorType::kUniformTexelBuffer: + return VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; + case DescriptorType::kStorageTexelBuffer: + return VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; default: assert(type_ == DescriptorType::kSampledImage); return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; diff --git a/src/vulkan/descriptor.h b/src/vulkan/descriptor.h index 0a887e43a..5a8682922 100644 --- a/src/vulkan/descriptor.h +++ b/src/vulkan/descriptor.h @@ -37,6 +37,8 @@ enum class DescriptorType : uint8_t { kStorageImage, kSampledImage, kCombinedImageSampler, + kUniformTexelBuffer, + kStorageTexelBuffer, kSampler }; @@ -65,6 +67,12 @@ class Descriptor { bool IsUniformBuffer() const { return type_ == DescriptorType::kUniformBuffer; } + bool IsUniformTexelBuffer() const { + return type_ == DescriptorType::kUniformTexelBuffer; + } + bool IsStorageTexelBuffer() const { + return type_ == DescriptorType::kStorageTexelBuffer; + } protected: Device* device_ = nullptr; diff --git a/src/vulkan/engine_vulkan.cc b/src/vulkan/engine_vulkan.cc index 41b8e548b..9c638b2db 100644 --- a/src/vulkan/engine_vulkan.cc +++ b/src/vulkan/engine_vulkan.cc @@ -239,6 +239,10 @@ Result EngineVulkan::CreatePipeline(amber::Pipeline* pipeline) { type = BufferCommand::BufferType::kSampledImage; } else if (buf_info.type == BufferType::kCombinedImageSampler) { type = BufferCommand::BufferType::kCombinedImageSampler; + } else if (buf_info.type == BufferType::kUniformTexelBuffer) { + type = BufferCommand::BufferType::kUniformTexelBuffer; + } else if (buf_info.type == BufferType::kStorageTexelBuffer) { + type = BufferCommand::BufferType::kStorageTexelBuffer; } else if (buf_info.type == BufferType::kUniform) { type = BufferCommand::BufferType::kUniform; } else if (buf_info.type != BufferType::kStorage) { diff --git a/src/vulkan/pipeline.cc b/src/vulkan/pipeline.cc index 5804c77f5..fc76567cf 100644 --- a/src/vulkan/pipeline.cc +++ b/src/vulkan/pipeline.cc @@ -279,7 +279,8 @@ Result Pipeline::AddBufferDescriptor(const BufferCommand* cmd) { if (cmd->IsPushConstant()) return AddPushConstantBuffer(cmd->GetBuffer(), cmd->GetOffset()); if (!cmd->IsSSBO() && !cmd->IsUniform() && !cmd->IsStorageImage() && - !cmd->IsSampledImage() && !cmd->IsCombinedImageSampler()) { + !cmd->IsSampledImage() && !cmd->IsCombinedImageSampler() && + !cmd->IsUniformTexelBuffer() && !cmd->IsStorageTexelBuffer()) { return Result("Pipeline::AddBufferDescriptor not supported buffer type"); } @@ -292,25 +293,33 @@ Result Pipeline::AddBufferDescriptor(const BufferCommand* cmd) { auto& descriptors = descriptor_set_info_[cmd->GetDescriptorSet()].descriptors; if (desc == nullptr) { + bool is_image = false; + DescriptorType desc_type = DescriptorType::kUniformBuffer; + if (cmd->IsStorageImage()) { - auto image_desc = MakeUnique( - cmd->GetBuffer(), DescriptorType::kStorageImage, device_, - cmd->GetBaseMipLevel(), cmd->GetDescriptorSet(), cmd->GetBinding()); - descriptors.push_back(std::move(image_desc)); + desc_type = DescriptorType ::kStorageImage; + is_image = true; } else if (cmd->IsSampledImage()) { - auto image_desc = MakeUnique( - cmd->GetBuffer(), DescriptorType::kSampledImage, device_, - cmd->GetBaseMipLevel(), cmd->GetDescriptorSet(), cmd->GetBinding()); - descriptors.push_back(std::move(image_desc)); + desc_type = DescriptorType ::kSampledImage; + is_image = true; } else if (cmd->IsCombinedImageSampler()) { + desc_type = DescriptorType ::kCombinedImageSampler; + is_image = true; + } else if (cmd->IsUniformTexelBuffer()) { + desc_type = DescriptorType ::kUniformTexelBuffer; + } else if (cmd->IsStorageTexelBuffer()) { + desc_type = DescriptorType ::kStorageTexelBuffer; + } else if (cmd->IsSSBO()) { + desc_type = DescriptorType ::kStorageBuffer; + } + if (is_image) { auto image_desc = MakeUnique( - cmd->GetBuffer(), DescriptorType::kCombinedImageSampler, device_, - cmd->GetBaseMipLevel(), cmd->GetDescriptorSet(), cmd->GetBinding()); - image_desc->SetAmberSampler(cmd->GetBuffer()->GetSampler()); + cmd->GetBuffer(), desc_type, device_, cmd->GetBaseMipLevel(), + cmd->GetDescriptorSet(), cmd->GetBinding()); + if (cmd->IsSampledImage() || cmd->IsCombinedImageSampler()) + image_desc->SetAmberSampler(cmd->GetBuffer()->GetSampler()); descriptors.push_back(std::move(image_desc)); } else { - auto desc_type = cmd->IsSSBO() ? DescriptorType::kStorageBuffer - : DescriptorType::kUniformBuffer; auto buffer_desc = MakeUnique( cmd->GetBuffer(), desc_type, device_, cmd->GetDescriptorSet(), cmd->GetBinding()); diff --git a/src/vulkan/transfer_buffer.cc b/src/vulkan/transfer_buffer.cc index 427ee13d5..c59c969bb 100644 --- a/src/vulkan/transfer_buffer.cc +++ b/src/vulkan/transfer_buffer.cc @@ -19,10 +19,20 @@ namespace amber { namespace vulkan { -TransferBuffer::TransferBuffer(Device* device, uint32_t size_in_bytes) - : Resource(device, size_in_bytes) {} +TransferBuffer::TransferBuffer(Device* device, + uint32_t size_in_bytes, + Format* format) + : Resource(device, size_in_bytes) { + if (format) + format_ = device->GetVkFormat(*format); +} TransferBuffer::~TransferBuffer() { + if (view_ != VK_NULL_HANDLE) { + device_->GetPtrs()->vkDestroyBufferView(device_->GetVkDevice(), view_, + nullptr); + } + if (memory_ != VK_NULL_HANDLE) { UnMapMemory(memory_); device_->GetPtrs()->vkFreeMemory(device_->GetVkDevice(), memory_, nullptr); @@ -46,6 +56,23 @@ Result TransferBuffer::Initialize(const VkBufferUsageFlags usage) { if (!r.IsSuccess()) return r; + // Create buffer view + if (usage & (VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | + VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT)) { + VkBufferViewCreateInfo buffer_view_info = VkBufferViewCreateInfo(); + buffer_view_info.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO; + buffer_view_info.buffer = buffer_; + buffer_view_info.format = format_; + buffer_view_info.offset = 0; + buffer_view_info.range = VK_WHOLE_SIZE; + + if (device_->GetPtrs()->vkCreateBufferView(device_->GetVkDevice(), + &buffer_view_info, nullptr, + &view_) != VK_SUCCESS) { + return Result("Vulkan::Calling vkCreateBufferView Fail"); + } + } + if (!device_->IsMemoryHostAccessible(memory_type_index) || !device_->IsMemoryHostCoherent(memory_type_index)) { return Result( diff --git a/src/vulkan/transfer_buffer.h b/src/vulkan/transfer_buffer.h index d608254c6..e8d8a4e34 100644 --- a/src/vulkan/transfer_buffer.h +++ b/src/vulkan/transfer_buffer.h @@ -19,6 +19,7 @@ #include "amber/result.h" #include "amber/vulkan_header.h" +#include "src/format.h" #include "src/vulkan/resource.h" namespace amber { @@ -30,10 +31,13 @@ class Device; /// Wrapper around a Vulkan VkBuffer object. class TransferBuffer : public Resource { public: - TransferBuffer(Device* device, uint32_t size_in_bytes); + TransferBuffer(Device* device, + uint32_t size_in_bytes, + Format* format = nullptr); ~TransferBuffer() override; Result Initialize(const VkBufferUsageFlags usage); + const VkBufferView* GetVkBufferView() const { return &view_; } VkBuffer GetVkBuffer() const { return buffer_; } @@ -47,6 +51,8 @@ class TransferBuffer : public Resource { private: VkBuffer buffer_ = VK_NULL_HANDLE; VkDeviceMemory memory_ = VK_NULL_HANDLE; + VkBufferView view_ = VK_NULL_HANDLE; + VkFormat format_ = VK_FORMAT_UNDEFINED; }; } // namespace vulkan diff --git a/tests/cases/draw_storagetexelbuffer.amber b/tests/cases/draw_storagetexelbuffer.amber new file mode 100644 index 000000000..285c08e79 --- /dev/null +++ b/tests/cases/draw_storagetexelbuffer.amber @@ -0,0 +1,53 @@ +#!amber +# Copyright 2020 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. + +SHADER compute compute_shader GLSL +#version 430 +layout(local_size_x=4,local_size_y=1) in; +uniform layout(set=0, binding=0) samplerBuffer texelsIn; +uniform layout(set=0, binding=1, rgba32f) imageBuffer texelsOut; + +void main () +{ + vec4 color = texelFetch(texelsIn, int(gl_GlobalInvocationID)); + imageStore(texelsOut, int(gl_GlobalInvocationID), color); +} +END + +BUFFER texel_buffer_in DATA_TYPE R8G8B8A8_UNORM DATA +255 0 0 255 + 0 255 0 255 + 0 0 255 255 + 0 255 255 255 +END + +BUFFER texel_buffer_out DATA_TYPE R32G32B32A32_SFLOAT SIZE 4 FILL 0 + +BUFFER ref DATA_TYPE R32G32B32A32_SFLOAT DATA +1.0 0.0 0.0 1.0 +0.0 1.0 0.0 1.0 +0.0 0.0 1.0 1.0 +0.0 1.0 1.0 1.0 +END + +PIPELINE compute pipeline + ATTACH compute_shader + BIND BUFFER texel_buffer_in AS uniform_texel_buffer DESCRIPTOR_SET 0 BINDING 0 + BIND BUFFER texel_buffer_out AS storage_texel_buffer DESCRIPTOR_SET 0 BINDING 1 +END + +RUN pipeline 1 1 1 + +EXPECT texel_buffer_out EQ_BUFFER ref diff --git a/tests/cases/draw_uniformtexelbuffer.amber b/tests/cases/draw_uniformtexelbuffer.amber new file mode 100644 index 000000000..4ece20861 --- /dev/null +++ b/tests/cases/draw_uniformtexelbuffer.amber @@ -0,0 +1,56 @@ +#!amber +# Copyright 2020 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. + +SHADER vertex vert_shader PASSTHROUGH +SHADER fragment frag_shader GLSL +#version 430 +layout(location = 0) out vec4 color_out; +uniform layout(set=0, binding=0) samplerBuffer texels; + +void main() +{ + color_out = texelFetch(texels, int(gl_FragCoord.x) % 4); +} +END + +BUFFER texel_buffer DATA_TYPE R8G8B8A8_UNORM DATA +255 0 0 255 + 0 255 0 255 + 0 0 255 255 + 0 255 255 255 +END + +BUFFER framebuffer FORMAT B8G8R8A8_UNORM + +PIPELINE graphics pipeline + ATTACH vert_shader + ATTACH frag_shader + BIND BUFFER texel_buffer AS uniform_texel_buffer DESCRIPTOR_SET 0 BINDING 0 + FRAMEBUFFER_SIZE 256 256 + BIND BUFFER framebuffer AS color LOCATION 0 +END + +CLEAR_COLOR pipeline 0 0 255 255 +CLEAR pipeline +RUN pipeline DRAW_RECT POS 50 50 SIZE 100 100 + +EXPECT framebuffer IDX 50 50 SIZE 1 100 EQ_RGBA 0 0 255 255 +EXPECT framebuffer IDX 51 50 SIZE 1 100 EQ_RGBA 0 255 255 255 +EXPECT framebuffer IDX 52 50 SIZE 1 100 EQ_RGBA 255 0 0 255 +EXPECT framebuffer IDX 53 50 SIZE 1 100 EQ_RGBA 0 255 0 255 +EXPECT framebuffer IDX 54 50 SIZE 1 100 EQ_RGBA 0 0 255 255 +EXPECT framebuffer IDX 55 50 SIZE 1 100 EQ_RGBA 0 255 255 255 +EXPECT framebuffer IDX 56 50 SIZE 1 100 EQ_RGBA 255 0 0 255 +EXPECT framebuffer IDX 57 50 SIZE 1 100 EQ_RGBA 0 255 0 255 From 3127b5e64d568bd744b4897844e90739603a9003 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ari=20Suonp=C3=A4=C3=A4?= Date: Wed, 20 May 2020 07:47:09 +0300 Subject: [PATCH 2/3] Addressed review comments. --- src/vulkan/buffer_descriptor.cc | 5 +++-- src/vulkan/index_buffer.cc | 2 +- src/vulkan/transfer_buffer.cc | 10 +++------- src/vulkan/transfer_buffer.h | 4 +--- src/vulkan/vertex_buffer.cc | 2 +- 5 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/vulkan/buffer_descriptor.cc b/src/vulkan/buffer_descriptor.cc index b96a46c13..0a6978399 100644 --- a/src/vulkan/buffer_descriptor.cc +++ b/src/vulkan/buffer_descriptor.cc @@ -58,9 +58,10 @@ Result BufferDescriptor::CreateResourceIfNeeded() { flags |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; } else if (IsUniformTexelBuffer()) { flags |= VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT; - } else { - assert(IsStorageTexelBuffer()); + } else if (IsStorageTexelBuffer()) { flags |= VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; + } else { + return Result("Unexpected buffer type when deciding usage flags"); } Result r = transfer_buffer_->Initialize(flags); diff --git a/src/vulkan/index_buffer.cc b/src/vulkan/index_buffer.cc index a86194e36..73a9083cf 100644 --- a/src/vulkan/index_buffer.cc +++ b/src/vulkan/index_buffer.cc @@ -37,7 +37,7 @@ Result IndexBuffer::SendIndexData(CommandBuffer* command, Buffer* buffer) { return Result("IndexBuffer::SendIndexData |buffer| is empty"); transfer_buffer_ = - MakeUnique(device_, buffer->GetSizeInBytes()); + MakeUnique(device_, buffer->GetSizeInBytes(), nullptr); Result r = transfer_buffer_->Initialize(VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); if (!r.IsSuccess()) diff --git a/src/vulkan/transfer_buffer.cc b/src/vulkan/transfer_buffer.cc index c59c969bb..bdc43f466 100644 --- a/src/vulkan/transfer_buffer.cc +++ b/src/vulkan/transfer_buffer.cc @@ -28,19 +28,15 @@ TransferBuffer::TransferBuffer(Device* device, } TransferBuffer::~TransferBuffer() { - if (view_ != VK_NULL_HANDLE) { - device_->GetPtrs()->vkDestroyBufferView(device_->GetVkDevice(), view_, - nullptr); - } + device_->GetPtrs()->vkDestroyBufferView(device_->GetVkDevice(), view_, + nullptr); if (memory_ != VK_NULL_HANDLE) { UnMapMemory(memory_); device_->GetPtrs()->vkFreeMemory(device_->GetVkDevice(), memory_, nullptr); } - if (buffer_ != VK_NULL_HANDLE) - device_->GetPtrs()->vkDestroyBuffer(device_->GetVkDevice(), buffer_, - nullptr); + device_->GetPtrs()->vkDestroyBuffer(device_->GetVkDevice(), buffer_, nullptr); } Result TransferBuffer::Initialize(const VkBufferUsageFlags usage) { diff --git a/src/vulkan/transfer_buffer.h b/src/vulkan/transfer_buffer.h index e8d8a4e34..2c0a51de4 100644 --- a/src/vulkan/transfer_buffer.h +++ b/src/vulkan/transfer_buffer.h @@ -31,9 +31,7 @@ class Device; /// Wrapper around a Vulkan VkBuffer object. class TransferBuffer : public Resource { public: - TransferBuffer(Device* device, - uint32_t size_in_bytes, - Format* format = nullptr); + TransferBuffer(Device* device, uint32_t size_in_bytes, Format* format); ~TransferBuffer() override; Result Initialize(const VkBufferUsageFlags usage); diff --git a/src/vulkan/vertex_buffer.cc b/src/vulkan/vertex_buffer.cc index fe58d665f..402a68b64 100644 --- a/src/vulkan/vertex_buffer.cc +++ b/src/vulkan/vertex_buffer.cc @@ -79,7 +79,7 @@ Result VertexBuffer::SendVertexData(CommandBuffer* command) { uint32_t bytes = Get4BytesAlignedStride() * n_vertices; if (!transfer_buffer_) { - transfer_buffer_ = MakeUnique(device_, bytes); + transfer_buffer_ = MakeUnique(device_, bytes, nullptr); Result r = transfer_buffer_->Initialize(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); if (!r.IsSuccess()) From 0e8326b7310afba0ff624c1b4c965109fff167d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ari=20Suonp=C3=A4=C3=A4?= Date: Wed, 20 May 2020 09:07:51 +0300 Subject: [PATCH 3/3] Fixed unit test compilation and transfer image destruction in vertex buffer tests --- src/vulkan/transfer_buffer.cc | 18 +++++++++++------- src/vulkan/vertex_buffer_test.cc | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/vulkan/transfer_buffer.cc b/src/vulkan/transfer_buffer.cc index bdc43f466..a5fb2d15f 100644 --- a/src/vulkan/transfer_buffer.cc +++ b/src/vulkan/transfer_buffer.cc @@ -28,15 +28,19 @@ TransferBuffer::TransferBuffer(Device* device, } TransferBuffer::~TransferBuffer() { - device_->GetPtrs()->vkDestroyBufferView(device_->GetVkDevice(), view_, - nullptr); + if (device_) { + device_->GetPtrs()->vkDestroyBufferView(device_->GetVkDevice(), view_, + nullptr); - if (memory_ != VK_NULL_HANDLE) { - UnMapMemory(memory_); - device_->GetPtrs()->vkFreeMemory(device_->GetVkDevice(), memory_, nullptr); - } + if (memory_ != VK_NULL_HANDLE) { + UnMapMemory(memory_); + device_->GetPtrs()->vkFreeMemory(device_->GetVkDevice(), memory_, + nullptr); + } - device_->GetPtrs()->vkDestroyBuffer(device_->GetVkDevice(), buffer_, nullptr); + device_->GetPtrs()->vkDestroyBuffer(device_->GetVkDevice(), buffer_, + nullptr); + } } Result TransferBuffer::Initialize(const VkBufferUsageFlags usage) { diff --git a/src/vulkan/vertex_buffer_test.cc b/src/vulkan/vertex_buffer_test.cc index c023d5a93..12bed3a88 100644 --- a/src/vulkan/vertex_buffer_test.cc +++ b/src/vulkan/vertex_buffer_test.cc @@ -30,7 +30,7 @@ namespace { class BufferForTest : public TransferBuffer { public: BufferForTest(Device* device, uint32_t size_in_bytes) - : TransferBuffer(device, size_in_bytes) { + : TransferBuffer(device, size_in_bytes, nullptr) { memory_.resize(4096); SetMemoryPtr(memory_.data()); }