lambda_platform/gfx/
fence.rs

1//! GPU synchronization Implementations that are built on top of gfx-hal and
2//! are used by the lambda-platform rendering implementations to synchronize
3//! GPU operations.
4
5use gfx_hal::device::Device;
6
7pub struct RenderSemaphoreBuilder {}
8
9impl RenderSemaphoreBuilder {
10  pub fn new() -> Self {
11    return Self {};
12  }
13
14  /// Builds a new render semaphore using the provided GPU. This semaphore can
15  /// only be used with the GPU that it was created with.
16  pub fn build<RenderBackend: gfx_hal::Backend>(
17    self,
18    gpu: &mut super::gpu::Gpu<RenderBackend>,
19  ) -> RenderSemaphore<RenderBackend> {
20    let semaphore = gpu
21      .internal_logical_device()
22      .create_semaphore()
23      .expect("The GPU has no memory to allocate the semaphore");
24
25    return RenderSemaphore { semaphore };
26  }
27}
28
29/// Render semaphores are used to synchronize operations happening within the
30/// GPU. This allows for us to tell the GPU to wait for a frame to finish
31/// rendering before presenting it to the screen.
32pub struct RenderSemaphore<RenderBackend: gfx_hal::Backend> {
33  semaphore: RenderBackend::Semaphore,
34}
35
36impl<RenderBackend: gfx_hal::Backend> RenderSemaphore<RenderBackend> {
37  /// Destroys the semaphore using the GPU that created it.
38  pub fn destroy(self, gpu: &super::gpu::Gpu<RenderBackend>) {
39    unsafe {
40      gpu
41        .internal_logical_device()
42        .destroy_semaphore(self.semaphore)
43    }
44  }
45}
46
47impl<RenderBackend: gfx_hal::Backend> RenderSemaphore<RenderBackend> {
48  /// Retrieve a reference to the internal semaphore.
49  pub(super) fn internal_semaphore(&self) -> &RenderBackend::Semaphore {
50    return &self.semaphore;
51  }
52
53  /// Retrieve a mutable reference to the internal semaphore.
54  pub(super) fn internal_semaphore_mut(
55    &mut self,
56  ) -> &mut RenderBackend::Semaphore {
57    return &mut self.semaphore;
58  }
59}
60
61pub struct RenderSubmissionFenceBuilder {
62  default_render_timeout: u64,
63}
64
65impl RenderSubmissionFenceBuilder {
66  /// Creates a new Render Submission Fence Builder that defaults to a 1 second
67  /// timeout for waiting on the fence.
68  pub fn new() -> Self {
69    return Self {
70      default_render_timeout: 1_000_000_000,
71    };
72  }
73
74  /// Provides a default render timeout in nanoseconds. This render timeout is
75  /// used to reset the submission fence if it's time-to-live expires.
76  pub fn with_render_timeout(mut self, render_timeout: u64) -> Self {
77    self.default_render_timeout = render_timeout;
78    return self;
79  }
80
81  /// Builds a new submission fence using the provided GPU. This fence can only
82  /// be used to block operation on the GPU that created it.
83  pub fn build<RenderBackend: gfx_hal::Backend>(
84    self,
85    gpu: &mut super::gpu::Gpu<RenderBackend>,
86  ) -> RenderSubmissionFence<RenderBackend> {
87    let fence = gpu
88      .internal_logical_device()
89      .create_fence(true)
90      .expect("There is not enough memory to create a fence on this device.");
91
92    return RenderSubmissionFence {
93      fence,
94      default_render_timeout: self.default_render_timeout,
95    };
96  }
97}
98
99/// A GPU fence is used to synchronize GPU operations. It is used to ensure that
100/// a GPU operation has completed before the CPU attempts to submit commands to
101/// it.
102pub struct RenderSubmissionFence<RenderBackend: gfx_hal::Backend> {
103  fence: RenderBackend::Fence,
104  default_render_timeout: u64,
105}
106
107impl<RenderBackend: gfx_hal::Backend> RenderSubmissionFence<RenderBackend> {
108  /// Block a GPU until the fence is ready and then reset the fence status.
109  pub fn block_until_ready(
110    &mut self,
111    gpu: &mut super::gpu::Gpu<RenderBackend>,
112    render_timeout_override: Option<u64>,
113  ) {
114    let timeout = match render_timeout_override {
115      Some(render_timeout_override) => render_timeout_override,
116      None => self.default_render_timeout,
117    };
118
119    unsafe {
120      gpu.internal_logical_device()
121        .wait_for_fence(&self.fence, timeout)
122    }
123    .expect("The GPU ran out of memory or has become detached from the current context.");
124
125    unsafe { gpu.internal_logical_device().reset_fence(&mut self.fence) }
126      .expect("The fence failed to reset.");
127  }
128
129  /// Destroy this fence given the GPU that created it.
130  pub fn destroy(self, gpu: &super::gpu::Gpu<RenderBackend>) {
131    unsafe { gpu.internal_logical_device().destroy_fence(self.fence) }
132  }
133}
134
135impl<RenderBackend: gfx_hal::Backend> RenderSubmissionFence<RenderBackend> {
136  /// Retrieve the underlying fence.
137  pub fn internal_fence(&self) -> &RenderBackend::Fence {
138    return &self.fence;
139  }
140
141  /// Retrieve a mutable reference to the underlying fence.
142  pub fn internal_fence_mut(&mut self) -> &mut RenderBackend::Fence {
143    return &mut self.fence;
144  }
145}