luminance/backend/
framebuffer.rs

1//! Framebuffer backend interface.
2//!
3//! This interface defines the low-level API framebuffers must implement to be usable.
4
5use crate::{
6  backend::{color_slot::ColorSlot, depth_stencil_slot::DepthStencilSlot, texture::TextureBase},
7  framebuffer::FramebufferError,
8  texture::{Dim2, Dimensionable, Sampler},
9};
10
11/// Framebuffer backend.
12///
13/// A type implementing [`Framebuffer`] must implement [`TextureBase`] in the first place, because framebuffers and
14/// textures have a strong relationship.
15///
16/// Framebuffers implement a strong type contract with the safe interface and are associated with
17/// [`ColorSlot`] and [`DepthStencilSlot`]. Those types provide associated types to adapt the kind
18/// of data that will be allocated and provided to the user. For instance, if you want to have a
19/// framebuffer that will not have any depth information, you can use `()` as a
20/// [`DepthStencilSlot`]. The backends will then not allocate anything and no depth data will be
21/// present at runtime.
22///
23/// The whole process of implementing this trait revolves around three main aspects:
24///
25/// 1. How to create the framebuffer on the backend. This is the [`Framebuffer::new_framebuffer`] method.
26/// 2. How to attach color and depth data, which are [`Framebuffer::attach_color_texture`] and
27///   [`Framebuffer::attach_depth_texture`].
28/// 3. Valide the resulting framebuffer.
29///
30/// `D` is the dimension of the framebuffer, which must implement [`Dimensionable`], reifying the dimension at runtime.
31/// This is a useful type to the backends, as it will provide methods to get the size, offsets, etc. to correctly create textures.
32pub unsafe trait Framebuffer<D>: TextureBase
33where
34  D: Dimensionable,
35{
36  /// Backend representation of the framebuffer.
37  type FramebufferRepr;
38
39  /// Create a new framebuffer on the backend.
40  ///
41  /// `CS` is the [`ColorSlot`] and `DS` is the [`DepthStencilSlot`]. This function must create the part that is _only_
42  /// relevant to the framebuffer, not to the color slots directly. It can still allocate enough storage for the slots
43  /// but it doesn’t have the handles / representations of the slots yet.
44  unsafe fn new_framebuffer<CS, DS>(
45    &mut self,
46    size: D::Size,
47    mipmaps: usize,
48    sampler: &Sampler,
49  ) -> Result<Self::FramebufferRepr, FramebufferError>
50  where
51    CS: ColorSlot<Self, D>,
52    DS: DepthStencilSlot<Self, D>;
53
54  /// Attach a single color data to the framebuffer.
55  ///
56  /// The `attachment_index` gives the rank of the texture in the case of MRT. This method will never be called if the
57  /// color slot is `()`.
58  unsafe fn attach_color_texture(
59    framebuffer: &mut Self::FramebufferRepr,
60    texture: &Self::TextureRepr,
61    attachment_index: usize,
62  ) -> Result<(), FramebufferError>;
63
64  /// Attach a single depth data to the framebuffer.
65  ///
66  /// This method will never be called if the depth slot is `()`.
67  unsafe fn attach_depth_texture(
68    framebuffer: &mut Self::FramebufferRepr,
69    texture: &Self::TextureRepr,
70  ) -> Result<(), FramebufferError>;
71
72  /// Validate the status of the framebuffer.
73  ///
74  /// This function is required because of the multi-step process required to create a full framebuffer. Once the
75  /// framebuffer is created and its color and depth slots added, that method is called to ensure the state of the
76  /// framebuffer is correct.
77  unsafe fn validate_framebuffer(
78    framebuffer: Self::FramebufferRepr,
79  ) -> Result<Self::FramebufferRepr, FramebufferError>;
80
81  /// Get the size of the framebuffer.
82  ///
83  /// The size is currently stored on the backend side, so this function extracts it from the backend.
84  unsafe fn framebuffer_size(framebuffer: &Self::FramebufferRepr) -> D::Size;
85}
86
87/// Back buffer.
88///
89/// A back buffer is a special kind of [`Framebuffer`]. It’s a 2D (c.f. [`Dim2`]) framebuffer that is provided
90/// exclusively by the backend. Even though it should be cached by the application, its method is — most of the
91/// time — cheap to call, so it can be called in a render loop.
92pub unsafe trait FramebufferBackBuffer: Framebuffer<Dim2> {
93  /// Get the back buffer from the backend.
94  ///
95  /// The `size` argument should match the current size of the actual system framebuffer. Because this value depends on
96  /// the system platform, it is not possible to compute it directly.
97  unsafe fn back_buffer(
98    &mut self,
99    size: <Dim2 as Dimensionable>::Size,
100  ) -> Result<Self::FramebufferRepr, FramebufferError>;
101}