use crate::buffer::{VertexAttr, VertexInfo};
use crate::color::Color;
use crate::device::{DropManager, ResourceId};
use crate::{Device, ShaderSource};
use std::sync::Arc;
#[derive(Debug)]
struct PipelineIdRef {
id: u64,
drop_manager: Arc<DropManager>,
}
impl Drop for PipelineIdRef {
fn drop(&mut self) {
self.drop_manager.push(ResourceId::Pipeline(self.id));
}
}
#[derive(Debug, Clone)]
pub struct Pipeline {
id: u64,
_id_ref: Arc<PipelineIdRef>,
stride: usize,
pub options: PipelineOptions,
}
impl std::cmp::PartialEq for Pipeline {
fn eq(&self, other: &Self) -> bool {
self.id() == other.id() && self.options == other.options
}
}
impl Pipeline {
pub(crate) fn new(
id: u64,
stride: usize,
options: PipelineOptions,
drop_manager: Arc<DropManager>,
) -> Self {
let id_ref = Arc::new(PipelineIdRef { id, drop_manager });
Self {
id,
_id_ref: id_ref,
stride,
options,
}
}
#[inline(always)]
pub fn id(&self) -> u64 {
self.id
}
#[inline(always)]
pub fn stride(&self) -> usize {
self.stride
}
#[inline(always)]
pub fn offset(&self) -> usize {
self.stride / 4
}
}
enum ShaderKind<'b> {
Raw {
vertex: &'b [u8],
fragment: &'b [u8],
},
Source {
vertex: &'b ShaderSource<'b>,
fragment: &'b ShaderSource<'b>,
},
}
pub struct PipelineBuilder<'a, 'b> {
device: &'a mut Device,
attrs: Vec<VertexAttr>,
options: PipelineOptions,
shaders: Option<ShaderKind<'b>>,
texture_locations: Vec<(u32, String)>,
}
impl<'a, 'b> PipelineBuilder<'a, 'b> {
pub fn new(device: &'a mut Device) -> Self {
Self {
device,
attrs: vec![],
options: Default::default(),
shaders: None,
texture_locations: vec![],
}
}
pub fn from(mut self, vertex: &'b ShaderSource, fragment: &'b ShaderSource) -> Self {
self.shaders = Some(ShaderKind::Source { vertex, fragment });
self
}
#[allow(clippy::wrong_self_convention)]
pub fn from_raw(mut self, vertex: &'b [u8], fragment: &'b [u8]) -> Self {
self.shaders = Some(ShaderKind::Raw { vertex, fragment });
self
}
pub fn with_vertex_info(mut self, info: &VertexInfo) -> Self {
self.attrs.extend(&info.attrs);
self
}
pub fn with_texture_location(mut self, location: u32, id: &str) -> Self {
self.texture_locations.push((location, id.to_string()));
self
}
pub fn with_color_blend(mut self, color_blend: BlendMode) -> Self {
self.options.color_blend = Some(color_blend);
self
}
pub fn with_alpha_blend(mut self, alpha_blend: BlendMode) -> Self {
self.options.alpha_blend = Some(alpha_blend);
self
}
pub fn with_cull_mode(mut self, cull_mode: CullMode) -> Self {
self.options.cull_mode = cull_mode;
self
}
pub fn with_depth_stencil(mut self, depth_stencil: DepthStencil) -> Self {
self.options.depth_stencil = depth_stencil;
self
}
pub fn with_color_mask(mut self, color_mask: ColorMask) -> Self {
self.options.color_mask = color_mask;
self
}
pub fn with_stencil(mut self, stencil: StencilOptions) -> Self {
self.options.stencil = Some(stencil);
self
}
pub fn build(self) -> Result<Pipeline, String> {
match self.shaders {
Some(ShaderKind::Source { vertex, fragment }) => self.device.inner_create_pipeline(
vertex,
fragment,
&self.attrs,
&self.texture_locations,
self.options,
),
Some(ShaderKind::Raw { vertex, fragment }) => {
self.device.inner_create_pipeline_from_raw(
vertex,
fragment,
&self.attrs,
&self.texture_locations,
self.options,
)
}
_ => Err("Vertex and Fragment shaders should be present".to_string()),
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum BlendFactor {
Zero,
One,
SourceColor,
InverseSourceColor,
DestinationColor,
InverseDestinationColor,
SourceAlpha,
InverseSourceAlpha,
DestinationAlpha,
InverseDestinationAlpha,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum BlendOperation {
Add,
Subtract,
ReverseSubtract,
Min,
Max,
}
#[derive(Debug, Clone, Eq, PartialEq, Copy)]
pub struct BlendMode {
pub src: BlendFactor,
pub dst: BlendFactor,
pub op: BlendOperation,
}
impl BlendMode {
pub const NONE: BlendMode = BlendMode {
src: BlendFactor::One,
dst: BlendFactor::Zero,
op: BlendOperation::Add,
};
pub const NORMAL: BlendMode = BlendMode {
src: BlendFactor::SourceAlpha,
dst: BlendFactor::InverseSourceAlpha,
op: BlendOperation::Add,
};
pub const ADD: BlendMode = BlendMode {
src: BlendFactor::One,
dst: BlendFactor::One,
op: BlendOperation::Add,
};
pub const MULTIPLY: BlendMode = BlendMode {
src: BlendFactor::DestinationColor,
dst: BlendFactor::InverseSourceAlpha,
op: BlendOperation::Add,
};
pub const SCREEN: BlendMode = BlendMode {
src: BlendFactor::One,
dst: BlendFactor::InverseSourceColor,
op: BlendOperation::Add,
};
pub const ERASE: BlendMode = BlendMode {
src: BlendFactor::Zero,
dst: BlendFactor::InverseSourceColor,
op: BlendOperation::Add,
};
pub const OVER: BlendMode = BlendMode {
src: BlendFactor::One,
dst: BlendFactor::InverseSourceAlpha,
op: BlendOperation::Add,
};
pub fn new(source: BlendFactor, destination: BlendFactor) -> Self {
Self::with_operation(source, destination, BlendOperation::Add)
}
pub fn with_operation(
source: BlendFactor,
destination: BlendFactor,
operation: BlendOperation,
) -> Self {
Self {
src: source,
dst: destination,
op: operation,
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum CompareMode {
None,
Less,
Equal,
LEqual,
Greater,
NotEqual,
GEqual,
Always,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum CullMode {
None,
Front,
Back,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct ColorMask {
pub r: bool,
pub g: bool,
pub b: bool,
pub a: bool,
}
impl Default for ColorMask {
fn default() -> Self {
Self {
r: true,
g: true,
b: true,
a: true,
}
}
}
impl ColorMask {
pub const ALL: ColorMask = ColorMask {
r: true,
g: true,
b: true,
a: true,
};
pub const NONE: ColorMask = ColorMask {
r: false,
g: false,
b: false,
a: false,
};
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct DepthStencil {
pub write: bool,
pub compare: CompareMode,
}
impl Default for DepthStencil {
fn default() -> Self {
Self {
write: true,
compare: CompareMode::None, }
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct PipelineOptions {
pub color_blend: Option<BlendMode>,
pub alpha_blend: Option<BlendMode>,
pub cull_mode: CullMode,
pub depth_stencil: DepthStencil,
pub color_mask: ColorMask,
pub stencil: Option<StencilOptions>,
}
impl Default for PipelineOptions {
fn default() -> Self {
Self {
depth_stencil: Default::default(),
cull_mode: CullMode::None,
color_blend: None,
alpha_blend: None,
color_mask: Default::default(),
stencil: None,
}
}
}
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct ClearOptions {
pub color: Option<Color>,
pub depth: Option<f32>,
pub stencil: Option<i32>,
}
impl ClearOptions {
pub fn color(color: Color) -> Self {
Self {
color: Some(color),
..Default::default()
}
}
pub fn none() -> Self {
Self::default()
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum DrawType {
Static,
Dynamic,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum StencilAction {
Keep,
Zero,
Replace,
Increment,
IncrementWrap,
Decrement,
DecrementWrap,
Invert,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct StencilOptions {
pub stencil_fail: StencilAction,
pub depth_fail: StencilAction,
pub pass: StencilAction,
pub compare: CompareMode,
pub read_mask: u32,
pub write_mask: u32,
pub reference: u32,
}
impl Default for StencilOptions {
fn default() -> Self {
Self {
stencil_fail: StencilAction::Keep,
depth_fail: StencilAction::Keep,
pass: StencilAction::Keep,
compare: CompareMode::Always,
read_mask: 0xff,
write_mask: 0,
reference: 0,
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum DrawPrimitive {
Lines,
LineStrip,
Triangles,
TriangleStrip,
}
impl Default for DrawPrimitive {
fn default() -> Self {
DrawPrimitive::Triangles
}
}