aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/vulkan/buffer.cc14
-rw-r--r--src/vulkan/buffer.h8
-rw-r--r--src/vulkan/compute_pipeline.cc14
-rw-r--r--src/vulkan/descriptor.cc18
-rw-r--r--src/vulkan/descriptor.h61
-rw-r--r--src/vulkan/graphics_pipeline.cc18
-rw-r--r--src/vulkan/graphics_pipeline.h1
-rw-r--r--src/vulkan/pipeline.cc48
-rw-r--r--src/vulkan/pipeline.h1
-rw-r--r--src/vulkan/storage_buffer_descriptor.cc131
-rw-r--r--src/vulkan/storage_buffer_descriptor.h15
-rw-r--r--tests/cases/multiple_ssbo_update_with_graphics_pipeline.amber167
12 files changed, 400 insertions, 96 deletions
diff --git a/src/vulkan/buffer.cc b/src/vulkan/buffer.cc
index 6a3cff4..737a8d2 100644
--- a/src/vulkan/buffer.cc
+++ b/src/vulkan/buffer.cc
@@ -18,9 +18,9 @@ namespace amber {
namespace vulkan {
Buffer::Buffer(VkDevice device,
- size_t size,
+ size_t size_in_bytes,
const VkPhysicalDeviceMemoryProperties& properties)
- : Resource(device, size, properties) {}
+ : Resource(device, size_in_bytes, properties) {}
Buffer::~Buffer() = default;
@@ -88,6 +88,16 @@ Result Buffer::CopyToHost(VkCommandBuffer command) {
return {};
}
+void Buffer::CopyFromBuffer(VkCommandBuffer command, const Buffer& src) {
+ VkBufferCopy region = {};
+ region.srcOffset = 0;
+ region.dstOffset = 0;
+ region.size = src.GetSizeInBytes();
+
+ vkCmdCopyBuffer(command, src.buffer_, buffer_, 1, &region);
+ MemoryBarrier(command);
+}
+
void Buffer::Shutdown() {
// TODO(jaebaek): Doublecheck what happens if |view_| is VK_NULL_HANDLE on
// Android and Windows.
diff --git a/src/vulkan/buffer.h b/src/vulkan/buffer.h
index f88d9e1..d3429db 100644
--- a/src/vulkan/buffer.h
+++ b/src/vulkan/buffer.h
@@ -25,7 +25,7 @@ namespace vulkan {
class Buffer : public Resource {
public:
Buffer(VkDevice device,
- size_t size,
+ size_t size_in_bytes,
const VkPhysicalDeviceMemoryProperties& properties);
~Buffer() override;
@@ -60,6 +60,12 @@ class Buffer : public Resource {
// submission must be done later.
Result CopyToHost(VkCommandBuffer command) override;
+ // Copy all data from |src| to |this| and wait until
+ // the memory update is effective by calling vkCmdPipelineBarrier().
+ // Note that this method only records the copy command and the
+ // actual submission of the command must be done later.
+ void CopyFromBuffer(VkCommandBuffer command, const Buffer& src);
+
void Shutdown() override;
private:
diff --git a/src/vulkan/compute_pipeline.cc b/src/vulkan/compute_pipeline.cc
index 4f6f61a..97cb7b9 100644
--- a/src/vulkan/compute_pipeline.cc
+++ b/src/vulkan/compute_pipeline.cc
@@ -60,17 +60,21 @@ Result ComputePipeline::CreateVkComputePipeline() {
}
Result ComputePipeline::Compute(uint32_t x, uint32_t y, uint32_t z) {
+ Result r = command_->BeginIfNotInRecording();
+ if (!r.IsSuccess())
+ return r;
+
+ r = SendDescriptorDataToDeviceIfNeeded();
+ if (!r.IsSuccess())
+ return r;
+
if (pipeline_ == VK_NULL_HANDLE) {
Result r = CreateVkComputePipeline();
if (!r.IsSuccess())
return r;
}
- Result r = command_->BeginIfNotInRecording();
- if (!r.IsSuccess())
- return r;
-
- r = SendDescriptorDataToDeviceIfNeeded();
+ r = UpdateDescriptorSetsIfNeeded();
if (!r.IsSuccess())
return r;
diff --git a/src/vulkan/descriptor.cc b/src/vulkan/descriptor.cc
index bdbbe29..b0cb76c 100644
--- a/src/vulkan/descriptor.cc
+++ b/src/vulkan/descriptor.cc
@@ -92,7 +92,7 @@ Result Descriptor::UpdateDescriptorSetForBuffer(
"buffer");
}
- vkUpdateDescriptorSets(device_, 1, &write, 0, nullptr);
+ UpdateVkDescriptorSet(write);
return {};
}
@@ -115,7 +115,7 @@ Result Descriptor::UpdateDescriptorSetForImage(
"Vulkan::UpdateDescriptorSetForImage not descriptor based on image");
}
- vkUpdateDescriptorSets(device_, 1, &write, 0, nullptr);
+ UpdateVkDescriptorSet(write);
return {};
}
@@ -136,9 +136,21 @@ Result Descriptor::UpdateDescriptorSetForBufferView(
"view");
}
- vkUpdateDescriptorSets(device_, 1, &write, 0, nullptr);
+ UpdateVkDescriptorSet(write);
return {};
}
+void Descriptor::UpdateVkDescriptorSet(const VkWriteDescriptorSet& write) {
+ vkUpdateDescriptorSets(device_, 1, &write, 0, nullptr);
+ is_descriptor_set_update_needed_ = false;
+}
+
+void Descriptor::AddToSSBODataQueue(DataType type,
+ uint32_t offset,
+ size_t size_in_bytes,
+ const std::vector<Value>& values) {
+ ssbo_data_queue_.push_back({type, offset, size_in_bytes, values});
+}
+
} // namespace vulkan
} // namespace amber
diff --git a/src/vulkan/descriptor.h b/src/vulkan/descriptor.h
index 0cf38b0..68e53de 100644
--- a/src/vulkan/descriptor.h
+++ b/src/vulkan/descriptor.h
@@ -16,8 +16,10 @@
#define SRC_VULKAN_DESCRIPTOR_H_
#include <memory>
+#include <vector>
#include "amber/result.h"
+#include "src/datum_type.h"
#include "src/engine.h"
#include "vulkan/vulkan.h"
@@ -40,6 +42,13 @@ enum class DescriptorType : uint8_t {
VkDescriptorType ToVkDescriptorType(DescriptorType type);
+struct SSBOData {
+ DataType type;
+ uint32_t offset;
+ size_t size_in_bytes;
+ std::vector<Value> values;
+};
+
class Descriptor {
public:
Descriptor(DescriptorType type,
@@ -84,10 +93,35 @@ class Descriptor {
return type_ == DescriptorType::kDynamicStorageBuffer;
}
- bool IsDataAlreadySent() { return is_data_already_sent_; }
-
- virtual Result UpdateDescriptorSet(VkDescriptorSet descriptor_set) = 0;
- virtual void SendDataToDeviceIfNeeded(VkCommandBuffer command) = 0;
+ bool HasDataNotSent() { return !ssbo_data_queue_.empty(); }
+
+ void AddToSSBODataQueue(DataType type,
+ uint32_t offset,
+ size_t size_in_bytes,
+ const std::vector<Value>& values);
+
+ // Call vkUpdateDescriptorSets() to update the backing resource
+ // for this descriptor only when the backing resource was newly
+ // created or changed.
+ virtual Result UpdateDescriptorSetIfNeeded(VkDescriptorSet) = 0;
+
+ // Create new vulkan resource if needed i.e., if it was not created
+ // yet or if we need bigger one. If we recreated it for bigger size,
+ // it records the command for copying the old one's data to the new
+ // one. Note that it only records the command and the actual
+ // submission must be done later.
+ virtual Result CreateOrResizeIfNeeded(
+ VkCommandBuffer command,
+ const VkPhysicalDeviceMemoryProperties& properties) = 0;
+
+ // Record a command for copying data in |ssbo_data_queue_| to the
+ // resource. Note that it only records the command and the actual
+ // submission must be done later.
+ virtual void UpdateResourceIfNeeded(VkCommandBuffer command) = 0;
+
+ // Only record the copy command for sending the bound resource
+ // data to the host accessible memory. The actual submission of
+ // the command must be done later.
virtual Result SendDataToHostIfNeeded(VkCommandBuffer command) = 0;
virtual ResourceInfo GetResourceInfo() = 0;
virtual void Shutdown() = 0;
@@ -104,7 +138,20 @@ class Descriptor {
VkDescriptorType descriptor_type,
const VkBufferView& texel_view);
- void SetDataSent() { is_data_already_sent_ = true; }
+ VkDevice GetDevice() const { return device_; }
+
+ const std::vector<SSBOData>& GetSSBODataQueue() const {
+ return ssbo_data_queue_;
+ }
+
+ void ClearSSBODataQueue() { ssbo_data_queue_.clear(); }
+
+ void SetUpdateDescriptorSetNeeded() {
+ is_descriptor_set_update_needed_ = true;
+ }
+ bool IsDescriptorSetUpdateNeeded() {
+ return is_descriptor_set_update_needed_;
+ }
uint32_t descriptor_set_ = 0;
uint32_t binding_ = 0;
@@ -113,10 +160,12 @@ class Descriptor {
VkWriteDescriptorSet GetWriteDescriptorSet(
VkDescriptorSet descriptor_set,
VkDescriptorType descriptor_type) const;
+ void UpdateVkDescriptorSet(const VkWriteDescriptorSet& write);
DescriptorType type_ = DescriptorType::kSampledImage;
- bool is_data_already_sent_ = false;
VkDevice device_ = VK_NULL_HANDLE;
+ std::vector<SSBOData> ssbo_data_queue_;
+ bool is_descriptor_set_update_needed_ = false;
};
} // namespace vulkan
diff --git a/src/vulkan/graphics_pipeline.cc b/src/vulkan/graphics_pipeline.cc
index 57f5df9..b01facb 100644
--- a/src/vulkan/graphics_pipeline.cc
+++ b/src/vulkan/graphics_pipeline.cc
@@ -466,14 +466,24 @@ Result GraphicsPipeline::ClearBuffer(const VkClearValue& clear_value,
}
Result GraphicsPipeline::Draw(const DrawArraysCommand* command) {
+ Result r = command_->BeginIfNotInRecording();
+ if (!r.IsSuccess())
+ return r;
+
+ DeactivateRenderPassIfNeeded();
+
+ r = SendDescriptorDataToDeviceIfNeeded();
+ if (!r.IsSuccess())
+ return r;
+
// TODO(jaebaek): Handle primitive topology.
if (pipeline_ == VK_NULL_HANDLE) {
- Result r = CreateVkGraphicsPipeline(ToVkTopology(command->GetTopology()));
+ r = CreateVkGraphicsPipeline(ToVkTopology(command->GetTopology()));
if (!r.IsSuccess())
return r;
}
- Result r = command_->BeginIfNotInRecording();
+ r = UpdateDescriptorSetsIfNeeded();
if (!r.IsSuccess())
return r;
@@ -481,10 +491,6 @@ Result GraphicsPipeline::Draw(const DrawArraysCommand* command) {
if (!r.IsSuccess())
return r;
- r = SendDescriptorDataToDeviceIfNeeded();
- if (!r.IsSuccess())
- return r;
-
frame_->ChangeFrameImageLayout(command_->GetCommandBuffer(),
FrameImageState::kClearOrDraw);
diff --git a/src/vulkan/graphics_pipeline.h b/src/vulkan/graphics_pipeline.h
index 110d944..2503055 100644
--- a/src/vulkan/graphics_pipeline.h
+++ b/src/vulkan/graphics_pipeline.h
@@ -83,6 +83,7 @@ class GraphicsPipeline : public Pipeline {
void ActivateRenderPassIfNeeded();
void DeactivateRenderPassIfNeeded();
+ // Send vertex and index buffers.
Result SendBufferDataIfNeeded();
// TODO(jaebaek): Implement image/ssbo probe.
diff --git a/src/vulkan/pipeline.cc b/src/vulkan/pipeline.cc
index e252196..291c04f 100644
--- a/src/vulkan/pipeline.cc
+++ b/src/vulkan/pipeline.cc
@@ -213,17 +213,18 @@ Result Pipeline::CreateVkDescriptorRelatedObjects() {
if (!r.IsSuccess())
return r;
- r = CreatePipelineLayout();
- if (!r.IsSuccess())
- return r;
+ return CreatePipelineLayout();
+}
+Result Pipeline::UpdateDescriptorSetsIfNeeded() {
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]);
+ Result r =
+ descriptors_[i]->UpdateDescriptorSetIfNeeded(descriptor_sets_[j]);
if (!r.IsSuccess())
return r;
}
@@ -236,16 +237,27 @@ 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_);
+ Descriptor* desc = nullptr;
+ for (size_t i = 0; i < descriptors_.size(); ++i) {
+ if (descriptors_[i]->GetDescriptorSet() ==
+ buffer_command->GetDescriptorSet() &&
+ descriptors_[i]->GetBinding() == buffer_command->GetBinding()) {
+ desc = descriptors_[i].get();
+ }
+ }
- Result r = ssbo->Initialize(buffer_command->GetDatumType().GetType(),
- buffer_command->GetValues());
- if (!r.IsSuccess())
- return r;
+ if (desc == nullptr) {
+ auto ssbo = MakeUnique<StorageBufferDescriptor>(
+ device_, buffer_command->GetDescriptorSet(),
+ buffer_command->GetBinding());
+ descriptors_.push_back(std::move(ssbo));
+
+ desc = descriptors_.back().get();
+ }
- descriptors_.push_back(std::move(ssbo));
+ desc->AddToSSBODataQueue(
+ buffer_command->GetDatumType().GetType(), buffer_command->GetOffset(),
+ buffer_command->GetSize(), buffer_command->GetValues());
return {};
}
@@ -256,7 +268,7 @@ Result Pipeline::SendDescriptorDataToDeviceIfNeeded() {
bool data_send_needed = false;
for (const auto& desc : descriptors_) {
- if (!desc->IsDataAlreadySent()) {
+ if (desc->HasDataNotSent()) {
data_send_needed = true;
break;
}
@@ -269,8 +281,14 @@ Result Pipeline::SendDescriptorDataToDeviceIfNeeded() {
if (!r.IsSuccess())
return r;
- for (const auto& desc : descriptors_)
- desc->SendDataToDeviceIfNeeded(command_->GetCommandBuffer());
+ for (const auto& desc : descriptors_) {
+ r = desc->CreateOrResizeIfNeeded(command_->GetCommandBuffer(),
+ memory_properties_);
+ if (!r.IsSuccess())
+ return r;
+
+ desc->UpdateResourceIfNeeded(command_->GetCommandBuffer());
+ }
return {};
}
diff --git a/src/vulkan/pipeline.h b/src/vulkan/pipeline.h
index a8b5dde..490723e 100644
--- a/src/vulkan/pipeline.h
+++ b/src/vulkan/pipeline.h
@@ -67,6 +67,7 @@ class Pipeline {
const std::vector<VkPipelineShaderStageCreateInfo>& shader_stage_info);
Result InitializeCommandBuffer(VkCommandPool pool, VkQueue queue);
Result CreateVkDescriptorRelatedObjects();
+ Result UpdateDescriptorSetsIfNeeded();
Result SendDescriptorDataToDeviceIfNeeded();
void BindVkPipeline();
diff --git a/src/vulkan/storage_buffer_descriptor.cc b/src/vulkan/storage_buffer_descriptor.cc
index f8a7c15..b08ae70 100644
--- a/src/vulkan/storage_buffer_descriptor.cc
+++ b/src/vulkan/storage_buffer_descriptor.cc
@@ -14,6 +14,8 @@
#include "src/vulkan/storage_buffer_descriptor.h"
+#include <algorithm>
+#include <utility>
#include <vector>
#include "src/engine.h"
@@ -25,89 +27,115 @@ namespace {
// TODO(jaebaek): Make this as a protected method of Descriptor.
template <typename T>
-void SetUintValueForBuffer(void* memory, const std::vector<Value>& values) {
+void SetValueForBuffer(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());
+ for (const auto& v : values) {
+ *ptr = static_cast<T>(v.IsInteger() ? v.AsUint64() : v.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(VkDevice device,
+ uint32_t desc_set,
+ uint32_t binding)
+ : Descriptor(DescriptorType::kStorageBuffer, device, desc_set, binding) {}
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) {
+// TODO(jaebaek): Add unittests for this method.
+void StorageBufferDescriptor::FillBufferWithData(const SSBOData& data) {
+ uint8_t* ptr =
+ static_cast<uint8_t*>(buffer_->HostAccessibleMemoryPtr()) + data.offset;
+ switch (data.type) {
case DataType::kInt8:
case DataType::kUint8:
- SetUintValueForBuffer<uint8_t>(buffer_->HostAccessibleMemoryPtr(),
- values);
+ SetValueForBuffer<uint8_t>(ptr, data.values);
break;
case DataType::kInt16:
case DataType::kUint16:
- SetUintValueForBuffer<uint16_t>(buffer_->HostAccessibleMemoryPtr(),
- values);
+ SetValueForBuffer<uint16_t>(ptr, data.values);
break;
case DataType::kInt32:
case DataType::kUint32:
- SetUintValueForBuffer<uint32_t>(buffer_->HostAccessibleMemoryPtr(),
- values);
+ SetValueForBuffer<uint32_t>(ptr, data.values);
break;
case DataType::kInt64:
case DataType::kUint64:
- SetUintValueForBuffer<uint64_t>(buffer_->HostAccessibleMemoryPtr(),
- values);
+ SetValueForBuffer<uint64_t>(ptr, data.values);
break;
case DataType::kFloat:
- SetFloatValueForBuffer<float>(buffer_->HostAccessibleMemoryPtr(), values);
+ SetValueForBuffer<float>(ptr, data.values);
break;
case DataType::kDouble:
- SetFloatValueForBuffer<double>(buffer_->HostAccessibleMemoryPtr(),
- values);
+ SetValueForBuffer<double>(ptr, data.values);
break;
- default:
- return Result("StorageBufferDescriptor::Initialize unknown data type");
+ }
+}
+
+Result StorageBufferDescriptor::CreateOrResizeIfNeeded(
+ VkCommandBuffer command,
+ const VkPhysicalDeviceMemoryProperties& properties) {
+ const auto& ssbo_data_queue = GetSSBODataQueue();
+
+ if (ssbo_data_queue.empty())
+ return {};
+
+ auto ssbo_data_with_last_offset = std::max_element(
+ ssbo_data_queue.begin(), ssbo_data_queue.end(),
+ [](const SSBOData& a, const SSBOData& b) {
+ return static_cast<size_t>(a.offset) + a.size_in_bytes <
+ static_cast<size_t>(b.offset) + b.size_in_bytes;
+ });
+ size_t new_size_in_bytes =
+ static_cast<size_t>(ssbo_data_with_last_offset->offset) +
+ ssbo_data_with_last_offset->size_in_bytes;
+
+ if (!buffer_) {
+ // Create buffer
+ buffer_ = MakeUnique<Buffer>(GetDevice(), new_size_in_bytes, properties);
+
+ 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;
+
+ SetUpdateDescriptorSetNeeded();
+ } else if (buffer_->GetSizeInBytes() < new_size_in_bytes) {
+ // Resize buffer
+ auto new_buffer =
+ MakeUnique<Buffer>(GetDevice(), new_size_in_bytes, properties);
+
+ Result r = new_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;
+
+ new_buffer->CopyFromBuffer(command, *buffer_);
+
+ buffer_ = std::move(new_buffer);
+
+ SetUpdateDescriptorSetNeeded();
}
return {};
}
-void StorageBufferDescriptor::SendDataToDeviceIfNeeded(
- VkCommandBuffer command) {
- // TODO(jaebaek): VkRunner script allows data updating after initialiation.
- // Support updating data.
- if (IsDataAlreadySent())
+void StorageBufferDescriptor::UpdateResourceIfNeeded(VkCommandBuffer command) {
+ const auto& ssbo_data_queue = GetSSBODataQueue();
+
+ if (ssbo_data_queue.empty())
return;
+ for (const auto& data : ssbo_data_queue) {
+ FillBufferWithData(data);
+ }
+ ClearSSBODataQueue();
+
buffer_->CopyToDevice(command);
- SetDataSent();
}
Result StorageBufferDescriptor::SendDataToHostIfNeeded(
@@ -115,8 +143,11 @@ Result StorageBufferDescriptor::SendDataToHostIfNeeded(
return buffer_->CopyToHost(command);
}
-Result StorageBufferDescriptor::UpdateDescriptorSet(
+Result StorageBufferDescriptor::UpdateDescriptorSetIfNeeded(
VkDescriptorSet descriptor_set) {
+ if (!IsDescriptorSetUpdateNeeded())
+ return {};
+
VkDescriptorBufferInfo buffer_info = {};
buffer_info.buffer = buffer_->GetVkBuffer();
buffer_info.offset = 0;
diff --git a/src/vulkan/storage_buffer_descriptor.h b/src/vulkan/storage_buffer_descriptor.h
index a30bcd5..8fa5bde 100644
--- a/src/vulkan/storage_buffer_descriptor.h
+++ b/src/vulkan/storage_buffer_descriptor.h
@@ -31,19 +31,18 @@ namespace vulkan {
class StorageBufferDescriptor : public Descriptor {
public:
- StorageBufferDescriptor(VkDevice device,
- uint32_t desc_set,
- uint32_t binding,
- size_t size,
- const VkPhysicalDeviceMemoryProperties& properties);
+ StorageBufferDescriptor(VkDevice device, uint32_t desc_set, uint32_t binding);
~StorageBufferDescriptor();
- Result Initialize(DataType type, const std::vector<Value>& values);
+ void FillBufferWithData(const SSBOData& data);
// Descriptor
- void SendDataToDeviceIfNeeded(VkCommandBuffer command) override;
+ Result CreateOrResizeIfNeeded(
+ VkCommandBuffer command,
+ const VkPhysicalDeviceMemoryProperties& properties) override;
+ void UpdateResourceIfNeeded(VkCommandBuffer command) override;
Result SendDataToHostIfNeeded(VkCommandBuffer command) override;
- Result UpdateDescriptorSet(VkDescriptorSet descriptor_set) override;
+ Result UpdateDescriptorSetIfNeeded(VkDescriptorSet descriptor_set) override;
ResourceInfo GetResourceInfo() override;
void Shutdown() override;
diff --git a/tests/cases/multiple_ssbo_update_with_graphics_pipeline.amber b/tests/cases/multiple_ssbo_update_with_graphics_pipeline.amber
new file mode 100644
index 0000000..6205b30
--- /dev/null
+++ b/tests/cases/multiple_ssbo_update_with_graphics_pipeline.amber
@@ -0,0 +1,167 @@
+# 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 block0 {
+ vec4 addon0;
+ vec4 addon1;
+};
+
+layout(set = 1, binding = 0) buffer block1 {
+ float data_set1_binding0[11];
+ float data_set1_binding0_result[11];
+};
+
+layout(set = 1, binding = 2) buffer block2 {
+ float data_set1_binding2[11];
+ float data_set1_binding2_result[11];
+};
+
+layout(set = 2, binding = 1) buffer block3 {
+ float data_set2_binding1[11];
+ float data_set2_binding1_result[11];
+};
+
+layout(set = 2, binding = 3) buffer block4 {
+ float data_set2_binding3[11];
+ float data_set2_binding3_result[11];
+};
+
+void main() {
+ gl_Position = position;
+ frag_color = vert_color + (addon0 + addon1) / 2.0f;
+
+ for (int i = 0; i < 11; ++i) {
+ data_set1_binding0_result[i] = data_set1_binding2[i];
+ data_set1_binding2_result[i] = data_set2_binding1[i];
+ data_set2_binding1_result[i] = data_set2_binding3[i];
+ data_set2_binding3_result[i] = data_set1_binding0[i];
+ }
+}
+
+[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]
+clear
+
+ssbo 0 subdata vec4 0 0.1 0.2 0.3 0.4
+ssbo 0 subdata vec4 16 0.9 0.8 0.7 0.6
+
+ssbo 1:0 subdata vec4 0 0.1 0.2 0.3 0.4
+ssbo 1:2 subdata vec4 0 0.1 0.2 0.3 0.4
+ssbo 2:1 subdata vec4 0 0.1 0.2 0.3 0.4
+ssbo 2:3 subdata vec4 0 0.1 0.2 0.3 0.4
+
+draw arrays TRIANGLE_LIST 0 6
+relative probe rect rgba (0.0, 0.0, 1.0, 1.0) (1.0, 0.75, 0.625, 0.5)
+
+
+
+ssbo 0 subdata vec4 0 0.5 0.5 0.25 1.0 \
+ 0.3 0.2 0.1 0.4 \
+ 0 0 0 0
+
+ssbo 1:0 subdata float 0 0.1 0.2 0.3 0.4 \
+ 0.5 0.6 0.7 0.8 \
+ 0.9 0.10 0.11 \
+ 0.1 0.2 0.3 0.4 \
+ 0.5 0.6 0.7 0.8 \
+ 0.9 0.10 0.11
+
+ssbo 1:2 subdata float 0 0.57 0.56 0.55 0.54 \
+ 0.53 0.52 0.51 0.50 \
+ 0.49 0.48 0.47 \
+ 0.57 0.56 0.55 0.54 \
+ 0.53 0.52 0.51 0.50 \
+ 0.49 0.48 0.47
+
+ssbo 2:1 subdata float 0 0.21 0.22 0.23 0.24 \
+ 0.25 0.26 0.27 0.28 \
+ 0.29 0.30 0.31 \
+ 0.21 0.22 0.23 0.24 \
+ 0.25 0.26 0.27 0.28 \
+ 0.29 0.30 0.31
+
+ssbo 2:3 subdata float 0 0.23 0.229 0.228 0.227 \
+ 0.226 0.225 0.224 0.223 \
+ 0.222 0.221 0.22 \
+ 0.23 0.229 0.228 0.227 \
+ 0.226 0.225 0.224 0.223 \
+ 0.222 0.221 0.22
+
+draw arrays TRIANGLE_LIST 0 6
+relative probe rect rgba (0.0, 0.0, 1.0, 1.0) (0.9, 0.6, 0.3, 0.7)
+
+probe ssbo float 1:0 0 ~= 0.1 0.2 0.3 0.4 \
+ 0.5 0.6 0.7 0.8 \
+ 0.9 0.10 0.11
+probe ssbo float 1:0 44 ~= 0.57 0.56 0.55 0.54 \
+ 0.53 0.52 0.51 0.50 \
+ 0.49 0.48 0.47
+
+probe ssbo float 1:2 0 ~= 0.57 0.56 0.55 0.54 \
+ 0.53 0.52 0.51 0.50 \
+ 0.49 0.48 0.47
+probe ssbo float 1:2 44 ~= 0.21 0.22 0.23 0.24 \
+ 0.25 0.26 0.27 0.28 \
+ 0.29 0.30 0.31
+
+probe ssbo float 2:1 0 ~= 0.21 0.22 0.23 0.24 \
+ 0.25 0.26 0.27 0.28 \
+ 0.29 0.30 0.31
+probe ssbo float 2:1 44 ~= 0.23 0.229 0.228 0.227 \
+ 0.226 0.225 0.224 0.223 \
+ 0.222 0.221 0.22
+
+probe ssbo float 2:3 0 ~= 0.23 0.229 0.228 0.227 \
+ 0.226 0.225 0.224 0.223 \
+ 0.222 0.221 0.22
+probe ssbo float 2:3 44 ~= 0.1 0.2 0.3 0.4 \
+ 0.5 0.6 0.7 0.8 \
+ 0.9 0.10 0.11
+
+
+
+ssbo 0 subdata float 8 \
+0.35 0.6 \
+0.1 0.4
+draw arrays TRIANGLE_LIST 0 6
+relative probe rect rgba (0.0, 0.0, 1.0, 1.0) (0.8, 0.7, 0.35, 0.5)