]> git.tdb.fi Git - libs/gl.git/blobdiff - source/backends/vulkan/texture_backend.cpp
Add support for storage images in Renderer and PipelineState
[libs/gl.git] / source / backends / vulkan / texture_backend.cpp
index ec6d504732f9f0a13055eff1f42086d2fe4858a7..1367cc8d46c2a87a24eddb892b93b0d7cb142817 100644 (file)
@@ -1,3 +1,4 @@
+#include <msp/strings/format.h>
 #include "device.h"
 #include "error.h"
 #include "synchronizer.h"
@@ -34,6 +35,11 @@ VulkanTexture::~VulkanTexture()
 
        if(view_handle)
                dq.destroy(view_handle);
+       if(mip_view_handles.size()>1)
+       {
+               for(VkImageView i: mip_view_handles)
+                       dq.destroy(i);
+       }
        if(handle)
                dq.destroy(handle, memory_id);
 }
@@ -43,9 +49,13 @@ void VulkanTexture::allocate()
        const Texture &self = *static_cast<const Texture *>(this);
        const VulkanFunctions &vk = device.get_functions();
 
+       VkFormat vk_format = static_cast<VkFormat>(get_vulkan_pixelformat(self.storage_fmt));
+       VkFormatProperties props;
+       vk.GetPhysicalDeviceFormatProperties(vk_format, props);
+
        VkImageCreateInfo image_info = { };
        image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
-       image_info.format = static_cast<VkFormat>(get_vulkan_pixelformat(self.storage_fmt));
+       image_info.format = vk_format;
        image_info.extent.width = 1;
        image_info.extent.height = 1;
        image_info.extent.depth = 1;
@@ -57,6 +67,9 @@ void VulkanTexture::allocate()
        image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
 
        image_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_SAMPLED_BIT;
+       if(props.optimalTilingFeatures&VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)
+               image_info.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
+
        PixelComponents comp = get_components(self.storage_fmt);
        if(comp==DEPTH_COMPONENT || comp==STENCIL_INDEX)
                image_info.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
@@ -76,11 +89,22 @@ void VulkanTexture::allocate()
                change_layout(-1, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, true);
        }
 
+       view_handle = create_view(-1);
+
+       if(!debug_name.empty())
+               set_vulkan_object_names();
+}
+
+VkImageView VulkanTexture::create_view(int level) const
+{
+       const Texture &self = *static_cast<const Texture *>(this);
+       const VulkanFunctions &vk = device.get_functions();
+
        VkImageViewCreateInfo view_info = { };
        view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
        view_info.image = handle_cast<::VkImage>(handle);
        view_info.viewType = static_cast<VkImageViewType>(view_type);
-       view_info.format = image_info.format;
+       view_info.format = static_cast<VkFormat>(get_vulkan_pixelformat(self.storage_fmt));
 
        const unsigned *swizzle_order = get_vulkan_swizzle(self.swizzle);
        view_info.components.r = static_cast<VkComponentSwizzle>(swizzle_order[0]);
@@ -89,51 +113,31 @@ void VulkanTexture::allocate()
        view_info.components.a = static_cast<VkComponentSwizzle>(swizzle_order[3]);
 
        view_info.subresourceRange.aspectMask = get_vulkan_aspect(get_components(self.storage_fmt));
-       view_info.subresourceRange.baseMipLevel = 0;
-       view_info.subresourceRange.levelCount = image_info.mipLevels;
+       view_info.subresourceRange.baseMipLevel = max(level, 0);
+       view_info.subresourceRange.levelCount = (level<0 ? VK_REMAINING_MIP_LEVELS : 1);
        view_info.subresourceRange.baseArrayLayer = 0;
-       view_info.subresourceRange.layerCount = image_info.arrayLayers;
+       view_info.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
 
-       vk.CreateImageView(view_info, view_handle);
+       VkImageView view;
+       vk.CreateImageView(view_info, view);
 
-       if(!debug_name.empty())
-               set_vulkan_object_names();
+       return view;
 }
 
