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