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