logo
 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>;
}