diff options
-rw-r--r-- | src/vulkan/buffer.cc | 14 | ||||
-rw-r--r-- | src/vulkan/buffer.h | 8 | ||||
-rw-r--r-- | src/vulkan/compute_pipeline.cc | 14 | ||||
-rw-r--r-- | src/vulkan/descriptor.cc | 18 | ||||
-rw-r--r-- | src/vulkan/descriptor.h | 61 | ||||
-rw-r--r-- | src/vulkan/graphics_pipeline.cc | 18 | ||||
-rw-r--r-- | src/vulkan/graphics_pipeline.h | 1 | ||||
-rw-r--r-- | src/vulkan/pipeline.cc | 48 | ||||
-rw-r--r-- | src/vulkan/pipeline.h | 1 | ||||
-rw-r--r-- | src/vulkan/storage_buffer_descriptor.cc | 131 | ||||
-rw-r--r-- | src/vulkan/storage_buffer_descriptor.h | 15 | ||||
-rw-r--r-- | tests/cases/multiple_ssbo_update_with_graphics_pipeline.amber | 167 |
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, ®ion); + 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) |