-void VulkanTexture::stage_pixels(void *staging, const void *data, size_t count)
+void VulkanTexture::create_mip_views() const
 {
        const Texture &self = *static_cast<const Texture *>(this);
 
-       if(self.swizzle==RGBA_TO_RGB)
-       {
-               const uint32_t *src = static_cast<const uint32_t *>(data);
-               uint32_t *dst = static_cast<uint32_t *>(staging);
-               size_t i = 0;
-               for(; i+3<count; i+=4)
-               {
-                       dst[0] = src[0]|0xFF000000;
-                       dst[1] = (src[0]>>24)|(src[1]<<8)|0xFF000000;
-                       dst[2] = (src[1]>>16)|(src[2]<<16)|0xFF000000;
-                       dst[3] = (src[2]>>8)|0xFF000000;
-                       src += 3;
-                       dst += 4;
-               }
-
-               if(i<count)
-               {
-                       const uint8_t *src_bytes = reinterpret_cast<const uint8_t *>(src);
-                       for(; i<count; ++i)
-                       {
-                               *dst++ = src_bytes[0]|(src_bytes[1]<<8)|(src_bytes[2]<<16)|0xFF000000;
-                               src_bytes += 3;
-                       }
-               }
-       }
+       if(!mip_view_handles.empty())
+               return;
+               
+       mip_view_handles.resize(self.n_levels);
+       if(self.n_levels==1)
+               mip_view_handles[0] = view_handle;
        else
        {
-               const char *src = static_cast<const char *>(data);
-               size_t data_size = count*get_pixel_size(self.storage_fmt);
-               copy(src, src+data_size, static_cast<char *>(staging));
+               for(unsigned i=0; i<self.n_levels; ++i)
+                       mip_view_handles[i] = create_view(i);
        }
 }
 
@@ -144,16 +148,16 @@ void VulkanTexture::generate_mipmap()
        TransferQueue &tq = device.get_transfer_queue();
        for(unsigned i=0; i+1<n_levels; ++i)
        {
-               tq.prepare_transfer(this, true, 0,
+               tq.prepare_transfer(this, true,
                        [this, i](){
                                change_layout(i, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, false);
                                change_layout(i+1, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true);
                        },
-                       [this, i](VkCommandBuffer cmd_buf, VkBuffer, size_t){
-                               const VulkanFunctions &vk = device.get_functions();
+                       [this, i](const VulkanCommandRecorder &vkCmd, VkBuffer, size_t){
+                               const Texture &self = *static_cast<const Texture *>(this);
 
                                VkImageBlit region = { };
-                               region.srcSubresource.aspectMask = get_vulkan_aspect(get_components(static_cast<const Texture *>(this)->storage_fmt));
+                               region.srcSubresource.aspectMask = get_vulkan_aspect(get_components(self.storage_fmt));
                                region.srcSubresource.mipLevel = i;
                                region.srcSubresource.baseArrayLayer = 0;
                                region.srcSubresource.layerCount = 1;
@@ -162,7 +166,7 @@ void VulkanTexture::generate_mipmap()
 
                                fill_mipmap_blit(i, &region);
 
-                               vk.CmdBlitImage(cmd_buf, handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+                               vkCmd.BlitImage(handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
                                        1, &region, VK_FILTER_LINEAR);
                        });
        }
@@ -206,6 +210,17 @@ void VulkanTexture::set_vulkan_object_names() const
        name_info.objectHandle = reinterpret_cast<uint64_t>(view_handle);
        name_info.pObjectName = view_name.c_str();
        vk.SetDebugUtilsObjectName(name_info);
+
+       if(mip_view_handles.size()>1)
+       {
+               for(unsigned i=0; i<mip_view_handles.size(); ++i)
+               {
+                       view_name = format("%s/mip%d.view", debug_name, i);
+                       name_info.objectHandle = reinterpret_cast<uint64_t>(mip_view_handles[i]);
+                       name_info.pObjectName = view_name.c_str();
+                       vk.SetDebugUtilsObjectName(name_info);
+               }
+       }
 #endif
 }