]> git.tdb.fi Git - libs/gl.git/blobdiff - source/backends/vulkan/synchronizer.cpp
Implement textures and samplers for Vulkan
[libs/gl.git] / source / backends / vulkan / synchronizer.cpp
index 85c813e261e79536910f468480db1ce74c969f7a..7ce7c08a9d99fcc63763f3bb106e37fd9eb34e0f 100644 (file)
@@ -35,17 +35,38 @@ void Synchronizer::access(VkBuffer buffer, size_t offset, size_t size)
        i->pending_write = true;
 }
 
+void Synchronizer::access(VkImage image, unsigned aspect, int layer, unsigned layout, bool discard)
+{
+       auto i = find_member(image_accesses, image, &ImageAccess::image);
+       if(i==image_accesses.end())
+       {
+               i = image_accesses.emplace(image_accesses.end());
+               i->image = image;
+               i->aspect = aspect;
+               i->layer = layer;
+               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;
+}
+
 void Synchronizer::reset()
 {
        for(BufferAccess &b: buffer_accesses)
                b.pending_write = false;
+       for(ImageAccess &i: image_accesses)
+               i.pending_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
 }
 
 void Synchronizer::barrier(VkCommandBuffer command_buffer)
 {
        const VulkanFunctions &vk = device.get_functions();
 
-       if(buffer_accesses.empty())
+       if(buffer_accesses.empty() && image_accesses.empty())
                return;
 
        VkPipelineStageFlags src_stage = 0;
@@ -75,13 +96,52 @@ void Synchronizer::barrier(VkCommandBuffer command_buffer)
                dst_stage |= (b.pending_write ? buffer_write_stages : buffer_read_stages);
        }
 
+       static constexpr VkPipelineStageFlags image_read_stages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT|VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT|
+               VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT|VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
+       static constexpr VkPipelineStageFlags image_write_stages = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT|
+               VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT|VK_PIPELINE_STAGE_TRANSFER_BIT;
+
+       vector<VkImageMemoryBarrier> image_barriers;
+       image_barriers.reserve(image_accesses.size());
+       for(const ImageAccess &i: image_accesses)
+       {
+               image_barriers.emplace_back(VkImageMemoryBarrier{ });
+               VkImageMemoryBarrier &barrier = image_barriers.back();
+
+               barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+               barrier.srcAccessMask = (is_write_layout(i.current_layout) ? VK_ACCESS_MEMORY_WRITE_BIT : 0);
+               barrier.dstAccessMask = (is_write_layout(i.pending_layout) ? VK_ACCESS_MEMORY_WRITE_BIT : VK_ACCESS_MEMORY_READ_BIT);
+               barrier.oldLayout = static_cast<VkImageLayout>(i.current_layout);
+               barrier.newLayout = static_cast<VkImageLayout>(i.pending_layout);
+               barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+               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;
+               }
+
+               if(i.current_layout!=VK_IMAGE_LAYOUT_UNDEFINED)
+                       src_stage |= (is_write_layout(i.current_layout) ? image_write_stages : image_read_stages);
+               dst_stage |= (is_write_layout(i.pending_layout) ? image_write_stages : image_read_stages);
+       }
+
        if(!src_stage)
                src_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
        if(!dst_stage)
                dst_stage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
 
        vk.CmdPipelineBarrier(command_buffer, src_stage, dst_stage, 0, 0, 0,
-               buffer_barriers.size(), buffer_barriers.data(), 0, 0);
+               buffer_barriers.size(), buffer_barriers.data(), image_barriers.size(), image_barriers.data());
 
        for(auto i=buffer_accesses.begin(); i!=buffer_accesses.end(); )
        {
@@ -93,6 +153,23 @@ void Synchronizer::barrier(VkCommandBuffer command_buffer)
                        ++i;
                }
        }
+
+       for(auto i=image_accesses.begin(); i!=image_accesses.end(); )
+       {
+               if(i->pending_layout==VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
+                       i = image_accesses.erase(i);
+               else
+               {
+                       i->current_layout = i->pending_layout;
+                       ++i;
+               }
+       }
+}
+
+bool Synchronizer::is_write_layout(unsigned layout)
+{
+       return layout==VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL || layout==VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ||
+               layout==VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
 }
 
 } // namespace GL