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 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
//! Graphics context.
//!
//! # Graphics context and backends
//!
//! A graphics context is an external type typically implemented by other crates and which provides
//! support for backends. Its main scope is to unify all possible implementations of backends
//! behind a single trait: [`GraphicsContext`]. A [`GraphicsContext`] really only requires two items
//! to be implemented:
//!
//! - The type of the backend to use — [`GraphicsContext::Backend`]. That type will often be used
//! to access the GPU, cache costly operations, etc.
//! - A method to get a mutable access to the underlying backend — [`GraphicsContext::backend`].
//!
//! Most of the time, if you want to work with _any_ windowing implementation, you will want to
//! use a type variable such as `C: GraphicsContext`. If you want to work with any context
//! supporting a specific backend, use `C: GraphicsContext<Backend = YourBackendType`. Etc.
//!
//! This crate doesn’t provide you with creating such contexts. Instead, you must do it yourself
//! or rely on crates doing it for you.
//!
//! # Default implementation of helper functions
//!
//! By default, graphics contexts automatically get several methods implemented on them. Those
//! methods are helper functions available to write code in a more elegant and compact way than
//! passing around mutable references on the context. Often, it will help you not having to
//! use type ascription, too, since the [`GraphicsContext::Backend`] type is known when calling
//! those functions.
//!
//! Instead of:
//!
//! ```ignore
//! use luminance::context::GraphicsContext as _;
//! use luminance::buffer::Buffer;
//!
//! let buffer: Buffer<SomeBackendType, u8> = Buffer::from_slice(&mut context, slice).unwrap();
//! ```
//!
//! You can simply do:
//!
//! ```ignore
//! use luminance::context::GraphicsContext as _;
//!
//! let buffer = context.new_buffer_from_slice(slice).unwrap();
//! ```
use crate::{
backend::{
color_slot::ColorSlot,
depth_stencil_slot::DepthStencilSlot,
framebuffer::Framebuffer as FramebufferBackend,
query::Query as QueryBackend,
shader::{Shader, ShaderData as ShaderDataBackend},
tess::Tess as TessBackend,
texture::Texture as TextureBackend,
},
texture::TexelUpload,
};
use crate::{
framebuffer::{Framebuffer, FramebufferError},
pipeline::PipelineGate,
pixel::Pixel,
query::Query,
shader::{ProgramBuilder, ShaderData, ShaderDataError, Stage, StageError, StageType},
tess::{Deinterleaved, Interleaved, TessBuilder, TessVertexData},
texture::{Dimensionable, Sampler, Texture, TextureError},
vertex::Semantics,
};
/// Class of graphics context.
///
/// Graphics context must implement this trait to be able to be used throughout the rest of the
/// crate.
pub unsafe trait GraphicsContext: Sized {
/// Internal type used by the backend to cache, optimize and store data. This roughly represents
/// the GPU data / context a backend implementation needs to work correctly.
type Backend;
/// Access the underlying backend.
fn backend(&mut self) -> &mut Self::Backend;
/// Access the query API.
fn query(&mut self) -> Query<Self::Backend>
where
Self::Backend: QueryBackend,
{
Query::new(self)
}
/// Create a new pipeline gate
fn new_pipeline_gate(&mut self) -> PipelineGate<Self::Backend> {
PipelineGate::new(self)
}
/// Create a new framebuffer.
///
/// See the documentation of [`Framebuffer::new`] for further details.
fn new_framebuffer<D, CS, DS>(
&mut self,
size: D::Size,
mipmaps: usize,
sampler: Sampler,
) -> Result<Framebuffer<Self::Backend, D, CS, DS>, FramebufferError>
where
Self::Backend: FramebufferBackend<D>,
D: Dimensionable,
CS: ColorSlot<Self::Backend, D>,
DS: DepthStencilSlot<Self::Backend, D>,
{
Framebuffer::new(self, size, mipmaps, sampler)
}
/// Create a new shader stage.
///
/// See the documentation of [`Stage::new`] for further details.
fn new_shader_stage<R>(
&mut self,
ty: StageType,
src: R,
) -> Result<Stage<Self::Backend>, StageError>
where
Self::Backend: Shader,
R: AsRef<str>,
{
Stage::new(self, ty, src)
}
/// Create a new shader program.
///
/// See the documentation of [`ProgramBuilder::new`] for further details.
fn new_shader_program<Sem, Out, Uni>(&mut self) -> ProgramBuilder<Self, Sem, Out, Uni>
where
Self::Backend: Shader,
Sem: Semantics,
{
ProgramBuilder::new(self)
}
/// Create a new shader data.
///
/// See the documentation of [`ShaderData::new`] for further details.
fn new_shader_data<T>(
&mut self,
values: impl IntoIterator<Item = T>,
) -> Result<ShaderData<Self::Backend, T>, ShaderDataError>
where
Self::Backend: ShaderDataBackend<T>,
{
ShaderData::new(self, values)
}
/// Create a [`TessBuilder`].
///
/// See the documentation of [`TessBuilder::new`] for further details.
fn new_tess(&mut self) -> TessBuilder<Self::Backend, (), (), (), Interleaved>
where
Self::Backend: TessBackend<(), (), (), Interleaved>,
{
TessBuilder::new(self)
}
/// Create a [`TessBuilder`] with deinterleaved memory.
///
/// See the documentation of [`TessBuilder::new`] for further details.
fn new_deinterleaved_tess<V, W>(&mut self) -> TessBuilder<Self::Backend, V, (), W, Deinterleaved>
where
Self::Backend: TessBackend<V, (), W, Deinterleaved>,
V: TessVertexData<Deinterleaved>,
W: TessVertexData<Deinterleaved>,
{
TessBuilder::new(self)
}
/// Create a new texture from texels.
///
/// Feel free to have a look at the documentation of [`Texture::new`] for further details.
fn new_texture<D, P>(
&mut self,
size: D::Size,
sampler: Sampler,
texels: TexelUpload<[P::Encoding]>,
) -> Result<Texture<Self::Backend, D, P>, TextureError>
where
Self::Backend: TextureBackend<D, P>,
D: Dimensionable,
P: Pixel,
{
Texture::new(self, size, sampler, texels)
}
/// Create a new texture from raw texels.
///
/// Feel free to have a look at the documentation of [`Texture::new_raw`] for further details.
fn new_texture_raw<D, P>(
&mut self,
size: D::Size,
sampler: Sampler,
texels: TexelUpload<[P::RawEncoding]>,
) -> Result<Texture<Self::Backend, D, P>, TextureError>
where
Self::Backend: TextureBackend<D, P>,
D: Dimensionable,
P: Pixel,
{
Texture::new_raw(self, size, sampler, texels)
}
}