]> git.tdb.fi Git - libs/gl.git/blobdiff - source/backends/vulkan/synchronizer.cpp
Check the flat qualifier from the correct member
[libs/gl.git] / source / backends / vulkan / synchronizer.cpp
index c2c245a5a094cec43f7a3ec7a45970361ac64a64..28488fd0d28ad81188fe882b7e2c81ede29ebc59 100644 (file)
@@ -1,6 +1,7 @@
 #include <msp/core/algorithm.h>
 #include "buffer.h"
 #include "device.h"
+#include "error.h"
 #include "texture.h"
 #include "synchronizer.h"
 #include "vulkan.h"
@@ -14,12 +15,12 @@ Synchronizer::Synchronizer(Device &d):
        device(d)
 { }
 
-void Synchronizer::access(VkBuffer buffer, size_t offset, size_t size)
+void Synchronizer::write_buffer(VkBuffer buffer, size_t offset, size_t size, bool mapped)
 {
-       auto i = find_member(buffer_accesses, buffer, &BufferAccess::buffer);
-       if(i==buffer_accesses.end())
+       auto i = lower_bound_member(buffer_accesses, buffer, &BufferAccess::buffer);
+       if(i==buffer_accesses.end() || i->buffer!=buffer)
        {
-               i = buffer_accesses.emplace(buffer_accesses.end());
+               i = buffer_accesses.emplace(i);
                i->buffer = buffer;
                i->offset = offset;
                i->size = size;
@@ -32,26 +33,84 @@ void Synchronizer::access(VkBuffer buffer, size_t offset, size_t size)
                i->size = end-begin;
        }
 
+       if(mapped)
+               i->was_written = true;
        i->pending_write = true;
 }
 
-void Synchronizer::access(VkImage image, unsigned aspect, int layer, unsigned layout, bool discard)
+void Synchronizer::split_image_mipmap(VkImage image, unsigned aspect, unsigned n_levels)
 {
-       auto i = find_member(image_accesses, image, &ImageAccess::image);
-       if(i==image_accesses.end())
+       if(!n_levels)
+               throw invalid_argument("Synchronizer::split_image_mipmap");
+
+       auto i = lower_bound_member(image_accesses, image, &ImageAccess::image);
+       if(i!=image_accesses.end() && i->image==image && i->level>=0)
+               return;
+
+       if(i!=image_accesses.end() && i->image==image && i->level==-1)
+       {
+               i = image_accesses.insert(i, n_levels-1, *i);
+               for(unsigned j=0; j<n_levels; ++i, ++j)
+                       i->level = j;
+       }
+       else
+       {
+               ImageAccess access;
+               access.image = image;
+               access.aspect = aspect;
+               access.current_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+               access.pending_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+
+               if(i->level==-2)
+                       i = image_accesses.erase(i);
+
+               for(unsigned j=0; j<n_levels; ++i, ++j)
+                       if(i==image_accesses.end() || i->image!=image || i->level>static_cast<int>(j))
+                       {
+                               i = image_accesses.insert(i, access);
+                               i->level = j;
+                       }
+       }
+}
+
+void Synchronizer::change_image_layout(VkImage image, unsigned aspect, int level, unsigned layout, bool discard)
+{
+       auto i = lower_bound_member(image_accesses, image, &ImageAccess::image);
+
+       if(level>=0)
+       {
+               if(i==image_accesses.end() || i->image!=image)
+               {
+                       i = image_accesses.emplace(i);
+                       i->image = image;
+                       i->level = -2;
+                       ++i;
+               }
+               else if(i->level==-1)
+                       throw invalid_operation("Synchronizer::change_image_layout");
+               else
+               {
+                       for(; (i!=image_accesses.end() && i->image==image && i->level<level); ++i) ;
+               }
+       }
+       else if(i!=image_accesses.end() && i->image==image && i->level==-2)
+               throw invalid_operation("Synchronizer::change_image_layout");
+
+       if(i==image_accesses.end() || i->image!=image || (level>=0 && i->level!=level))
        {
-               i = image_accesses.emplace(image_accesses.end());
+               i = image_accesses.emplace(i);
                i->image = image;
                i->aspect = aspect;
-               i->layer = layer;
+               i->level = (level<0 ? -1 : level);
                i->current_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
        }
 
-       if(discard)
-               i->current_layout = VK_IMAGE_LAYOUT_UNDEFINED;
-       if(layer!=i->layer)
-               i->layer = -1;
-       i->pending_layout = layout;
+       for(; (i!=image_accesses.end() && i->image==image && (level<0 || i->level==level)); ++i)
+       {
+               if(discard)
+                       i->current_layout = VK_IMAGE_LAYOUT_UNDEFINED;
+               i->pending_layout = layout;
+       }
 }
 
 void Synchronizer::reset()
