diff options
author | Jaebaek Seo <duke.acacia@gmail.com> | 2018-12-01 23:47:57 -0500 |
---|---|---|
committer | David Neto <dneto@google.com> | 2018-12-01 23:47:57 -0500 |
commit | c244ec886ce0775f92664e89b285b6bdae44a593 (patch) | |
tree | b0b7985f670075674d32a7e38505e8186803cefd | |
parent | df01fbd43429ab383525b72882ee907ef4b46340 (diff) | |
download | amber-c244ec886ce0775f92664e89b285b6bdae44a593.tar.gz |
Vulkan: handle probe ssbo command (#101)
Vulkan: handle probe ssbo command
Related to #32
-rw-r--r-- | src/dawn/find_dawn.cmake | 3 | ||||
-rw-r--r-- | src/vulkan/buffer.cc | 55 | ||||
-rw-r--r-- | src/vulkan/buffer.h | 23 | ||||
-rw-r--r-- | src/vulkan/compute_pipeline.cc | 2 | ||||
-rw-r--r-- | src/vulkan/descriptor.h | 5 | ||||
-rw-r--r-- | src/vulkan/engine_vulkan.cc | 14 | ||||
-rw-r--r-- | src/vulkan/frame_buffer.h | 4 | ||||
-rw-r--r-- | src/vulkan/graphics_pipeline.cc | 2 | ||||
-rw-r--r-- | src/vulkan/image.cc | 8 | ||||
-rw-r--r-- | src/vulkan/image.h | 12 | ||||
-rw-r--r-- | src/vulkan/pipeline.cc | 42 | ||||
-rw-r--r-- | src/vulkan/pipeline.h | 12 | ||||
-rw-r--r-- | src/vulkan/resource.cc | 8 | ||||
-rw-r--r-- | src/vulkan/resource.h | 17 | ||||
-rw-r--r-- | src/vulkan/storage_buffer_descriptor.cc | 17 | ||||
-rw-r--r-- | src/vulkan/storage_buffer_descriptor.h | 5 | ||||
-rw-r--r-- | tests/cases/compute_ssbo.amber | 54 |
17 files changed, 242 insertions, 41 deletions
diff --git a/src/dawn/find_dawn.cmake b/src/dawn/find_dawn.cmake index 5222408..40d4158 100644 --- a/src/dawn/find_dawn.cmake +++ b/src/dawn/find_dawn.cmake @@ -39,7 +39,8 @@ set(Dawn_FOUND FALSE) # # -DDawn_INCLUDE_DIR=<directory containing dawn/dawn_export.h> # -DDawn_GEN_INCLUDE_DIR=<directory containing dawn/dawn.h> -# -DDawn_LIBRARY_DIR=<directory containing dawn_native> +# -DDawn_LIBRARY_DIR=<directory containing dawn_native library +# e.g., libdawn_native.a> find_path(Dawn_INCLUDE_DIR diff --git a/src/vulkan/buffer.cc b/src/vulkan/buffer.cc index d71d4bb..bb4ac0b 100644 --- a/src/vulkan/buffer.cc +++ b/src/vulkan/buffer.cc @@ -34,8 +34,10 @@ Result Buffer::Initialize(const VkBufferUsageFlags usage) { if (!allocate_result.r.IsSuccess()) return allocate_result.r; - if (CheckMemoryHostAccessible(allocate_result.memory_type_index)) { + if (IsMemoryHostAccessible(allocate_result.memory_type_index)) { is_buffer_host_accessible_ = true; + is_buffer_host_coherent_ = + IsMemoryHostCoherent(allocate_result.memory_type_index); return MapMemory(memory_); } @@ -58,17 +60,32 @@ Result Buffer::CreateVkBufferView(VkFormat format) { return {}; } -void Buffer::CopyToDevice(VkCommandBuffer command) { +Result Buffer::CopyToDevice(VkCommandBuffer command) { if (is_buffer_host_accessible_) - return; + return FlushMemoryIfNeeded(); VkBufferCopy region = {}; region.srcOffset = 0; region.dstOffset = 0; - region.size = GetSize(); + region.size = GetSizeInBytes(); vkCmdCopyBuffer(command, GetHostAccessibleBuffer(), buffer_, 1, ®ion); MemoryBarrier(command); + return {}; +} + +Result Buffer::CopyToHost(VkCommandBuffer command) { + if (is_buffer_host_accessible_) + return InvalidateMemoryIfNeeded(); + + VkBufferCopy region = {}; + region.srcOffset = 0; + region.dstOffset = 0; + region.size = GetSizeInBytes(); + + vkCmdCopyBuffer(command, buffer_, GetHostAccessibleBuffer(), 1, ®ion); + MemoryBarrier(command); + return {}; } void Buffer::Shutdown() { @@ -90,5 +107,35 @@ void Buffer::Shutdown() { } } +Result Buffer::InvalidateMemoryIfNeeded() { + if (is_buffer_host_coherent_) + return {}; + + VkMappedMemoryRange range = {}; + range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; + range.memory = GetHostAccessMemory(); + range.offset = 0; + range.size = VK_WHOLE_SIZE; + if (vkInvalidateMappedMemoryRanges(GetDevice(), 1, &range) != VK_SUCCESS) + return Result("Vulkan: vkInvalidateMappedMemoryRanges fail"); + + return {}; +} + +Result Buffer::FlushMemoryIfNeeded() { + if (is_buffer_host_coherent_) + return {}; + + VkMappedMemoryRange range = {}; + range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; + range.memory = GetHostAccessMemory(); + range.offset = 0; + range.size = VK_WHOLE_SIZE; + if (vkFlushMappedMemoryRanges(GetDevice(), 1, &range) != VK_SUCCESS) + return Result("Vulkan: vkFlushMappedMemoryRanges fail"); + + return {}; +} + } // namespace vulkan } // namespace amber diff --git a/src/vulkan/buffer.h b/src/vulkan/buffer.h index 9ec1dd2..f88d9e1 100644 --- a/src/vulkan/buffer.h +++ b/src/vulkan/buffer.h @@ -34,8 +34,14 @@ class Buffer : public Resource { Result CreateVkBufferView(VkFormat format); VkBufferView GetVkBufferView() const { return view_; } - // TODO(jaebaek): Determine copy all or partial data - void CopyToDevice(VkCommandBuffer command); + // If this buffer is host accessible and has coherent memory, this + // method does nothing. If this buffer is host accessible but it does + // not have coherent memory, this method flush the memory to make the + // writes from host effective to device. Otherwise, this method records + // the command for copying the secondary host-accessible buffer to + // this device local buffer. Note that it only records the command and + // the actual submission must be done later. + Result CopyToDevice(VkCommandBuffer command); // Resource VkDeviceMemory GetHostAccessMemory() const override { @@ -45,13 +51,26 @@ class Buffer : public Resource { return Resource::GetHostAccessMemory(); } + // If this buffer is host accessible and has coherent memory, this + // method does nothing. If this buffer is host accessible but it does + // not have coherent memory, this method invalidate the memory to make the + // writes from device visible to host. Otherwise, this method records + // the command for copying this buffer to its secondary host-accessible + // buffer. Note that it only records the command and the actual + // submission must be done later. + Result CopyToHost(VkCommandBuffer command) override; + void Shutdown() override; private: + Result InvalidateMemoryIfNeeded(); + Result FlushMemoryIfNeeded(); + VkBuffer buffer_ = VK_NULL_HANDLE; VkBufferView view_ = VK_NULL_HANDLE; VkDeviceMemory memory_ = VK_NULL_HANDLE; bool is_buffer_host_accessible_ = false; + bool is_buffer_host_coherent_ = false; }; } // namespace vulkan diff --git a/src/vulkan/compute_pipeline.cc b/src/vulkan/compute_pipeline.cc index a4f94f6..4f6f61a 100644 --- a/src/vulkan/compute_pipeline.cc +++ b/src/vulkan/compute_pipeline.cc @@ -70,7 +70,7 @@ Result ComputePipeline::Compute(uint32_t x, uint32_t y, uint32_t z) { if (!r.IsSuccess()) return r; - r = SendDescriptorDataToGPUIfNeeded(); + r = SendDescriptorDataToDeviceIfNeeded(); if (!r.IsSuccess()) return r; diff --git a/src/vulkan/descriptor.h b/src/vulkan/descriptor.h index eb70001..0cf38b0 100644 --- a/src/vulkan/descriptor.h +++ b/src/vulkan/descriptor.h @@ -18,6 +18,7 @@ #include <memory> #include "amber/result.h" +#include "src/engine.h" #include "vulkan/vulkan.h" namespace amber { @@ -86,7 +87,9 @@ class Descriptor { bool IsDataAlreadySent() { return is_data_already_sent_; } virtual Result UpdateDescriptorSet(VkDescriptorSet descriptor_set) = 0; - virtual void SendDataToGPUIfNeeded(VkCommandBuffer command) = 0; + virtual void SendDataToDeviceIfNeeded(VkCommandBuffer command) = 0; + virtual Result SendDataToHostIfNeeded(VkCommandBuffer command) = 0; + virtual ResourceInfo GetResourceInfo() = 0; virtual void Shutdown() = 0; protected: diff --git a/src/vulkan/engine_vulkan.cc b/src/vulkan/engine_vulkan.cc index bdcd786..d546761 100644 --- a/src/vulkan/engine_vulkan.cc +++ b/src/vulkan/engine_vulkan.cc @@ -297,10 +297,16 @@ Result EngineVulkan::GetFrameBufferInfo(ResourceInfo* info) { return {}; } -Result EngineVulkan::GetDescriptorInfo(const uint32_t, - const uint32_t, - ResourceInfo*) { - return Result("EngineVulkan::GetDescriptorInfo not implemented"); +Result EngineVulkan::GetDescriptorInfo(const uint32_t descriptor_set, + const uint32_t binding, + ResourceInfo* info) { + assert(info); + Result r = pipeline_->CopyDescriptorToHost(descriptor_set, binding); + if (!r.IsSuccess()) + return r; + + pipeline_->GetDescriptorInfo(descriptor_set, binding, info); + return {}; } Result EngineVulkan::DoBuffer(const BufferCommand* command) { diff --git a/src/vulkan/frame_buffer.h b/src/vulkan/frame_buffer.h index bfee4c3..7e3a214 100644 --- a/src/vulkan/frame_buffer.h +++ b/src/vulkan/frame_buffer.h @@ -47,6 +47,10 @@ class FrameBuffer { return color_image_->HostAccessibleMemoryPtr(); } VkImage GetColorImage() const { return color_image_->GetVkImage(); } + + // Only record the command for copying the image that backs this + // framebuffer to the host accessible buffer. The actual submission + // of the command must be done later. Result CopyColorImageToHost(VkCommandBuffer command) { ChangeFrameImageLayout(command, FrameImageState::kProbe); return color_image_->CopyToHost(command); diff --git a/src/vulkan/graphics_pipeline.cc b/src/vulkan/graphics_pipeline.cc index c9c9eed..1c182be 100644 --- a/src/vulkan/graphics_pipeline.cc +++ b/src/vulkan/graphics_pipeline.cc @@ -481,7 +481,7 @@ Result GraphicsPipeline::Draw(const DrawArraysCommand* command) { if (!r.IsSuccess()) return r; - r = SendDescriptorDataToGPUIfNeeded(); + r = SendDescriptorDataToDeviceIfNeeded(); if (!r.IsSuccess()) return r; diff --git a/src/vulkan/image.cc b/src/vulkan/image.cc index 0e0f588..87f9c05 100644 --- a/src/vulkan/image.cc +++ b/src/vulkan/image.cc @@ -79,7 +79,6 @@ Result Image::Initialize(VkImageUsageFlags usage) { // is optimal, read/write data from CPU does not show correct values. We need // a secondary buffer to convert the GPU-optimial data to CPU-readable data // and vice versa. - is_image_host_accessible_ = false; return Resource::Initialize(); } @@ -123,9 +122,6 @@ void Image::Shutdown() { } Result Image::CopyToHost(VkCommandBuffer command) { - if (is_image_host_accessible_) - return {}; - VkBufferImageCopy copy_region = {}; copy_region.bufferOffset = 0; copy_region.bufferRowLength = 0; @@ -206,10 +202,6 @@ void Image::ChangeLayout(VkCommandBuffer command, break; case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - // An image becomes "host readable transfer src" only when we directly - // probe it from CPU. - if (is_image_host_accessible_) - barrier.dstAccessMask |= VK_ACCESS_HOST_READ_BIT; break; case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: // An image becomes "transfer dst" only when we send a buffer data to diff --git a/src/vulkan/image.h b/src/vulkan/image.h index 36186a2..4668f71 100644 --- a/src/vulkan/image.h +++ b/src/vulkan/image.h @@ -36,9 +36,6 @@ class Image : public Resource { VkImage GetVkImage() const { return image_; } VkImageView GetVkImageView() const { return view_; } - // TODO(jaebaek): Determine copy all or partial data - Result CopyToHost(VkCommandBuffer command); - // TODO(jaebaek): Implement CopyToDevice void ChangeLayout(VkCommandBuffer command, @@ -49,12 +46,14 @@ class Image : public Resource { // Resource VkDeviceMemory GetHostAccessMemory() const override { - if (is_image_host_accessible_) - return memory_; - return Resource::GetHostAccessMemory(); } + // Only record the command for copying this image to its secondary + // host-accessible buffer. The actual submission of the command + // must be done later. + Result CopyToHost(VkCommandBuffer command) override; + void Shutdown() override; private: @@ -65,7 +64,6 @@ class Image : public Resource { VkImage image_ = VK_NULL_HANDLE; VkImageView view_ = VK_NULL_HANDLE; VkDeviceMemory memory_ = VK_NULL_HANDLE; - bool is_image_host_accessible_ = false; }; } // namespace vulkan diff --git a/src/vulkan/pipeline.cc b/src/vulkan/pipeline.cc index 5050ea0..89d357a 100644 --- a/src/vulkan/pipeline.cc +++ b/src/vulkan/pipeline.cc @@ -15,10 +15,12 @@ #include "src/vulkan/pipeline.h" #include <algorithm> +#include <cassert> #include <limits> #include <utility> #include "src/command.h" +#include "src/engine.h" #include "src/make_unique.h" #include "src/vulkan/compute_pipeline.h" #include "src/vulkan/graphics_pipeline.h" @@ -247,7 +249,7 @@ Result Pipeline::AddDescriptor(const BufferCommand* buffer_command) { return {}; } -Result Pipeline::SendDescriptorDataToGPUIfNeeded() { +Result Pipeline::SendDescriptorDataToDeviceIfNeeded() { if (descriptors_.size() == 0) return {}; @@ -267,7 +269,7 @@ Result Pipeline::SendDescriptorDataToGPUIfNeeded() { return r; for (const auto& desc : descriptors_) - desc->SendDataToGPUIfNeeded(command_->GetCommandBuffer()); + desc->SendDataToDeviceIfNeeded(command_->GetCommandBuffer()); return {}; } @@ -287,5 +289,41 @@ void Pipeline::BindVkPipeline() { pipeline_); } +Result Pipeline::CopyDescriptorToHost(const uint32_t descriptor_set, + const uint32_t binding) { + Result r = command_->BeginIfNotInRecording(); + if (!r.IsSuccess()) + return r; + + for (size_t i = 0; i < descriptors_.size(); ++i) { + if (descriptors_[i]->GetDescriptorSet() == descriptor_set && + descriptors_[i]->GetBinding() == binding) { + return descriptors_[i]->SendDataToHostIfNeeded( + command_->GetCommandBuffer()); + } + } + + return Result("Vulkan::Pipeline descriptor with descriptor set: " + + std::to_string(descriptor_set) + + ", binding: " + std::to_string(binding) + " does not exist"); +} + +Result Pipeline::GetDescriptorInfo(const uint32_t descriptor_set, + const uint32_t binding, + ResourceInfo* info) { + assert(info); + for (size_t i = 0; i < descriptors_.size(); ++i) { + if (descriptors_[i]->GetDescriptorSet() == descriptor_set && + descriptors_[i]->GetBinding() == binding) { + *info = descriptors_[i]->GetResourceInfo(); + return {}; + } + } + + return Result("Vulkan::Pipeline descriptor with descriptor set: " + + std::to_string(descriptor_set) + + ", binding: " + std::to_string(binding) + " does not exist"); +} + } // namespace vulkan } // namespace amber diff --git a/src/vulkan/pipeline.h b/src/vulkan/pipeline.h index 8b56391..a20ec5d 100644 --- a/src/vulkan/pipeline.h +++ b/src/vulkan/pipeline.h @@ -45,6 +45,16 @@ class Pipeline { Result AddDescriptor(const BufferCommand*); + // Copy the contents of the resource bound to the given descriptor + // to host memory. + Result CopyDescriptorToHost(const uint32_t descriptor_set, + const uint32_t binding); + + // Get the information of the resource bound to the given descriptor. + Result GetDescriptorInfo(const uint32_t descriptor_set, + const uint32_t binding, + ResourceInfo* info); + virtual void Shutdown(); virtual Result ProcessCommands() = 0; @@ -58,7 +68,7 @@ class Pipeline { Result InitializeCommandBuffer(VkCommandPool pool, VkQueue queue); Result CreateVkDescriptorRelatedObjects(); - Result SendDescriptorDataToGPUIfNeeded(); + Result SendDescriptorDataToDeviceIfNeeded(); void BindVkPipeline(); void BindVkDescriptorSets(); diff --git a/src/vulkan/resource.cc b/src/vulkan/resource.cc index 5916c28..c5f02c2 100644 --- a/src/vulkan/resource.cc +++ b/src/vulkan/resource.cc @@ -47,9 +47,11 @@ VkMemoryBarrier kMemoryBarrierForAll = { } // namespace Resource::Resource(VkDevice device, - size_t size, + size_t size_in_bytes, const VkPhysicalDeviceMemoryProperties& properties) - : device_(device), size_(size), physical_memory_properties_(properties) {} + : device_(device), + size_in_bytes_(size_in_bytes), + physical_memory_properties_(properties) {} Resource::~Resource() = default; @@ -84,7 +86,7 @@ Result Resource::CreateVkBuffer(VkBuffer* buffer, VkBufferUsageFlags usage) { VkBufferCreateInfo buffer_info = {}; buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - buffer_info.size = size_; + buffer_info.size = size_in_bytes_; buffer_info.usage = usage; if (vkCreateBuffer(device_, &buffer_info, nullptr, buffer) != VK_SUCCESS) diff --git a/src/vulkan/resource.h b/src/vulkan/resource.h index 9bb763c..7243f8b 100644 --- a/src/vulkan/resource.h +++ b/src/vulkan/resource.h @@ -31,10 +31,14 @@ class Resource { return host_accessible_memory_; } + virtual Result CopyToHost(VkCommandBuffer command) = 0; + virtual void Shutdown(); void* HostAccessibleMemoryPtr() const { return memory_ptr_; } + size_t GetSizeInBytes() const { return size_in_bytes_; } + protected: Resource(VkDevice device, size_t size, @@ -45,8 +49,6 @@ class Resource { VkDevice GetDevice() const { return device_; } VkBuffer GetHostAccessibleBuffer() const { return host_accessible_buffer_; } - size_t GetSize() const { return size_; } - struct AllocateResult { Result r; uint32_t memory_type_index; @@ -61,13 +63,20 @@ class Resource { VkMemoryPropertyFlags flags, bool force_flags); - bool CheckMemoryHostAccessible(uint32_t memory_type_index) { + bool IsMemoryHostAccessible(uint32_t memory_type_index) { return (physical_memory_properties_.memoryTypes[memory_type_index] .propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; } + bool IsMemoryHostCoherent(uint32_t memory_type_index) { + return (physical_memory_properties_.memoryTypes[memory_type_index] + .propertyFlags & + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + } + Result MapMemory(VkDeviceMemory memory); void UnMapMemory(VkDeviceMemory memory); @@ -91,7 +100,7 @@ class Resource { const VkMemoryRequirements GetVkImageMemoryRequirements(VkImage image) const; VkDevice device_ = VK_NULL_HANDLE; - size_t size_ = 0; + size_t size_in_bytes_ = 0; VkPhysicalDeviceMemoryProperties physical_memory_properties_; VkBuffer host_accessible_buffer_ = VK_NULL_HANDLE; diff --git a/src/vulkan/storage_buffer_descriptor.cc b/src/vulkan/storage_buffer_descriptor.cc index 3202bae..f8a7c15 100644 --- a/src/vulkan/storage_buffer_descriptor.cc +++ b/src/vulkan/storage_buffer_descriptor.cc @@ -16,6 +16,7 @@ #include <vector> +#include "src/engine.h" #include "src/make_unique.h" namespace amber { @@ -98,7 +99,8 @@ Result StorageBufferDescriptor::Initialize(DataType type, return {}; } -void StorageBufferDescriptor::SendDataToGPUIfNeeded(VkCommandBuffer command) { +void StorageBufferDescriptor::SendDataToDeviceIfNeeded( + VkCommandBuffer command) { // TODO(jaebaek): VkRunner script allows data updating after initialiation. // Support updating data. if (IsDataAlreadySent()) @@ -108,6 +110,11 @@ void StorageBufferDescriptor::SendDataToGPUIfNeeded(VkCommandBuffer command) { SetDataSent(); } +Result StorageBufferDescriptor::SendDataToHostIfNeeded( + VkCommandBuffer command) { + return buffer_->CopyToHost(command); +} + Result StorageBufferDescriptor::UpdateDescriptorSet( VkDescriptorSet descriptor_set) { VkDescriptorBufferInfo buffer_info = {}; @@ -119,6 +126,14 @@ Result StorageBufferDescriptor::UpdateDescriptorSet( descriptor_set, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, buffer_info); } +ResourceInfo StorageBufferDescriptor::GetResourceInfo() { + ResourceInfo info = {}; + info.type = ResourceInfoType::kBuffer; + info.size_in_bytes = buffer_->GetSizeInBytes(); + info.cpu_memory = buffer_->HostAccessibleMemoryPtr(); + return info; +} + void StorageBufferDescriptor::Shutdown() { buffer_->Shutdown(); } diff --git a/src/vulkan/storage_buffer_descriptor.h b/src/vulkan/storage_buffer_descriptor.h index e8af632..a30bcd5 100644 --- a/src/vulkan/storage_buffer_descriptor.h +++ b/src/vulkan/storage_buffer_descriptor.h @@ -20,6 +20,7 @@ #include "amber/result.h" #include "src/datum_type.h" +#include "src/engine.h" #include "src/value.h" #include "src/vulkan/buffer.h" #include "src/vulkan/descriptor.h" @@ -40,8 +41,10 @@ class StorageBufferDescriptor : public Descriptor { Result Initialize(DataType type, const std::vector<Value>& values); // Descriptor - void SendDataToGPUIfNeeded(VkCommandBuffer command) override; + void SendDataToDeviceIfNeeded(VkCommandBuffer command) override; + Result SendDataToHostIfNeeded(VkCommandBuffer command) override; Result UpdateDescriptorSet(VkDescriptorSet descriptor_set) override; + ResourceInfo GetResourceInfo() override; void Shutdown() override; private: diff --git a/tests/cases/compute_ssbo.amber b/tests/cases/compute_ssbo.amber new file mode 100644 index 0000000..24b112c --- /dev/null +++ b/tests/cases/compute_ssbo.amber @@ -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 +# +# 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. + +[compute shader] +#version 430 + +layout(set = 0, binding = 0) buffer block0 { + float data_set0_binding0[3]; +}; + +layout(set = 1, binding = 2) buffer block1 { + float data_set1_binding2[3]; +}; + +layout(set = 2, binding = 1) buffer block2 { + float data_set2_binding1[3]; +}; + +layout(set = 2, binding = 3) buffer block3 { + float data_set2_binding3[3]; +}; + +void main() { + const uint index = gl_WorkGroupID.x; + data_set0_binding0[index] = data_set0_binding0[index] + 1.0f; + data_set1_binding2[index] = data_set2_binding1[index] - + data_set1_binding2[index]; + data_set2_binding1[index] = 10.0f * data_set2_binding3[index] + + data_set2_binding1[index]; + data_set2_binding3[index] = 30.0f * data_set2_binding3[index]; +} + +[test] +ssbo 0:0 subdata vec3 0 1.0 2.0 3.0 +ssbo 1:2 subdata vec3 0 4.0 5.0 6.0 +ssbo 2:1 subdata vec3 0 21.0 22.0 23.0 +ssbo 2:3 subdata vec3 0 0.7 0.8 0.9 +compute 3 1 1 + +probe ssbo vec3 0:0 0 ~= 2.0 3.0 4.0 +probe ssbo vec3 1:2 0 ~= 17.0 17.0 17.0 +probe ssbo vec3 2:1 0 ~= 28.0 30.0 32.0 +probe ssbo vec3 2:3 0 ~= 21.0 24.0 27.0 |