]> git.tdb.fi Git - libs/gl.git/blob - source/backends/vulkan/framebuffer_backend.cpp
Rename VulkanFramebuffer::prepare_image_layouts to synchronize_resources
[libs/gl.git] / source / backends / vulkan / framebuffer_backend.cpp
1 #include <msp/strings/format.h>
2 #include "device.h"
3 #include "framebuffer.h"
4 #include "framebuffer_backend.h"
5 #include "renderpass.h"
6 #include "swapchaintexture.h"
7 #include "vulkan.h"
8
9 using namespace std;
10
11 namespace Msp {
12 namespace GL {
13
14 VulkanFramebuffer::VulkanFramebuffer(bool):
15         device(Device::get_current())
16 { }
17
18 VulkanFramebuffer::VulkanFramebuffer(VulkanFramebuffer &&other):
19         device(other.device),
20         handle(other.handle),
21         debug_name(move(other.debug_name))
22 {
23         other.handle = 0;
24 }
25
26 VulkanFramebuffer::~VulkanFramebuffer()
27 {
28         DestroyQueue &dq = device.get_destroy_queue();
29         if(handle)
30                 dq.destroy(handle);
31         for(VkImageView h: view_handles)
32                 if(h)
33                         dq.destroy(h);
34 }
35
36 bool VulkanFramebuffer::is_format_supported(const FrameFormat &fmt) const
37 {
38         const VulkanFunctions &vk = device.get_functions();
39         for(FrameAttachment a: fmt)
40         {
41                 PixelFormat pf = get_attachment_pixelformat(a);
42                 PixelComponents comp = get_components(pf);
43                 VkFormatProperties props;
44                 vk.GetPhysicalDeviceFormatProperties(static_cast<VkFormat>(get_vulkan_pixelformat(pf)), props);
45                 if(comp==DEPTH_COMPONENT || comp==STENCIL_INDEX)
46                 {
47                         if(!(props.optimalTilingFeatures&VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT))
48                                 return false;
49                 }
50                 else if(!(props.optimalTilingFeatures&VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT))
51                         return false;
52         }
53
54         return true;
55 }
56
57 bool VulkanFramebuffer::is_presentable() const
58 {
59         const Framebuffer &self = *static_cast<const Framebuffer *>(this);
60         return std::any_of(self.attachments.begin(), self.attachments.end(),
61                 [](const Framebuffer::Attachment &a){ return dynamic_cast<const SwapChainTexture *>(a.tex); });
62 }
63
64 void VulkanFramebuffer::update(unsigned mask) const
65 {
66         const Framebuffer &self = *static_cast<const Framebuffer *>(this);
67         const VulkanFunctions &vk = device.get_functions();
68
69         if(self.attachments.size()>view_handles.size())
70                 view_handles.resize(self.attachments.size());
71
72         if(handle)
73                 device.get_destroy_queue().destroy(handle);
74
75         VkImageView vk_attachments[FrameFormat::MAX_ATTACHMENTS*2] = { };
76         unsigned i = 0;
77         bool any_resolve = false;
78         for(const Framebuffer::Attachment &a: self.attachments)
79         {
80                 bool use_tex_view = (a.tex->view_type==VK_IMAGE_VIEW_TYPE_2D || (a.tex->view_type==VK_IMAGE_VIEW_TYPE_2D_ARRAY && a.layer<0));
81
82                 if(mask&(1<<i))
83                 {
84                         if(use_tex_view)
85                                 a.tex->refresh_mip_views();
86                         else
87                         {
88                                 if(view_handles[i])
89                                         device.get_destroy_queue().destroy(view_handles[i]);
90
91                                 PixelFormat tex_format = a.tex->get_format();
92
93                                 VkImageViewCreateInfo view_info = { };
94                                 view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
95                                 view_info.image = handle_cast<::VkImage>(a.tex->handle);
96                                 view_info.viewType = (a.layer<0 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D);
97                                 view_info.format = static_cast<VkFormat>(get_vulkan_pixelformat(tex_format));
98
99                                 view_info.components.r = VK_COMPONENT_SWIZZLE_R;
100                                 view_info.components.g = VK_COMPONENT_SWIZZLE_G;
101                                 view_info.components.b = VK_COMPONENT_SWIZZLE_B;
102                                 view_info.components.a = VK_COMPONENT_SWIZZLE_A;
103
104                                 view_info.subresourceRange.aspectMask = get_vulkan_aspect(get_components(tex_format));
105                                 view_info.subresourceRange.baseMipLevel = a.level;
106                                 view_info.subresourceRange.levelCount = 1;
107                                 view_info.subresourceRange.baseArrayLayer = max(a.layer, 0);
108                                 view_info.subresourceRange.layerCount = (a.layer<0 ? VK_REMAINING_ARRAY_LAYERS : 1);
109
110                                 vk.CreateImageView(view_info, view_handles[i]);
111                         }
112                 }
113
114                 if(use_tex_view)
115                         vk_attachments[i] = a.tex->mip_view_handles[a.level];
116                 else if(view_handles[i])
117                         vk_attachments[i] = view_handles[i];
118                 else
119                         throw logic_error("unexpected framebuffer configuration");
120
121                 if(a.resolve)
122                 {
123                         a.resolve->refresh_mip_views();
124                         vk_attachments[self.format.size()+i] = a.resolve->mip_view_handles[0];
125                         any_resolve = true;
126                 }
127
128                 ++i;
129         }
130
131         RenderPass render_pass;
132         render_pass.framebuffer = &self;
133         render_pass.to_present = is_presentable();
134         render_pass.update(device);
135
136         VkFramebufferCreateInfo framebuffer_info = { };
137         framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
138         framebuffer_info.renderPass = handle_cast<::VkRenderPass>(render_pass.handle);
139         framebuffer_info.attachmentCount = self.format.size()*(1+any_resolve);
140         framebuffer_info.pAttachments = handle_cast<::VkImageView *>(vk_attachments);
141         framebuffer_info.width = self.width;
142         framebuffer_info.height = self.height;
143         framebuffer_info.layers = self.layers;
144
145         vk.CreateFramebuffer(framebuffer_info, handle);
146
147         if(!debug_name.empty())
148                 set_vulkan_object_name();
149 }
150
151 void VulkanFramebuffer::synchronize_resources(bool discard) const
152 {
153         for(const Framebuffer::Attachment &a: static_cast<const Framebuffer *>(this)->attachments)
154         {
155                 a.tex->change_layout(a.level, get_vulkan_attachment_layout(get_components(a.tex->get_format())), (discard && a.layer<0));
156                 if(a.resolve)
157                         a.resolve->change_layout(a.level, get_vulkan_attachment_layout(get_components(a.resolve->get_format())), discard);
158         }
159 }
160
161 void VulkanFramebuffer::set_debug_name(const string &name)
162 {
163 #ifdef DEBUG
164         debug_name = name;
165         if(handle)
166                 set_vulkan_object_name();
167 #else
168         (void)name;
169 #endif
170 }
171
172 void VulkanFramebuffer::set_vulkan_object_name() const
173 {
174 #ifdef DEBUG
175         const VulkanFunctions &vk = device.get_functions();
176
177         VkDebugUtilsObjectNameInfoEXT name_info = { };
178         name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
179         name_info.objectType = VK_OBJECT_TYPE_FRAMEBUFFER;
180         name_info.objectHandle = reinterpret_cast<uint64_t>(handle);
181         name_info.pObjectName = debug_name.c_str();
182         vk.SetDebugUtilsObjectName(name_info);
183 #endif
184 }
185
186 } // namespace GL
187 } // namespace Msp