@@ -62,10 +121,8 @@ void Synchronizer::reset()
                i.pending_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
 }
 
-void Synchronizer::barrier(VkCommandBuffer command_buffer)
+void Synchronizer::barrier(const VulkanCommandRecorder &vkCmd)
 {
-       const VulkanFunctions &vk = device.get_functions();
-
        if(buffer_accesses.empty() && image_accesses.empty())
                return;
 
@@ -74,7 +131,8 @@ void Synchronizer::barrier(VkCommandBuffer command_buffer)
 
        static constexpr VkPipelineStageFlags buffer_read_stages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT|
                VK_PIPELINE_STAGE_VERTEX_SHADER_BIT|VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
-       static constexpr VkPipelineStageFlags buffer_write_stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
+       static constexpr VkPipelineStageFlags buffer_write_stages = VK_PIPELINE_STAGE_TRANSFER_BIT|
+               VK_PIPELINE_STAGE_HOST_BIT;
 
        vector<VkBufferMemoryBarrier> buffer_barriers;
        buffer_barriers.reserve(buffer_accesses.size());
@@ -108,7 +166,7 @@ void Synchronizer::barrier(VkCommandBuffer command_buffer)
        image_barriers.reserve(image_accesses.size());
        for(const ImageAccess &i: image_accesses)
        {
-               if(i.pending_layout==i.current_layout)
+               if(i.level==-2 || i.pending_layout==i.current_layout)
                        continue;
 
                image_barriers.emplace_back(VkImageMemoryBarrier{ });
@@ -123,18 +181,10 @@ void Synchronizer::barrier(VkCommandBuffer command_buffer)
                barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
                barrier.image = handle_cast<::VkImage>(i.image);
                barrier.subresourceRange.aspectMask = i.aspect;
-               barrier.subresourceRange.baseMipLevel = 0;
-               barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
-               if(i.layer>=0)
-               {
-                       barrier.subresourceRange.baseArrayLayer = i.layer;
-                       barrier.subresourceRange.layerCount = 1;
-               }
-               else
-               {
-                       barrier.subresourceRange.baseArrayLayer = 0;
-                       barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
-               }
+               barrier.subresourceRange.baseMipLevel = max(i.level, 0);
+               barrier.subresourceRange.levelCount = (i.level<0 ? VK_REMAINING_MIP_LEVELS : 1);
+               barrier.subresourceRange.baseArrayLayer = 0;
+               barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
 
                if(i.current_layout!=VK_IMAGE_LAYOUT_UNDEFINED)
                        src_stage |= (is_write_layout(i.current_layout) ? image_write_stages : image_read_stages);
@@ -149,7 +199,7 @@ void Synchronizer::barrier(VkCommandBuffer command_buffer)
        if(!dst_stage)
                dst_stage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
 
-       vk.CmdPipelineBarrier(command_buffer, src_stage, dst_stage, 0, 0, 0,
+       vkCmd.PipelineBarrier(src_stage, dst_stage, 0, 0, 0,
                buffer_barriers.size(), buffer_barriers.data(), image_barriers.size(), image_barriers.data());
 
        for(auto i=buffer_accesses.begin(); i!=buffer_accesses.end(); )
@@ -165,7 +215,25 @@ void Synchronizer::barrier(VkCommandBuffer command_buffer)
 
        for(auto i=image_accesses.begin(); i!=image_accesses.end(); )
        {
-               if(i->pending_layout==VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
+               if(i->level!=-1)
+               {
+                       auto j = i;
+                       if(j->level==-2)
+                               ++j;
+
+                       bool remove_image = true;
+                       for(; (j!=image_accesses.end() && j->image==i->image); ++j)
+                               remove_image &= (j->pending_layout==VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+
+                       if(remove_image)
+                               i = image_accesses.erase(i, j);
+                       else
+                       {
+                               for(; i!=j; ++i)
+                                       i->current_layout = i->pending_layout;
+                       }
+               }
+               else if(i->pending_layout==VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
                        i = image_accesses.erase(i);
                else
                {