Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change RefreshSync loop mode to wait on previous frame presentation #239

Merged
merged 1 commit into from
Jan 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 36 additions & 26 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1501,14 +1501,14 @@ where
// This method cleans up any unused resources associated with this GPU future.
fn cleanup_unused_gpu_resources_for_window(app: &App, window_id: window::Id) {
let windows = app.windows.borrow();
windows[&window_id]
let mut guard = windows[&window_id]
.swapchain
.previous_frame_end
.lock()
.expect("failed to lock `previous_frame_end`")
.as_mut()
.expect("`previous_frame_end` was `None`")
.cleanup_finished();
.expect("failed to lock `previous_frame_end`");
if let Some(future) = guard.as_mut() {
future.cleanup_finished();
}
}

// Returns `true` if the window's swapchain needs to be recreated.
Expand Down Expand Up @@ -2008,43 +2008,53 @@ where

let mut windows = app.windows.borrow_mut();
let window = windows.get_mut(&window_id).expect("no window for id");
let future = window

// Wait for the previous frame presentation to be finished to avoid out-pacing the GPU on macos.
if let Some(mut previous_frame_fence_signal_future) = window
.swapchain
.previous_frame_end
.lock()
.expect("failed to lock `previous_frame_end`")
.take()
.expect("`previous_frame_end` was `None`")
.join(swapchain_image_acquire_future)
.then_execute(queue.clone(), command_buffer)
.expect("failed to execute future")
// The image color output is now expected to contain the user's graphics.
// But in order to show it on the screen, we have to `present` the image.
.then_swapchain_present(
queue.clone(),
swapchain.swapchain.clone(),
swapchain_image_index,
)
// Flush forwards the future to the GPU to begin the actual processing.
.then_signal_fence_and_flush();
let previous_frame_end = match future {
Ok(future) => {
Some(Box::new(future) as Box<_>)
}
{
previous_frame_fence_signal_future.cleanup_finished();
previous_frame_fence_signal_future
.wait(None)
.expect("failed to wait for `previous_frame_end` future to signal fence");
}

// The future associated with the end of the current frame.
let future_result = {
let present_future = swapchain_image_acquire_future
.then_execute(queue.clone(), command_buffer)
.expect("failed to execute future")
.then_swapchain_present(
queue.clone(),
swapchain.swapchain.clone(),
swapchain_image_index,
);
(Box::new(present_future) as Box<GpuFuture>)
.then_signal_fence_and_flush()
};

// Handle the result of the future.
let current_frame_end = match future_result {
Ok(future) => Some(future),
Err(vulkano::sync::FlushError::OutOfDate) => {
window.swapchain.needs_recreation.store(true, atomic::Ordering::Relaxed);
Some(Box::new(vulkano::sync::now(queue.device().clone())) as Box<_>)
None
}
Err(e) => {
println!("{:?}", e);
Some(Box::new(vulkano::sync::now(queue.device().clone())) as Box<_>)
None
}
};

*window
.swapchain
.previous_frame_end
.lock()
.expect("failed to acquire `previous_frame_end` lock") = previous_frame_end;
.expect("failed to acquire `previous_frame_end` lock") = current_frame_end;
}

// Acquire the next swapchain image for the given window and draw to it using the user's
Expand Down
16 changes: 5 additions & 11 deletions src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use vulkano::framebuffer::{AttachmentsList, Framebuffer, FramebufferAbstract, Fr
use vulkano::instance::PhysicalDevice;
use vulkano::swapchain::{ColorSpace, CompositeAlpha, PresentMode, SurfaceTransform,
SwapchainCreationError};
use vulkano::sync::GpuFuture;
use vulkano::sync::{FenceSignalFuture, GpuFuture};
use vulkano_win::{VkSurfaceBuild};
use winit::{self, MonitorId, MouseCursor};
use winit::dpi::LogicalSize;
Expand Down Expand Up @@ -251,11 +251,7 @@ pub(crate) struct WindowSwapchain {
//
// Destroying the `GpuFuture` blocks until the GPU is finished executing it. In order to avoid
// that, we store the submission of the previous frame here.
//
// This is initialised to `Some(vulkano::sync::now(device))`. An `Option` is used to allow for
// taking ownership in the application loop where we are required to join `previous_frame_end`
// with the future associated with acquiring an image from the GPU.
pub(crate) previous_frame_end: Mutex<Option<Box<GpuFuture>>>,
pub(crate) previous_frame_end: Mutex<Option<FenceSignalFuture<Box<GpuFuture>>>>,
}

/// Swapchain building parameters for which Nannou will provide a default if unspecified.
Expand Down Expand Up @@ -955,8 +951,7 @@ impl<'app> Builder<'app> {

let window_id = surface.window().id();
let needs_recreation = AtomicBool::new(false);
let now = Box::new(vulkano::sync::now(queue.device().clone())) as Box<GpuFuture>;
let previous_frame_end = Mutex::new(Some(now));
let previous_frame_end = Mutex::new(None);
let frame_count = 0;
let swapchain = Arc::new(WindowSwapchain {
needs_recreation,
Expand Down Expand Up @@ -1341,14 +1336,13 @@ impl Window {
.previous_frame_end
.lock()
.expect("failed to lock `previous_frame_end`")
.take()
.expect("`previous_frame_end` was `None`");
.take();
self.swapchain = Arc::new(WindowSwapchain {
needs_recreation: AtomicBool::new(false),
frame_created: self.frame_count,
swapchain: new_swapchain,
images: new_images,
previous_frame_end: Mutex::new(Some(previous_frame_end)),
previous_frame_end: Mutex::new(previous_frame_end),
});
}
}
Expand Down