]> git.tdb.fi Git - libs/gl.git/blob - source/backends/vulkan/texture_backend.cpp
Check the flat qualifier from the correct member
[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         VkFormat vk_format = static_cast<VkFormat>(get_vulkan_pixelformat(self.storage_fmt));
53         VkFormatProperties props;
54         vk.GetPhysicalDeviceFormatProperties(vk_format, props);
55
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;
68
69         image_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_SAMPLED_BIT;
70
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;
74         else
75                 image_info.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
76
77         fill_image_info(&image_info);
78
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;
81
82         /* SwapChainTexture may have already provided the image.  Create_info is
83         filled anyway because some of its fields are used for view_info. */
84         if(!handle)
85         {
86                 vk.CreateImage(image_info, handle);
87                 memory_id = device.get_allocator().allocate(handle, DEVICE_MEMORY);
88
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);
91         }
92
93         view_handle = create_view(-1);
94
95         if(!debug_name.empty())
96                 set_vulkan_object_names();
97 }
98
99 VkImageView VulkanTexture::create_view(int level) const
100 {
101         const Texture &self = *static_cast<const Texture *>(this);
102         const VulkanFunctions &vk = device.get_functions();
103
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));
109
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]);
115
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;
121
122         VkImageView view;
123         vk.CreateImageView(view_info, view);
124
125         return view;
126 }
127
128 void VulkanTexture::create_mip_views() const
129 {
130         const Texture &self = *static_cast<const Texture *>(this);
131
132         if(!mip_view_handles.empty())
133                 return;
134                 
135         mip_view_handles.resize(self.n_levels);
136         if(self.n_levels==1)
137                 mip_view_handles[0] = view_handle;
138         else
139         {
140                 for(unsigned i=0; i<self.n_levels; ++i)
141                         mip_view_handles[i] = create_view(i);
142         }
143 }
144
145 void VulkanTexture::generate_mipmap()
146 {
147         unsigned n_levels = static_cast<const Texture *>(this)->n_levels;
148
149         TransferQueue &tq = device.get_transfer_queue();
150         for(unsigned i=0; i+1<n_levels; ++i)
151         {
152                 tq.prepare_transfer(this, true,
153                         [this, i](){
154                                 change_layout(i, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, false);
155                                 change_layout(i+1, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true);
156                         },
157                         [this, i](const VulkanCommandRecorder &vkCmd, VkBuffer, size_t){
158                                 const Texture &self = *static_cast<const Texture *>(this);
159
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;
167
168                                 fill_mipmap_blit(i, &region);
169
170                                 vkCmd.BlitImage(handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
171                                         1, &region, VK_FILTER_LINEAR);
172                         });
173         }
174 }
175
176 void VulkanTexture::change_layout(int level, unsigned layout, bool discard) const
177 {
178         const Texture &self = *static_cast<const Texture *>(this);
179
180         unsigned aspect = get_vulkan_aspect(get_components(self.storage_fmt));
181         if(level>=0)
182                 device.get_synchronizer().split_image_mipmap(handle, aspect, self.n_levels);
183         device.get_synchronizer().change_image_layout(handle, aspect, level, layout, discard);
184 }
185
186 void VulkanTexture::set_debug_name(const string &name)
187 {
188 #ifdef DEBUG
189         debug_name = name;
190         if(handle)
191                 set_vulkan_object_names();
192 #else
193         (void)name;
194 #endif
195 }
196
197 void VulkanTexture::set_vulkan_object_names() const
198 {
199 #ifdef DEBUG
200         const VulkanFunctions &vk = device.get_functions();
201
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);
208
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);
214
215         if(mip_view_handles.size()>1)
216         {
217                 for(unsigned i=0; i<mip_view_handles.size(); ++i)
218                 {
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);
223                 }
224         }
225 #endif
226 }
227
228 } // namespace GL
229 } // namespace Msp