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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
//! Pipeline backend interface.
//!
//! This interface defines the low-level API pipelines must implement to be usable.
//!
//! A (graphics) pipeline is a strongly typed object that represents a set of actions to perform to render a scene into
//! a framebuffer. This module exposes the required traits to implement to perform various actions in the pipeline.
//!
//! The most important one is [`PipelineBase`], that provides pipeline creation. This doesn’t feel like much but it’s
//! actually an important part of the backend interface. Besides telling the backend to prepare the pipeline creation,
//! this also serves for the backend to allocate and cache some values in their state so that they don’t get created
//! every time a user starts a pipeline, making dynamic pipeline creation cheap and possible.
//!
//! The [`Pipeline`] trait is the « entry-point » of a render. It takes a [`Framebuffer`] and a [`PipelineState`] and
//! put both objects to the backend to start a render.
//!
//! [`PipelineTexture`], [`PipelineShaderData`] etc. are used to scope-bind specific resources, such as textures and
//! shader data.
//!
//! [`Framebuffer`]: crate::framebuffer::Framebuffer

use crate::{
  backend::{
    framebuffer::Framebuffer as FramebufferBackend,
    shader::ShaderData,
    shading_gate::ShadingGate as ShadingGateBackend,
    texture::{Texture, TextureBase},
  },
  pipeline::{PipelineError, PipelineState},
  pixel::Pixel,
  texture::Dimensionable,
};

/// The base trait of pipelines.
///
/// This trait exposes the [`PipelineBase::new_pipeline`] method, which is called when a new pipeline is created. The
/// backend must create and allocate the data required to execute graphics pipelines, and is strongly advised to cache
/// that data so that this method is cheap after the first frame.
///
/// This trait has [`ShadingGate`] and [`TextureBase`] as super traits, as those are required to perform more operations
/// on pipelines.
///
/// [`ShadingGate`]: crate::backend::shading_gate::ShadingGate
pub unsafe trait PipelineBase: ShadingGateBackend + TextureBase {
  type PipelineRepr;

  /// Create a new (cached) pipeline.
  unsafe fn new_pipeline(&mut self) -> Result<Self::PipelineRepr, PipelineError>;
}

/// Start a pipeline.
///
/// This trait requires [`PipelineBase`] and [`Framebuffer`], as it starts rendering into one.
///
/// [`Framebuffer`]: crate::backend::framebuffer::Framebuffer
pub unsafe trait Pipeline<D>: PipelineBase + FramebufferBackend<D>
where
  D: Dimensionable,
{
  /// Start a pipeline that will output in the input [`Framebuffer`] and the given [`PipelineState`].
  ///
  /// This method should perform the required backend action to take into account the framebuffer and the state to start
  /// the pipeline.
  ///
  /// [`Framebuffer`]: crate::backend::framebuffer::Framebuffer
  unsafe fn start_pipeline(
    &mut self,
    framebuffer: &Self::FramebufferRepr,
    pipeline_state: &PipelineState,
  );
}

/// Operations that can be run on pipelines and textures.
///
/// This trait requires [`PipelineBase`] and [`Texture`].
pub unsafe trait PipelineTexture<D, P>: PipelineBase + Texture<D, P>
where
  D: Dimensionable,
  P: Pixel,
{
  /// Representation of a _bound_ [`Texture`] on the backend.
  type BoundTextureRepr;

  /// Bind a [`Texture`] to the current [`Pipeline`].
  ///
  /// This method must bind the texture on the backend and return an object representing the bound texture. Must of the
  /// time, this bound representation will also implement [`Drop`] so that backend resources are freed and recycled on
  /// the next bind.
  unsafe fn bind_texture(
    pipeline: &Self::PipelineRepr,
    texture: &Self::TextureRepr,
  ) -> Result<Self::BoundTextureRepr, PipelineError>
  where
    D: Dimensionable,
    P: Pixel;

  /// Get the `u32` representation of the bound texture, also known as binding.
  unsafe fn texture_binding(bound: &Self::BoundTextureRepr) -> u32;
}

/// Operations that can be run on pipelines and shader data.
///
/// This trait requires [`PipelineBase`] and [`ShaderData`].
pub unsafe trait PipelineShaderData<T>: PipelineBase + ShaderData<T> {
  /// Representation of a _bound_ [`ShaderData`] on the backend.
  type BoundShaderDataRepr;

  /// Bind a [`ShaderData`] to the current [`Pipeline`].
  ///
  /// This method must bind the shader data on the backend and return an object representing the bound shader data. Must
  /// of the time, this bound representation will also implement [`Drop`] so that backend resources are freed and
  /// recycled on the next bind.
  unsafe fn bind_shader_data(
    pipeline: &Self::PipelineRepr,
    shader_data: &Self::ShaderDataRepr,
  ) -> Result<Self::BoundShaderDataRepr, PipelineError>;

  /// Get the `u32` representation of the bound shader data, also known as binding.
  unsafe fn shader_data_binding(bound: &Self::BoundShaderDataRepr) -> u32;
}