]> git.tdb.fi Git - libs/gl.git/blob - source/backends/vulkan/commands_backend.cpp
bf8ee3f13d5652c21a14db09ff1e077e016740cc
[libs/gl.git] / source / backends / vulkan / commands_backend.cpp
1 #include <msp/core/hash.h>
2 #include <msp/graphics/vulkancontext_platform.h>
3 #include "batch.h"
4 #include "commands_backend.h"
5 #include "device.h"
6 #include "error.h"
7 #include "framebuffer.h"
8 #include "frameformat.h"
9 #include "pipelinestate.h"
10 #include "rect.h"
11 #include "semaphore.h"
12 #include "structurebuilder.h"
13 #include "swapchaintexture.h"
14 #include "vulkan.h"
15
16 using namespace std;
17
18 namespace Msp {
19 namespace GL {
20
21 VulkanCommands::VulkanCommands():
22         device(Device::get_current())
23 { }
24
25 VulkanCommands::~VulkanCommands()
26 {
27         const VulkanFunctions &vk = device.get_functions();
28
29         vk.QueueWaitIdle();
30 }
31
32 void VulkanCommands::begin_buffer(VkRenderPass render_pass)
33 {
34         if(frame_index>=command_pools.size())
35                 throw invalid_operation("VulkanCommands::begin_buffer");
36
37         const VulkanFunctions &vk = device.get_functions();
38
39         CommandPool *current_pool = &command_pools[frame_index];
40         if(!current_pool->in_use)
41         {
42                 current_pool->fence.reset();
43                 current_pool->in_use = true;
44         }
45
46         CommandBuffers &buffers = (render_pass ? current_pool->secondary : current_pool->primary);
47
48         if(buffers.next_buffer>=buffers.buffers.size())
49         {
50                 VkCommandBufferAllocateInfo alloc_info = { };
51                 alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
52                 alloc_info.commandPool = handle_cast<::VkCommandPool>(current_pool->pool);
53                 alloc_info.level = (render_pass ? VK_COMMAND_BUFFER_LEVEL_SECONDARY : VK_COMMAND_BUFFER_LEVEL_PRIMARY);
54                 alloc_info.commandBufferCount = 1;
55
56                 VkCommandBuffer buffer;
57                 vk.AllocateCommandBuffers(alloc_info, &buffer);
58                 buffers.buffers.push_back(buffer);
59         }
60
61         VkCommandBuffer buffer = buffers.buffers[buffers.next_buffer++];
62         (render_pass ? pass_buffer : primary_buffer) = buffer;
63
64         VkCommandBufferBeginInfo begin_info = { };
65         begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
66         begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
67         if(render_pass)
68                 begin_info.flags |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
69
70         VkCommandBufferInheritanceInfo inherit_info = { };
71         if(render_pass)
72         {
73                 inherit_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
74                 inherit_info.renderPass = handle_cast<::VkRenderPass>(render_pass);
75                 inherit_info.subpass = 0;
76
77                 begin_info.pInheritanceInfo = &inherit_info;
78         }
79
80         vk.BeginCommandBuffer(buffer, begin_info);
81 }
82
83 void VulkanCommands::begin_render_pass(bool clear, const ClearValue *clear_values)
84 {
85         framebuffer = pipeline_state->get_framebuffer();
86         if(!framebuffer)
87                 throw invalid_operation("VulkanCommands::begin_render_pass");
88
89         viewport = pipeline_state->get_viewport();
90
91         if(!primary_buffer)
92                 begin_buffer(0);
93
94         fb_is_swapchain = false;
95         unsigned n_attachments = framebuffer->get_format().size();
96         for(unsigned i=0; (!fb_is_swapchain && i<n_attachments); ++i)
97                 if(dynamic_cast<const SwapChainTexture *>(framebuffer->get_attachment(i)))
98                         fb_is_swapchain = true;
99
100         discard_fb_contents = (clear && !viewport);
101
102         framebuffer->refresh();
103
104         VkRenderPass render_pass = device.get_pipeline_cache().get_render_pass(framebuffer->get_format(), clear, (!clear_values && !viewport), fb_is_swapchain);
105         begin_buffer(render_pass);
106
107         StructureBuilder sb(pass_begin_info, 2);
108         VkRenderPassBeginInfo *&begin_info = sb.add<VkRenderPassBeginInfo>(1);
109         VkClearValue *&vk_clear_values = sb.add<VkClearValue>(FrameFormat::MAX_ATTACHMENTS);
110
111         begin_info->sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
112         begin_info->renderPass = handle_cast<::VkRenderPass>(render_pass);
113         begin_info->framebuffer = handle_cast<::VkFramebuffer>(framebuffer->handle);
114
115         if(viewport)
116         {
117                 begin_info->renderArea.offset.x = viewport->left;
118                 begin_info->renderArea.offset.y = viewport->bottom;
119                 begin_info->renderArea.extent.width = viewport->width;
120                 begin_info->renderArea.extent.height = viewport->height;
121         }
122         else
123         {
124                 begin_info->renderArea.extent.width = framebuffer->get_width();
125                 begin_info->renderArea.extent.height = framebuffer->get_height();
126         }
127
128         if(clear_values)
129         {
130                 unsigned i = 0;
131                 for(FrameAttachment a: framebuffer->get_format())
132                 {
133                         if(get_attach_point(a)==get_attach_point(DEPTH_ATTACHMENT))
134                                 vk_clear_values[i].depthStencil.depth = clear_values[i].depth_stencil.depth;
135                         else if(get_attach_point(a)==get_attach_point(STENCIL_ATTACHMENT))
136                                 vk_clear_values[i].depthStencil.stencil = clear_values[i].depth_stencil.stencil;
137                         else
138                         {
139                                 vk_clear_values[i].color.float32[0] = clear_values[i].color.r;
140                                 vk_clear_values[i].color.float32[1] = clear_values[i].color.g;
141                                 vk_clear_values[i].color.float32[2] = clear_values[i].color.b;
142                                 vk_clear_values[i].color.float32[3] = clear_values[i].color.a;
143                         }
144                         ++i;
145                 }
146
147                 begin_info->clearValueCount = framebuffer->get_format().size();
148                 begin_info->pClearValues = vk_clear_values;
149         }
150 }
151
152 void VulkanCommands::end_render_pass()
153 {
154         const VulkanFunctions &vk = device.get_functions();
155
156         vk.EndCommandBuffer(pass_buffer);
157
158         device.get_transfer_queue().dispatch_transfers(primary_buffer);
159
160         Synchronizer &sync = device.get_synchronizer();
161         sync.reset();
162         if(!fb_is_swapchain)
163                 framebuffer->prepare_image_layouts(discard_fb_contents);
164         sync.barrier(primary_buffer);
165
166         const VkRenderPassBeginInfo &begin_info = *reinterpret_cast<const VkRenderPassBeginInfo *>(pass_begin_info.data());
167         vk.CmdBeginRenderPass(primary_buffer, begin_info, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
168         vk.CmdExecuteCommands(primary_buffer, 1, &pass_buffer);
169         vk.CmdEndRenderPass(primary_buffer);
170
171         framebuffer = 0;
172         viewport = 0;
173         pass_buffer = 0;
174 }
175
176 void VulkanCommands::begin_frame(unsigned index)
177 {
178         const VulkanFunctions &vk = device.get_functions();
179
180         frame_index = index%device.get_n_frames_in_flight();
181         if(frame_index>=command_pools.size())
182         {
183                 command_pools.reserve(frame_index+1);
184                 for(unsigned i=command_pools.size(); i<frame_index+1; ++i)
185                         command_pools.emplace_back(device);
186         }
187
188         CommandPool *current_pool = &command_pools[frame_index];
189         if(current_pool->in_use)
190         {
191                 current_pool->fence.wait();
192                 vk.ResetCommandPool(current_pool->pool, 0);
193                 current_pool->in_use = false;
194                 current_pool->primary.next_buffer = 0;
195                 current_pool->secondary.next_buffer = 0;
196         }
197 }
198
199 void VulkanCommands::submit_frame(Semaphore *wait_sem, Semaphore *signal_sem)
200 {
201         if(!primary_buffer)
202                 return;
203
204         const VulkanFunctions &vk = device.get_functions();
205         ::VkSemaphore vk_wait_sem = (wait_sem ? handle_cast<::VkSemaphore>(wait_sem->handle) : 0);
206         ::VkSemaphore vk_signal_sem = (signal_sem ? handle_cast<::VkSemaphore>(signal_sem->handle) : 0);
207         VkPipelineStageFlags wait_stages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
208
209         if(framebuffer)
210                 end_render_pass();
211
212         vk.EndCommandBuffer(primary_buffer);
213
214         VkSubmitInfo submit_info = { };
215         submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
216         submit_info.waitSemaphoreCount = (wait_sem ? 1 : 0);
217         submit_info.pWaitSemaphores = &vk_wait_sem;
218         submit_info.pWaitDstStageMask = &wait_stages;
219         submit_info.commandBufferCount = 1;
220         submit_info.pCommandBuffers = handle_cast<::VkCommandBuffer *>(&primary_buffer);
221         submit_info.signalSemaphoreCount = (signal_sem ? 1 : 0);
222         submit_info.pSignalSemaphores = &vk_signal_sem;
223
224         vk.QueueSubmit(1, &submit_info, command_pools[frame_index].fence.handle);
225
226         primary_buffer = 0;
227 }
228
229 void VulkanCommands::use_pipeline(const PipelineState *ps)
230 {
231         if(!pipeline_state || !ps || ps->get_framebuffer()!=framebuffer || ps->get_viewport()!=viewport)
232                 if(framebuffer)
233                         end_render_pass();
234
235         pipeline_state = ps;
236 }
237
238 void VulkanCommands::clear(const ClearValue *values)
239 {
240         if(framebuffer)
241                 throw invalid_operation("VulkanCommands::clear");
242
243         begin_render_pass(true, values);
244 }
245
246 void VulkanCommands::draw(const Batch &batch)
247 {
248         draw_instanced(batch, 1);
249 }
250
251 void VulkanCommands::draw_instanced(const Batch &batch, unsigned count)
252 {
253         if(!pipeline_state)
254                 throw invalid_operation("VulkanCommands::draw_instanced");
255
256         const VulkanFunctions &vk = device.get_functions();
257
258         if(!framebuffer)
259                  begin_render_pass(false, 0);
260
261         pipeline_state->refresh();
262         pipeline_state->apply(pass_buffer, frame_index, fb_is_swapchain);
263         unsigned first_index = batch.get_offset()/batch.get_index_size();
264         vk.CmdDrawIndexed(pass_buffer, batch.size(), count, first_index, 0, 0);
265 }
266
267 void VulkanCommands::resolve_multisample(Framebuffer &)
268 {
269         throw logic_error("VulkanCommands::resolve_multisample is unimplemented");
270 }
271
272 void VulkanCommands::begin_query(const QueryPool &, unsigned)
273 {
274         throw logic_error("VulkanCommands::begin_query is unimplemented");
275 }
276
277 void VulkanCommands::end_query(const QueryPool &, unsigned)
278 {
279         throw logic_error("VulkanCommands::end_query is unimplemented");
280 }
281
282
283 VulkanCommands::CommandPool::CommandPool(Device &d):
284         device(d),
285         fence(true)
286 {
287         const VulkanFunctions &vk = device.get_functions();
288
289         VkCommandPoolCreateInfo pool_info = { };
290         pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
291         pool_info.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
292         pool_info.queueFamilyIndex = device.get_context().get_private().graphics_queue_family;
293
294         vk.CreateCommandPool(pool_info, pool);
295 }
296
297 VulkanCommands::CommandPool::CommandPool(CommandPool &&other):
298         device(other.device),
299         pool(other.pool),
300         fence(move(other.fence)),
301         in_use(other.in_use)
302 {
303         other.pool = 0;
304 }
305
306 VulkanCommands::CommandPool::~CommandPool()
307 {
308         const VulkanFunctions &vk = device.get_functions();
309
310         if(pool)
311                 vk.DestroyCommandPool(pool);
312 }
313
314 } // namespace GL
315 } // namespace Msp