]> git.tdb.fi Git - libs/gl.git/blob - source/backends/vulkan/texture_backend.cpp
Refactor TransferQueue to require explicit finalization of transfers
[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::stage_pixels(void *staging, const void *data, size_t count)
138 {
139         const Texture &self = *static_cast<const Texture *>(this);
140
141         if(self.swizzle==RGBA_TO_RGB)
142         {
143                 const uint32_t *src = static_cast<const uint32_t *>(data);
144                 uint32_t *dst = static_cast<uint32_t *>(staging);
145                 size_t i = 0;
146                 for(; i+3<count; i+=4)
147                 {
148                         dst[0] = src[0]|0xFF000000;
149                         dst[1] = (src[0]>>24)|(src[1]<<8)|0xFF000000;
150                         dst[2] = (src[1]>>16)|(src[2]<<16)|0xFF000000;
151                         dst[3] = (src[2]>>8)|0xFF000000;
152                         src += 3;
153                         dst += 4;
154                 }
155
156                 if(i<count)
157                 {
158                         const uint8_t *src_bytes = reinterpret_cast<const uint8_t *>(src);
159                         for(; i<count; ++i)
160                         {
161                                 *dst++ = src_bytes[0]|(src_bytes[1]<<8)|(src_bytes[2]<<16)|0xFF000000;
162                                 src_bytes += 3;
163                         }
164                 }
165         }
166         else
167         {
168                 const char *src = static_cast<const char *>(data);
169                 size_t data_size = count*get_pixel_size(self.storage_fmt);
170                 copy(src, src+data_size, static_cast<char *>(staging));
171         }
172 }
173
174 void VulkanTexture::generate_mipmap()
175 {
176         unsigned n_levels = static_cast<const Texture *>(this)->n_levels;
177
178         TransferQueue &tq = device.get_transfer_queue();
179         for(unsigned i=0; i+1<n_levels; ++i)
180         {
181                 tq.prepare_transfer(this, true,
182                         [this, i](){
183                                 change_layout(i, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, false);
184                                 change_layout(i+1, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true);
185                         },
186                         [this, i](VkCommandBuffer cmd_buf, VkBuffer, size_t){
187                                 const VulkanFunctions &vk = device.get_functions();
188
189                                 VkImageBlit region = { };
190                                 region.srcSubresource.aspectMask = get_vulkan_aspect(get_components(static_cast<const Texture *>(this)->storage_fmt));
191                                 region.srcSubresource.mipLevel = i;
192                                 region.srcSubresource.baseArrayLayer = 0;
193                                 region.srcSubresource.layerCount = 1;
194                                 region.dstSubresource = region.srcSubresource;
195                                 ++region.dstSubresource.mipLevel;
196
197                                 fill_mipmap_blit(i, &region);
198
199                                 vk.CmdBlitImage(cmd_buf, handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
200                                         1, &region, VK_FILTER_LINEAR);
201                         });
202         }
203 }
204
205 void VulkanTexture::change_layout(int level, unsigned layout, bool discard) const
206 {
207         const Texture &self = *static_cast<const Texture *>(this);
208
209         unsigned aspect = get_vulkan_aspect(get_components(self.storage_fmt));
210         if(level>=0)
211                 device.get_synchronizer().split_image_mipmap(handle, aspect, self.n_levels);
212         device.get_synchronizer().change_image_layout(handle, aspect, level, layout, discard);
213 }
214
215 void VulkanTexture::set_debug_name(const string &name)
216 {
217 #ifdef DEBUG
218         debug_name = name;
219         if(handle)
220                 set_vulkan_object_names();
221 #else
222         (void)name;
223 #endif
224 }
225
226 void VulkanTexture::set_vulkan_object_names() const
227 {
228 #ifdef DEBUG
229         const VulkanFunctions &vk = device.get_functions();
230
231         VkDebugUtilsObjectNameInfoEXT name_info = { };
232         name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
233         name_info.objectType = VK_OBJECT_TYPE_IMAGE;
234         name_info.objectHandle = reinterpret_cast<uint64_t>(handle);
235         name_info.pObjectName = debug_name.c_str();
236         vk.SetDebugUtilsObjectName(name_info);
237
238         string view_name = debug_name+"/view";
239         name_info.objectType = VK_OBJECT_TYPE_IMAGE_VIEW;
240         name_info.objectHandle = reinterpret_cast<uint64_t>(view_handle);
241         name_info.pObjectName = view_name.c_str();
242         vk.SetDebugUtilsObjectName(name_info);
243
244         if(mip_view_handles.size()>1)
245         {
246                 for(unsigned i=0; i<mip_view_handles.size(); ++i)
247                 {
248                         view_name = format("%s/mip%d.view", debug_name, i);
249                         name_info.objectHandle = reinterpret_cast<uint64_t>(mip_view_handles[i]);
250                         name_info.pObjectName = view_name.c_str();
251                         vk.SetDebugUtilsObjectName(name_info);
252                 }
253         }
254 #endif
255 }
256
257 } // namespace GL
258 } // namespace Msp