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}