]> git.tdb.fi Git - libs/gl.git/blob - source/backends/vulkan/texture_backend.cpp
Minor tweaks to MemoryAllocator
[libs/gl.git] / source / backends / vulkan / texture_backend.cpp
1 #include <msp/strings/format.h>
2 #include "device.h"
3 #include "error.h"
4 #include "synchronizer.h"
5 #include "texture.h"
6 #include "texture_backend.h"
7 #include "vulkan.h"
8
9 using namespace std;
10
11 namespace Msp {
12 namespace GL {
13
14 VulkanTexture::VulkanTexture(unsigned t):
15         device(Device::get_current()),
16         view_type(t)
17 { }
18
19 VulkanTexture::VulkanTexture(VulkanTexture &&other):
20         device(other.device),
21         handle(other.handle),
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))
26 {
27         other.handle = 0;
28         other.view_handle = 0;
29         other.memory_id = 0;
30 }
31
32 VulkanTexture::~VulkanTexture()
33 {
34         DestroyQueue &dq = device.get_destroy_queue();
35
36         if(view_handle)
37                 dq.destroy(view_handle);
38         if(mip_view_handles.size()>1)
39         {
40                 for(VkImageView i: mip_view_handles)
41                         dq.destroy(i);
42         }
43         if(handle)
44                 dq.destroy(handle, memory_id);
45 }
46
47 void VulkanTexture::allocate()
48 {
49         const Texture &self = *static_cast<const Texture *>(this);
50         const VulkanFunctions &vk = device.get_functions();
51
52         VkImageCreateInfo image_info = { };
53         image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
54         image_info.format = static_cast<VkFormat>(get_vulkan_pixelformat(self.storage_fmt));
55         image_info.extent.width = 1;
56         image_info.extent.height = 1;
57         image_info.extent.depth = 1;
58         image_info.mipLevels = self.n_levels;
59         image_info.arrayLayers = 1;
60         image_info.samples = VK_SAMPLE_COUNT_1_BIT;
61         image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
62         image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
63         image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
64
65         image_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_SAMPLED_BIT;
66         PixelComponents comp = get_components(self.storage_fmt);
67         if(comp==DEPTH_COMPONENT || comp==STENCIL_INDEX)
68                 image_info.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
69         else
70                 image_info.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
71
72         fill_image_info(&image_info);
73
74         /* SwapChainTexture may have already provided the image.  Create_info is
75         filled anyway because some of its fields are used for view_info. */
76         if(!handle)
77         {
78                 vk.CreateImage(image_info, handle);
79                 memory_id = device.get_allocator().allocate(handle, DEVICE_MEMORY);
80
81                 // Trigger a layout transition if the image is used before uploading data.
82                 change_layout(-1, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, true);
83         }
84
85         view_handle = create_view(-1);
86
87         if(!debug_name.empty())
88                 set_vulkan_object_names();
89 }
90
91 VkImageView VulkanTexture::create_view(int level) const
92 {
93         const Texture &self = *static_cast<const Texture *>(this);
94         const VulkanFunctions &vk = device.get_functions();
95
96         VkImageViewCreateInfo view_info = { };
97         view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
98         view_info.image = handle_cast<::VkImage>(handle);
99         view_info.viewType = static_cast<VkImageViewType>(view_type);
100         view_info.format = static_cast<VkFormat>(get_vulkan_pixelformat(self.storage_fmt));
101
102         const unsigned *swizzle_order = get_vulkan_swizzle(self.swizzle);
103         view_info.components.r = static_cast<VkComponentSwizzle>(swizzle_order[0]);
104         view_info.components.g = static_cast<VkComponentSwizzle>(swizzle_order[1]);
105         view_info.components.b = static_cast<VkComponentSwizzle>(swizzle_order[2]);
106         view_info.components.a = static_cast<VkComponentSwizzle>(swizzle_order[3]);
107
108         view_info.subresourceRange.aspectMask = get_vulkan_aspect(get_components(self.storage_fmt));
109         view_info.subresourceRange.baseMipLevel = max(level, 0);
110         view_info.subresourceRange.levelCount = (level<0 ? VK_REMAINING_MIP_LEVELS : 1);
111         view_info.subresourceRange.baseArrayLayer = 0;
112         view_info.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
113
114         VkImageView view;
115         vk.CreateImageView(view_info, view);
116
117         return view;
118 }
119
120 void VulkanTexture::create_mip_views() const
121 {
122         const Texture &self = *static_cast<const Texture *>(this);
123
124         if(!mip_view_handles.empty())
125                 return;
126                 
127         mip_view_handles.resize(self.n_levels);
128         if(self.n_levels==1)
129                 mip_view_handles[0] = view_handle;
130         else
131         {
132                 for(unsigned i=0; i<self.n_levels; ++i)
133                         mip_view_handles[i] = create_view(i);
134         }
135 }
136
137 void VulkanTexture::generate_mipmap()
138 {
139         unsigned n_levels = static_cast<const Texture *>(this)->n_levels;
140
141         TransferQueue &tq = device.get_transfer_queue();
142         for(unsigned i=0; i+1<n_levels; ++i)
143         {
144                 tq.prepare_transfer(this, true,
145                         [this, i](){
146                                 change_layout(i, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, false);
147                                 change_layout(i+1, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true);
148                         },
149                         [this, i](VkCommandBuffer cmd_buf, VkBuffer, size_t){
150                                 const Texture &self = *static_cast<const Texture *>(this);
151                                 const VulkanFunctions &vk = device.get_functions();
152
153                                 VkImageBlit region = { };
154                                 region.srcSubresource.aspectMask = get_vulkan_aspect(get_components(self.storage_fmt));
155                                 region.srcSubresource.mipLevel = i;
156                                 region.srcSubresource.baseArrayLayer = 0;
157                                 region.srcSubresource.layerCount = 1;
158                                 region.dstSubresource = region.srcSubresource;
159                                 ++region.dstSubresource.mipLevel;
160
161                                 fill_mipmap_blit(i, &region);
162
163                                 vk.CmdBlitImage(cmd_buf, handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
164                                         1, &region, VK_FILTER_LINEAR);
165                         });
166         }
167 }
168
169 void VulkanTexture::change_layout(int level, unsigned layout, bool discard) const
170 {
171         const Texture &self = *static_cast<const Texture *>(this);
172
173         unsigned aspect = get_vulkan_aspect(get_components(self.storage_fmt));
174         if(level>=0)
175                 device.get_synchronizer().split_image_mipmap(handle, aspect, self.n_levels);
176         device.get_synchronizer().change_image_layout(handle, aspect, level, layout, discard);
177 }
178
179 void VulkanTexture::set_debug_name(const string &name)
180 {
181 #ifdef DEBUG
182         debug_name = name;
183         if(handle)
184                 set_vulkan_object_names();
185 #else
186         (void)name;
187 #endif
188 }
189
190 void VulkanTexture::set_vulkan_object_names() const
191 {
192 #ifdef DEBUG
193         const VulkanFunctions &vk = device.get_functions();
194
195         VkDebugUtilsObjectNameInfoEXT name_info = { };
196         name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
197         name_info.objectType = VK_OBJECT_TYPE_IMAGE;
198         name_info.objectHandle = reinterpret_cast<uint64_t>(handle);
199         name_info.pObjectName = debug_name.c_str();
200         vk.SetDebugUtilsObjectName(name_info);
201
202         string view_name = debug_name+"/view";
203         name_info.objectType = VK_OBJECT_TYPE_IMAGE_VIEW;
204         name_info.objectHandle = reinterpret_cast<uint64_t>(view_handle);
205         name_info.pObjectName = view_name.c_str();
206         vk.SetDebugUtilsObjectName(name_info);
207
208         if(mip_view_handles.size()>1)
209         {
210                 for(unsigned i=0; i<mip_view_handles.size(); ++i)
211                 {
212                         view_name = format("%s/mip%d.view", debug_name, i);
213                         name_info.objectHandle = reinterpret_cast<uint64_t>(mip_view_handles[i]);
214                         name_info.pObjectName = view_name.c_str();
215                         vk.SetDebugUtilsObjectName(name_info);
216                 }
217         }
218 #endif
219 }
220
221 } // namespace GL
222 } // namespace Msp