Skip to content

Commit 54430d3

Browse files
committed
examples: Wait earlier for command-buffer fence to prevent semaphore reuse
This solves `VUID-vkAcquireNextImageKHR-semaphore-01779` where `acquire_next_image()` is asked to signal a semaphore that may still be waited on by the currently-running submit. Since the next submit is reusing the existing command buffer and resources as well it must inevitably wait on a fence from the previous frame/submit, pulling out that fence to wait on it is the most practical approach despite teaching bad/slow practices. Note that this fence was also used to "reuse" the setup command buffer in the `texture` sample; this was instead generalized to use another command buffer without waiting for and signaling any fence.
1 parent 151047d commit 54430d3

File tree

2 files changed

+24
-24
lines changed

2 files changed

+24
-24
lines changed

ash-examples/src/bin/texture.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,8 +352,8 @@ fn main() -> Result<(), Box<dyn Error>> {
352352

353353
record_submit_commandbuffer(
354354
&base.device,
355-
base.setup_command_buffer,
356-
base.setup_commands_reuse_fence,
355+
base.app_setup_command_buffer,
356+
vk::Fence::null(),
357357
base.present_queue,
358358
&[],
359359
&[],

ash-examples/src/lib.rs

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,7 @@ macro_rules! offset_of {
3636
}
3737
}};
3838
}
39-
/// Helper function for submitting command buffers. Immediately waits for the fence before the command buffer
40-
/// is executed. That way we can delay the waiting for the fences by 1 frame which is good for performance.
41-
/// Make sure to create the fence in a signaled state on the first use.
39+
4240
#[allow(clippy::too_many_arguments)]
4341
pub fn record_submit_commandbuffer<F: FnOnce(&Device, vk::CommandBuffer)>(
4442
device: &Device,
@@ -51,14 +49,6 @@ pub fn record_submit_commandbuffer<F: FnOnce(&Device, vk::CommandBuffer)>(
5149
f: F,
5250
) {
5351
unsafe {
54-
device
55-
.wait_for_fences(&[command_buffer_reuse_fence], true, u64::MAX)
56-
.expect("Wait for fence failed.");
57-
58-
device
59-
.reset_fences(&[command_buffer_reuse_fence])
60-
.expect("Reset fences failed.");
61-
6252
device
6353
.reset_command_buffer(
6454
command_buffer,
@@ -161,6 +151,7 @@ pub struct ExampleBase {
161151
pub pool: vk::CommandPool,
162152
pub draw_command_buffer: vk::CommandBuffer,
163153
pub setup_command_buffer: vk::CommandBuffer,
154+
pub app_setup_command_buffer: vk::CommandBuffer,
164155

165156
pub depth_image: vk::Image,
166157
pub depth_image_view: vk::ImageView,
@@ -170,7 +161,6 @@ pub struct ExampleBase {
170161
pub rendering_complete_semaphores: Vec<vk::Semaphore>,
171162

172163
pub draw_commands_reuse_fence: vk::Fence,
173-
pub setup_commands_reuse_fence: vk::Fence,
174164
}
175165

176166
impl ExampleBase {
@@ -194,7 +184,21 @@ impl ExampleBase {
194184
} => {
195185
elwp.exit();
196186
}
197-
Event::AboutToWait => f(),
187+
Event::AboutToWait => {
188+
unsafe {
189+
self.device.wait_for_fences(
190+
&[self.draw_commands_reuse_fence],
191+
true,
192+
u64::MAX,
193+
)
194+
}
195+
.expect("Wait for fence failed.");
196+
197+
unsafe { self.device.reset_fences(&[self.draw_commands_reuse_fence]) }
198+
.expect("Reset fences failed.");
199+
200+
f()
201+
}
198202
_ => (),
199203
}
200204
})
@@ -400,15 +404,16 @@ impl ExampleBase {
400404
let pool = device.create_command_pool(&pool_create_info, None).unwrap();
401405

402406
let command_buffer_allocate_info = vk::CommandBufferAllocateInfo::default()
403-
.command_buffer_count(2)
407+
.command_buffer_count(3)
404408
.command_pool(pool)
405409
.level(vk::CommandBufferLevel::PRIMARY);
406410

407411
let command_buffers = device
408412
.allocate_command_buffers(&command_buffer_allocate_info)
409413
.unwrap();
410414
let setup_command_buffer = command_buffers[0];
411-
let draw_command_buffer = command_buffers[1];
415+
let app_setup_command_buffer = command_buffers[1];
416+
let draw_command_buffer = command_buffers[2];
412417

413418
let present_images = swapchain_loader.get_swapchain_images(swapchain).unwrap();
414419
let present_image_views: Vec<vk::ImageView> = present_images
@@ -473,14 +478,11 @@ impl ExampleBase {
473478
let draw_commands_reuse_fence = device
474479
.create_fence(&fence_create_info, None)
475480
.expect("Create fence failed.");
476-
let setup_commands_reuse_fence = device
477-
.create_fence(&fence_create_info, None)
478-
.expect("Create fence failed.");
479481

480482
record_submit_commandbuffer(
481483
&device,
482484
setup_command_buffer,
483-
setup_commands_reuse_fence,
485+
vk::Fence::null(),
484486
present_queue,
485487
&[],
486488
&[],
@@ -561,12 +563,12 @@ impl ExampleBase {
561563
pool,
562564
draw_command_buffer,
563565
setup_command_buffer,
566+
app_setup_command_buffer,
564567
depth_image,
565568
depth_image_view,
566569
present_complete_semaphore,
567570
rendering_complete_semaphores,
568571
draw_commands_reuse_fence,
569-
setup_commands_reuse_fence,
570572
surface,
571573
debug_call_back,
572574
debug_utils_loader,
@@ -587,8 +589,6 @@ impl Drop for ExampleBase {
587589
}
588590
self.device
589591
.destroy_fence(self.draw_commands_reuse_fence, None);
590-
self.device
591-
.destroy_fence(self.setup_commands_reuse_fence, None);
592592
self.device.free_memory(self.depth_image_memory, None);
593593
self.device.destroy_image_view(self.depth_image_view, None);
594594
self.device.destroy_image(self.depth_image, None);

0 commit comments

Comments
 (0)