use std::error::Error;
use std::fmt;
use core::{buffer, format, handle, texture, state};
use core::{Primitive, Resources, ShaderSet};
use core::factory::Factory;
use core::pso::{CreationError, Descriptor};
use core::memory::{Bind, Pod, Usage};
use slice::{Slice, IndexBuffer, IntoIndexBuffer};
use pso;
use shade::ProgramError;
#[derive(Clone, PartialEq, Debug)]
pub enum PipelineStateError<S> {
Program(ProgramError),
DescriptorInit(pso::InitError<S>),
DeviceCreate(CreationError),
}
impl<'a> From<PipelineStateError<&'a str>> for PipelineStateError<String> {
fn from(pse: PipelineStateError<&'a str>) -> PipelineStateError<String> {
match pse {
PipelineStateError::Program(e) => PipelineStateError::Program(e),
PipelineStateError::DescriptorInit(e) => PipelineStateError::DescriptorInit(e.into()),
PipelineStateError::DeviceCreate(e) => PipelineStateError::DeviceCreate(e),
}
}
}
impl<S: fmt::Debug + fmt::Display> fmt::Display for PipelineStateError<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
PipelineStateError::Program(ref e) => write!(f, "{}: {}", self.description(), e),
PipelineStateError::DescriptorInit(ref e) => write!(f, "{}: {}", self.description(), e),
PipelineStateError::DeviceCreate(ref e) => write!(f, "{}: {}", self.description(), e),
}
}
}
impl<S: fmt::Debug + fmt::Display> Error for PipelineStateError<S> {
fn description(&self) -> &str {
match *self {
PipelineStateError::Program(_) => "Shader program failed to link",
PipelineStateError::DescriptorInit(_) =>
"Unable to create PSO descriptor due to mismatched formats",
PipelineStateError::DeviceCreate(_) => "Device failed to create the handle give the descriptor",
}
}
fn cause(&self) -> Option<&dyn Error> {
match *self {
PipelineStateError::Program(ref program_error) => Some(program_error),
PipelineStateError::DescriptorInit(ref init_error) => Some(init_error),
PipelineStateError::DeviceCreate(ref creation_error) => Some(creation_error),
}
}
}
impl<S> From<ProgramError> for PipelineStateError<S> {
fn from(e: ProgramError) -> Self {
PipelineStateError::Program(e)
}
}
impl<S> From<pso::InitError<S>> for PipelineStateError<S> {
fn from(e: pso::InitError<S>) -> Self {
PipelineStateError::DescriptorInit(e)
}
}
impl<S> From<CreationError> for PipelineStateError<S> {
fn from(e: CreationError) -> Self {
PipelineStateError::DeviceCreate(e)
}
}
pub trait FactoryExt<R: Resources>: Factory<R> {
fn create_vertex_buffer<T>(&mut self, vertices: &[T])
-> handle::Buffer<R, T>
where T: Pod + pso::buffer::Structure<format::Format>
{
self.create_buffer_immutable(vertices, buffer::Role::Vertex, Bind::empty())
.unwrap()
}
fn create_index_buffer<T>(&mut self, indices: T)
-> IndexBuffer<R>
where T: IntoIndexBuffer<R>
{
indices.into_index_buffer(self)
}
fn create_vertex_buffer_with_slice<B, V>(&mut self, vertices: &[V], indices: B)
-> (handle::Buffer<R, V>, Slice<R>)
where V: Pod + pso::buffer::Structure<format::Format>,
B: IntoIndexBuffer<R>
{
let vertex_buffer = self.create_vertex_buffer(vertices);
let index_buffer = self.create_index_buffer(indices);
let buffer_length = match index_buffer {
IndexBuffer::Auto => vertex_buffer.len(),
IndexBuffer::Index16(ref ib) => ib.len(),
IndexBuffer::Index32(ref ib) => ib.len(),
};
(vertex_buffer, Slice {
start: 0,
end: buffer_length as u32,
base_vertex: 0,
instances: None,
buffer: index_buffer
})
}
fn create_constant_buffer<T>(&mut self, num: usize) -> handle::Buffer<R, T>
where T: Copy
{
self.create_buffer(num,
buffer::Role::Constant,
Usage::Dynamic,
Bind::empty()).unwrap()
}
fn create_upload_buffer<T>(&mut self, num: usize)
-> Result<handle::Buffer<R, T>, buffer::CreationError>
{
self.create_buffer(num,
buffer::Role::Staging,
Usage::Upload,
Bind::TRANSFER_SRC)
}
fn create_download_buffer<T>(&mut self, num: usize)
-> Result<handle::Buffer<R, T>, buffer::CreationError>
{
self.create_buffer(num,
buffer::Role::Staging,
Usage::Download,
Bind::TRANSFER_DST)
}
fn create_shader_set(&mut self, vs_code: &[u8], ps_code: &[u8])
-> Result<ShaderSet<R>, ProgramError> {
let vs = self.create_shader_vertex(vs_code).map_err(ProgramError::Vertex)?;
let ps = self.create_shader_pixel(ps_code).map_err(ProgramError::Pixel)?;
Ok(ShaderSet::Simple(vs, ps))
}
fn create_shader_set_geometry(&mut self, vs_code: &[u8], gs_code: &[u8], ps_code: &[u8])
-> Result<ShaderSet<R>, ProgramError> {
let vs = self.create_shader_vertex(vs_code).map_err(ProgramError::Vertex)?;
let gs = self.create_shader_geometry(gs_code).map_err(ProgramError::Geometry)?;
let ps = self.create_shader_pixel(ps_code).map_err(ProgramError::Pixel)?;
Ok(ShaderSet::Geometry(vs, gs, ps))
}
fn create_shader_set_tessellation(&mut self, vs_code: &[u8], hs_code: &[u8], ds_code: &[u8], ps_code: &[u8])
-> Result<ShaderSet<R>, ProgramError> {
let vs = self.create_shader_vertex(vs_code).map_err(ProgramError::Vertex)?;
let hs = self.create_shader_hull(hs_code).map_err(ProgramError::Hull)?;
let ds = self.create_shader_domain(ds_code).map_err(ProgramError::Domain)?;
let ps = self.create_shader_pixel(ps_code).map_err(ProgramError::Pixel)?;
Ok(ShaderSet::Tessellated(vs, hs, ds, ps))
}
fn create_shader_set_tessellation_with_geometry(&mut self, vs_code: &[u8], hs_code: &[u8], ds_code: &[u8], gs_code: &[u8], ps_code: &[u8])
-> Result<ShaderSet<R>, ProgramError> {
let vs = self.create_shader_vertex(vs_code).map_err(ProgramError::Vertex)?;
let hs = self.create_shader_hull(hs_code).map_err(ProgramError::Hull)?;
let ds = self.create_shader_domain(ds_code).map_err(ProgramError::Domain)?;
let gs = self.create_shader_geometry(gs_code).map_err(ProgramError::Geometry)?;
let ps = self.create_shader_pixel(ps_code).map_err(ProgramError::Pixel)?;
Ok(ShaderSet::TessellatedGeometry(vs, hs, ds, gs, ps))
}
fn link_program(&mut self, vs_code: &[u8], ps_code: &[u8])
-> Result<handle::Program<R>, ProgramError> {
let set = try!(self.create_shader_set(vs_code, ps_code));
self.create_program(&set).map_err(|e| ProgramError::Link(e))
}
fn create_pipeline_state<I: pso::PipelineInit>(&mut self, shaders: &ShaderSet<R>,
primitive: Primitive, rasterizer: state::Rasterizer, init: I)
-> Result<pso::PipelineState<R, I::Meta>, PipelineStateError<String>>
{
let program = try!(self.create_program(shaders).map_err(|e| ProgramError::Link(e)));
self.create_pipeline_from_program(&program, primitive, rasterizer, init).map_err(|error| {
use self::PipelineStateError::*;
match error {
Program(e) => Program(e),
DescriptorInit(e) => DescriptorInit(e.into()),
DeviceCreate(e) => DeviceCreate(e),
}
})
}
fn create_pipeline_from_program<'a, I: pso::PipelineInit>(&mut self, program: &'a handle::Program<R>,
primitive: Primitive, rasterizer: state::Rasterizer, init: I)
-> Result<pso::PipelineState<R, I::Meta>, PipelineStateError<&'a str>>
{
let mut descriptor = Descriptor::new(primitive, rasterizer);
let meta = try!(init.link_to(&mut descriptor, program.get_info()));
let raw = try!(self.create_pipeline_state_raw(program, &descriptor));
Ok(pso::PipelineState::new(raw, primitive, meta))
}
fn create_pipeline_simple<I: pso::PipelineInit>(&mut self, vs: &[u8], ps: &[u8], init: I)
-> Result<pso::PipelineState<R, I::Meta>, PipelineStateError<String>>
{
let set = try!(self.create_shader_set(vs, ps));
self.create_pipeline_state(&set, Primitive::TriangleList, state::Rasterizer::new_fill(),
init)
}
fn create_sampler_linear(&mut self) -> handle::Sampler<R> {
self.create_sampler(texture::SamplerInfo::new(
texture::FilterMethod::Trilinear,
texture::WrapMode::Clamp,
))
}
}
impl<R: Resources, F: Factory<R>> FactoryExt<R> for F {}