1 #include <msp/strings/format.h>
4 #include "synchronizer.h"
6 #include "texture_backend.h"
14 VulkanTexture::VulkanTexture(unsigned t):
15 device(Device::get_current()),
19 VulkanTexture::VulkanTexture(VulkanTexture &&other):
22 view_handle(other.view_handle),
23 memory_id(other.memory_id),
24 view_type(other.view_type),
25 debug_name(move(other.debug_name))
28 other.view_handle = 0;
32 VulkanTexture::~VulkanTexture()
34 DestroyQueue &dq = device.get_destroy_queue();
37 dq.destroy(view_handle);
38 if(mip_view_handles.size()>1)
40 for(VkImageView i: mip_view_handles)
44 dq.destroy(handle, memory_id);
47 void VulkanTexture::allocate()
49 const Texture &self = *static_cast<const Texture *>(this);
50 const VulkanFunctions &vk = device.get_functions();
52 VkFormat vk_format = static_cast<VkFormat>(get_vulkan_pixelformat(self.storage_fmt));
53 VkFormatProperties props;
54 vk.GetPhysicalDeviceFormatProperties(vk_format, props);
56 VkImageCreateInfo image_info = { };
57 image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
58 image_info.format = vk_format;
59 image_info.extent.width = 1;
60 image_info.extent.height = 1;
61 image_info.extent.depth = 1;
62 image_info.mipLevels = self.n_levels;
63 image_info.arrayLayers = 1;
64 image_info.samples = VK_SAMPLE_COUNT_1_BIT;
65 image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
66 image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
67 image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
69 image_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_SAMPLED_BIT;
71 PixelComponents comp = get_components(self.storage_fmt);
72 if(comp==DEPTH_COMPONENT || comp==STENCIL_INDEX)
73 image_info.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
75 image_info.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
77 fill_image_info(&image_info);
79 if((props.optimalTilingFeatures&VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) && image_info.samples==VK_SAMPLE_COUNT_1_BIT)
80 image_info.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
82 /* SwapChainTexture may have already provided the image. Create_info is
83 filled anyway because some of its fields are used for view_info. */
86 vk.CreateImage(image_info, handle);
87 memory_id = device.get_allocator().allocate(handle, DEVICE_MEMORY);
89 // Trigger a layout transition if the image is used before uploading data.
90 change_layout(-1, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, true);
93 view_handle = create_view(-1);
95 if(!debug_name.empty())
96 set_vulkan_object_names();
99 VkImageView VulkanTexture::create_view(int level) const
101 const Texture &self = *static_cast<const Texture *>(this);
102 const VulkanFunctions &vk = device.get_functions();
104 VkImageViewCreateInfo view_info = { };
105 view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
106 view_info.image = handle_cast<::VkImage>(handle);
107 view_info.viewType = static_cast<VkImageViewType>(view_type);
108 view_info.format = static_cast<VkFormat>(get_vulkan_pixelformat(self.storage_fmt));
110 const unsigned *swizzle_order = get_vulkan_swizzle(self.swizzle);
111 view_info.components.r = static_cast<VkComponentSwizzle>(swizzle_order[0]);
112 view_info.components.g = static_cast<VkComponentSwizzle>(swizzle_order[1]);
113 view_info.components.b = static_cast<VkComponentSwizzle>(swizzle_order[2]);
114 view_info.components.a = static_cast<VkComponentSwizzle>(swizzle_order[3]);
116 view_info.subresourceRange.aspectMask = get_vulkan_aspect(get_components(self.storage_fmt));
117 view_info.subresourceRange.baseMipLevel = max(level, 0);
118 view_info.subresourceRange.levelCount = (level<0 ? VK_REMAINING_MIP_LEVELS : 1);
119 view_info.subresourceRange.baseArrayLayer = 0;
120 view_info.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
123 vk.CreateImageView(view_info, view);
128 void VulkanTexture::create_mip_views() const
130 const Texture &self = *static_cast<const Texture *>(this);
132 if(!mip_view_handles.empty())
135 mip_view_handles.resize(self.n_levels);
137 mip_view_handles[0] = view_handle;
140 for(unsigned i=0; i<self.n_levels; ++i)
141 mip_view_handles[i] = create_view(i);
145 void VulkanTexture::generate_mipmap()
147 unsigned n_levels = static_cast<const Texture *>(this)->n_levels;
149 TransferQueue &tq = device.get_transfer_queue();
150 for(unsigned i=0; i+1<n_levels; ++i)
152 tq.prepare_transfer(this, true,
154 change_layout(i, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, false);
155 change_layout(i+1, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true);
157 [this, i](const VulkanCommandRecorder &vkCmd, VkBuffer, size_t){
158 const Texture &self = *static_cast<const Texture *>(this);
160 VkImageBlit region = { };
161 region.srcSubresource.aspectMask = get_vulkan_aspect(get_components(self.storage_fmt));
162 region.srcSubresource.mipLevel = i;
163 region.srcSubresource.baseArrayLayer = 0;
164 region.srcSubresource.layerCount = 1;
165 region.dstSubresource = region.srcSubresource;
166 ++region.dstSubresource.mipLevel;
168 fill_mipmap_blit(i, ®ion);
170 vkCmd.BlitImage(handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
171 1, ®ion, VK_FILTER_LINEAR);
176 void VulkanTexture::change_layout(int level, unsigned layout, bool discard) const
178 const Texture &self = *static_cast<const Texture *>(this);
180 unsigned aspect = get_vulkan_aspect(get_components(self.storage_fmt));
182 device.get_synchronizer().split_image_mipmap(handle, aspect, self.n_levels);
183 device.get_synchronizer().change_image_layout(handle, aspect, level, layout, discard);
186 void VulkanTexture::set_debug_name(const string &name)
191 set_vulkan_object_names();
197 void VulkanTexture::set_vulkan_object_names() const
200 const VulkanFunctions &vk = device.get_functions();
202 VkDebugUtilsObjectNameInfoEXT name_info = { };
203 name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
204 name_info.objectType = VK_OBJECT_TYPE_IMAGE;
205 name_info.objectHandle = reinterpret_cast<uint64_t>(handle);
206 name_info.pObjectName = debug_name.c_str();
207 vk.SetDebugUtilsObjectName(name_info);
209 string view_name = debug_name+"/view";
210 name_info.objectType = VK_OBJECT_TYPE_IMAGE_VIEW;
211 name_info.objectHandle = reinterpret_cast<uint64_t>(view_handle);
212 name_info.pObjectName = view_name.c_str();
213 vk.SetDebugUtilsObjectName(name_info);
215 if(mip_view_handles.size()>1)
217 for(unsigned i=0; i<mip_view_handles.size(); ++i)
219 view_name = format("%s/mip%d.view", debug_name, i);
220 name_info.objectHandle = reinterpret_cast<uint64_t>(mip_view_handles[i]);
221 name_info.pObjectName = view_name.c_str();
222 vk.SetDebugUtilsObjectName(name_info);