wgpu/api/
surface_texture.rs

1use std::{error, fmt, thread};
2
3use crate::context::DynContext;
4use crate::*;
5
6/// Surface texture that can be rendered to.
7/// Result of a successful call to [`Surface::get_current_texture`].
8///
9/// This type is unique to the Rust API of `wgpu`. In the WebGPU specification,
10/// the [`GPUCanvasContext`](https://gpuweb.github.io/gpuweb/#canvas-context) provides
11/// a texture without any additional information.
12#[derive(Debug)]
13pub struct SurfaceTexture {
14    /// Accessible view of the frame.
15    pub texture: Texture,
16    /// `true` if the acquired buffer can still be used for rendering,
17    /// but should be recreated for maximum performance.
18    pub suboptimal: bool,
19    pub(crate) presented: bool,
20    pub(crate) detail: Box<dyn AnyWasmNotSendSync>,
21}
22#[cfg(send_sync)]
23static_assertions::assert_impl_all!(SurfaceTexture: Send, Sync);
24
25impl SurfaceTexture {
26    /// Schedule this texture to be presented on the owning surface.
27    ///
28    /// Needs to be called after any work on the texture is scheduled via [`Queue::submit`].
29    ///
30    /// # Platform dependent behavior
31    ///
32    /// On Wayland, `present` will attach a `wl_buffer` to the underlying `wl_surface` and commit the new surface
33    /// state. If it is desired to do things such as request a frame callback, scale the surface using the viewporter
34    /// or synchronize other double buffered state, then these operations should be done before the call to `present`.
35    pub fn present(mut self) {
36        self.presented = true;
37        DynContext::surface_present(
38            &*self.texture.context,
39            // This call to as_ref is essential because we want the DynContext implementation to see the inner
40            // value of the Box (T::SurfaceOutputDetail), not the Box itself.
41            self.detail.as_ref(),
42        );
43    }
44}
45
46impl Drop for SurfaceTexture {
47    fn drop(&mut self) {
48        if !self.presented && !thread::panicking() {
49            DynContext::surface_texture_discard(
50                &*self.texture.context,
51                // This call to as_ref is essential because we want the DynContext implementation to see the inner
52                // value of the Box (T::SurfaceOutputDetail), not the Box itself.
53                self.detail.as_ref(),
54            );
55        }
56    }
57}
58
59/// Result of an unsuccessful call to [`Surface::get_current_texture`].
60#[derive(Clone, PartialEq, Eq, Debug)]
61pub enum SurfaceError {
62    /// A timeout was encountered while trying to acquire the next frame.
63    Timeout,
64    /// The underlying surface has changed, and therefore the swap chain must be updated.
65    Outdated,
66    /// The swap chain has been lost and needs to be recreated.
67    Lost,
68    /// There is no more memory left to allocate a new frame.
69    OutOfMemory,
70}
71static_assertions::assert_impl_all!(SurfaceError: Send, Sync);
72
73impl fmt::Display for SurfaceError {
74    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75        write!(f, "{}", match self {
76            Self::Timeout => "A timeout was encountered while trying to acquire the next frame",
77            Self::Outdated => "The underlying surface has changed, and therefore the swap chain must be updated",
78            Self::Lost =>  "The swap chain has been lost and needs to be recreated",
79            Self::OutOfMemory => "There is no more memory left to allocate a new frame",
80        })
81    }
82}
83
84impl error::Error for SurfaceError {}