From eb8d4ae78fd3e7d1f7e9f4288e66db1a9fa3f048 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Mon, 23 Feb 2015 20:02:42 +1100 Subject: [PATCH 1/5] Decouple render::shade from GlResources --- examples/cube/main.rs | 4 +- examples/deferred/main.rs | 16 +++--- examples/performance/main.rs | 2 +- examples/terrain/main.rs | 2 +- examples/triangle/main.rs | 2 +- src/gfx/lib.rs | 8 +-- src/gfx_macros/shader_param.rs | 14 ++++- src/render/batch.rs | 93 +++++++++++++++++----------------- src/render/lib.rs | 6 +-- src/render/shade.rs | 33 +++++++----- tests/shader_param.rs | 8 +-- 11 files changed, 103 insertions(+), 85 deletions(-) diff --git a/examples/cube/main.rs b/examples/cube/main.rs index e79a24f6690..12595977405 100644 --- a/examples/cube/main.rs +++ b/examples/cube/main.rs @@ -46,7 +46,7 @@ struct Params { transform: [[f32; 4]; 4], #[name = "t_Color"] - color: gfx::shade::TextureParam, + color: gfx::shade::TextureParam, } static VERTEX_SRC: &'static [u8] = b" @@ -174,7 +174,7 @@ fn main() { let state = gfx::DrawState::new().depth(gfx::state::Comparison::LessEqual, true); - let batch: RefBatch = { + let batch: RefBatch = { context.make_batch(&program, &mesh, slice, &state) .ok().expect("Failed to make batch.") }; diff --git a/examples/deferred/main.rs b/examples/deferred/main.rs index b8e041000e8..04e4e9a40ae 100644 --- a/examples/deferred/main.rs +++ b/examples/deferred/main.rs @@ -109,11 +109,11 @@ struct LightParams { #[name = "u_FrameRes"] frame_res: [f32; 2], #[name = "u_TexPos"] - tex_pos: gfx::shade::TextureParam, + tex_pos: gfx::shade::TextureParam, #[name = "u_TexNormal"] - tex_normal: gfx::shade::TextureParam, + tex_normal: gfx::shade::TextureParam, #[name = "u_TexDiffuse"] - tex_diffuse: gfx::shade::TextureParam, + tex_diffuse: gfx::shade::TextureParam, } #[shader_param] @@ -129,7 +129,7 @@ struct EmitterParams { #[shader_param] struct BlitParams { #[name = "u_Tex"] - tex: gfx::shade::TextureParam, + tex: gfx::shade::TextureParam, } static TERRAIN_VERTEX_SRC: &'static [u8] = b" @@ -402,7 +402,7 @@ fn main() { }; let terrain_scale = Vector3::new(25.0, 25.0, 25.0); - let terrain_batch: RefBatch = { + let terrain_batch: RefBatch = { let plane = genmesh::generators::Plane::subdivide(256, 256); let vertex_data: Vec = plane.shared_vertex_iter() .map(|(x, y)| { @@ -435,7 +435,7 @@ fn main() { .ok().expect("Failed to match back") }; - let blit_batch: RefBatch = { + let blit_batch: RefBatch = { let vertex_data = [ BlitVertex { pos: [-1, -1, 0], tex_coord: [0, 0] }, BlitVertex { pos: [ 1, -1, 0], tex_coord: [1, 0] }, @@ -507,7 +507,7 @@ fn main() { .depth(gfx::state::Comparison::LessEqual, false) .blend(gfx::BlendPreset::Additive); - let light_batch: RefBatch = { + let light_batch: RefBatch = { let program = device.link_program(LIGHT_VERTEX_SRC, LIGHT_FRAGMENT_SRC) .ok().expect("Failed to link program."); @@ -515,7 +515,7 @@ fn main() { .ok().expect("Failed to create batch") }; - let emitter_batch: RefBatch = { + let emitter_batch: RefBatch = { let program = device.link_program(EMITTER_VERTEX_SRC, EMITTER_FRAGMENT_SRC) .ok().expect("Failed to link program."); diff --git a/examples/performance/main.rs b/examples/performance/main.rs index 665aad80b33..5caa72fec1e 100644 --- a/examples/performance/main.rs +++ b/examples/performance/main.rs @@ -130,7 +130,7 @@ fn gfx_main(mut glfw: glfw::Glfw, }; let mut graphics = gfx::Graphics::new(device); - let batch: RefBatch = { + let batch: RefBatch = { graphics.make_batch(&program, &mesh, slice, &state) .ok().expect("Failed to make batch") }; diff --git a/examples/terrain/main.rs b/examples/terrain/main.rs index 1f598487728..ffab7686782 100644 --- a/examples/terrain/main.rs +++ b/examples/terrain/main.rs @@ -163,7 +163,7 @@ fn main() { let state = gfx::DrawState::new().depth(gfx::state::Comparison::LessEqual, true); let mut graphics = gfx::Graphics::new(device); - let batch: RefBatch = { + let batch: RefBatch = { graphics.make_batch(&program, &mesh, slice, &state) .ok().expect("Failed to make batch.") }; diff --git a/examples/triangle/main.rs b/examples/triangle/main.rs index 522ccec964c..3433dfae0d0 100644 --- a/examples/triangle/main.rs +++ b/examples/triangle/main.rs @@ -103,7 +103,7 @@ fn main() { renderer.reset(); renderer.clear(clear_data, gfx::COLOR, &frame); - renderer.draw(&(&mesh, slice.clone(), &program, &(), &state), &frame).unwrap(); + renderer.draw(&(&mesh, slice.clone(), &program, &None, &state), &frame).unwrap(); device.submit(renderer.as_buffer()); window.swap_buffers(); diff --git a/src/gfx/lib.rs b/src/gfx/lib.rs index fef4190d1bd..0066e044dc0 100644 --- a/src/gfx/lib.rs +++ b/src/gfx/lib.rs @@ -72,12 +72,12 @@ impl Graphics { } /// Create a new ref batch. - pub fn make_batch(&mut self, + pub fn make_batch>(&mut self, program: &ProgramHandle, mesh: &Mesh, slice: Slice, state: &DrawState) - -> Result, batch::BatchError> { + -> Result, batch::BatchError> { self.context.make_batch(program, mesh, slice, state) } @@ -87,8 +87,8 @@ impl Graphics { } /// Draw a ref batch. - pub fn draw<'a, T: shade::ShaderParam>(&'a mut self, - batch: &'a batch::RefBatch, data: &'a T, frame: &Frame) + pub fn draw<'a, T: shade::ShaderParam>(&'a mut self, + batch: &'a batch::RefBatch, data: &'a T, frame: &Frame) -> Result<(), DrawError> { self.renderer.draw(&(batch, data, &self.context), frame) } diff --git a/src/gfx_macros/shader_param.rs b/src/gfx_macros/shader_param.rs index be254fdf47b..76a3bb7f701 100644 --- a/src/gfx_macros/shader_param.rs +++ b/src/gfx_macros/shader_param.rs @@ -363,7 +363,16 @@ impl ItemDecorator for ShaderParam { generic::ty::Borrowed(None, ast::MutImmutable) ), generic::ty::Literal( - generic::ty::Path::new(vec![super::EXTERN_CRATE_HACK, "gfx", "shade", "ParamValues"]), + generic::ty::Path { + path: vec![super::EXTERN_CRATE_HACK, "gfx", "shade", "ParamValues"], + lifetime: None, + params: vec![ + box generic::ty::Literal(generic::ty::Path::new( + vec![super::EXTERN_CRATE_HACK, "gfx", "GlResources"] + )), + ], + global: false, + }, ), ], ret_ty: generic::ty::Tuple(Vec::new()), @@ -374,6 +383,9 @@ impl ItemDecorator for ShaderParam { }, ], associated_types: vec![ + (context.ident_of("Resources"), generic::ty::Literal( + generic::ty::Path::new(vec![super::EXTERN_CRATE_HACK, "gfx", "GlResources"]), + )), (context.ident_of("Link"), link_ty), ], }; diff --git a/src/render/batch.rs b/src/render/batch.rs index 5bb89840066..7ff8921f89c 100644 --- a/src/render/batch.rs +++ b/src/render/batch.rs @@ -20,7 +20,6 @@ use std::fmt; use std::num::from_uint; use std::cmp::Ordering; use std::marker::PhantomData; -use device::back; use device::{Resources, PrimitiveType, ProgramHandle}; use device::shade::ProgramInfo; use render::mesh; @@ -69,8 +68,8 @@ pub fn link_mesh(mesh: &mesh::Mesh, pinfo: &ProgramInfo) -> Res } /// Return type for `Batch::get_data()`` -pub type BatchData<'a> = (&'a mesh::Mesh, mesh::AttributeIter, - &'a mesh::Slice, &'a DrawState); +pub type BatchData<'a, R: Resources> = (&'a mesh::Mesh, mesh::AttributeIter, + &'a mesh::Slice, &'a DrawState); /// Abstract batch trait pub trait Batch { @@ -78,18 +77,18 @@ pub trait Batch { /// Possible errors occurring at batch access type Error: fmt::Debug; /// Obtain information about the mesh, program, and state - fn get_data(&self) -> Result; + fn get_data(&self) -> Result, Self::Error>; /// Fill shader parameter values - fn fill_params(&self, ::shade::ParamValues) + fn fill_params(&self, ::shade::ParamValues) -> Result<&ProgramHandle, Self::Error>; } -impl<'a, T: ShaderParam> Batch for (&'a mesh::Mesh, mesh::Slice, - &'a ProgramHandle, &'a T, &'a DrawState) { - type Resources = back::GlResources; +impl<'a, T: ShaderParam> Batch for (&'a mesh::Mesh, mesh::Slice, + &'a ProgramHandle, &'a T, &'a DrawState) { + type Resources = T::Resources; type Error = BatchError; - fn get_data(&self) -> Result { + fn get_data(&self) -> Result, BatchError> { let (mesh, ref slice, program, _, state) = *self; match link_mesh(mesh, program.get_info()) { Ok(link) => Ok((mesh, link.to_iter(), &slice, state)), @@ -97,8 +96,8 @@ impl<'a, T: ShaderParam> Batch for (&'a mesh::Mesh, mesh::Sli } } - fn fill_params(&self, values: ::shade::ParamValues) - -> Result<&ProgramHandle, BatchError> { + fn fill_params(&self, values: ::shade::ParamValues) + -> Result<&ProgramHandle, BatchError> { let (_, _, program, params, _) = *self; match ShaderParam::create_link(None::<&T>, program.get_info()) { Ok(link) => { @@ -111,23 +110,23 @@ impl<'a, T: ShaderParam> Batch for (&'a mesh::Mesh, mesh::Sli } /// Owned batch - self-contained, but has heap-allocated data -pub struct OwnedBatch { - mesh: mesh::Mesh, +pub struct OwnedBatch { + mesh: mesh::Mesh, mesh_link: mesh::Link, /// Mesh slice - pub slice: mesh::Slice, + pub slice: mesh::Slice, /// Parameter data. pub param: T, - program: ProgramHandle, + program: ProgramHandle, param_link: T::Link, /// Draw state pub state: DrawState, } -impl OwnedBatch { +impl OwnedBatch { /// Create a new owned batch - pub fn new(mesh: mesh::Mesh, program: ProgramHandle, param: T) - -> Result, BatchError> { + pub fn new(mesh: mesh::Mesh, program: ProgramHandle, param: T) + -> Result, BatchError> { let slice = mesh.to_slice(PrimitiveType::TriangleList); let mesh_link = match link_mesh(&mesh, program.get_info()) { Ok(l) => l, @@ -149,16 +148,16 @@ impl OwnedBatch { } } -impl Batch for OwnedBatch { - type Resources = back::GlResources; +impl Batch for OwnedBatch { + type Resources = T::Resources; type Error = (); - fn get_data(&self) -> Result { + fn get_data(&self) -> Result, ()> { Ok((&self.mesh, self.mesh_link.to_iter(), &self.slice, &self.state)) } - fn fill_params(&self, values: ::shade::ParamValues) - -> Result<&ProgramHandle, ()> { + fn fill_params(&self, values: ::shade::ParamValues) + -> Result<&ProgramHandle, ()> { self.param.fill_params(&self.param_link, values); Ok(&self.program) } @@ -250,59 +249,59 @@ impl Array { /// Ref batch - copyable and smaller, but depends on the `Context`. /// It has references to the resources (mesh, program, state), that are held /// by the context that created the batch, so these have to be used together. -pub struct RefBatch { - mesh_id: Id>, +pub struct RefBatch { + mesh_id: Id>, mesh_link: mesh::Link, /// Mesh slice - pub slice: mesh::Slice, - program_id: Id>, + pub slice: mesh::Slice, + program_id: Id>, param_link: T::Link, state_id: Id, } -impl Copy for RefBatch where T::Link: Copy {} +impl Copy for RefBatch where T::Link: Copy {} -impl fmt::Debug for RefBatch { +impl fmt::Debug for RefBatch { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "RefBatch(mesh: {:?}, slice: {:?}, program: {:?}, state: {:?})", self.mesh_id, self.slice, self.program_id, self.state_id) } } -impl PartialEq for RefBatch { - fn eq(&self, other: &RefBatch) -> bool { +impl PartialEq for RefBatch { + fn eq(&self, other: &RefBatch) -> bool { self.program_id == other.program_id && self.state_id == other.state_id && self.mesh_id == other.mesh_id } } -impl Eq for RefBatch {} +impl Eq for RefBatch {} -impl PartialOrd for RefBatch { - fn partial_cmp(&self, other: &RefBatch) -> Option { +impl PartialOrd for RefBatch { + fn partial_cmp(&self, other: &RefBatch) -> Option { Some(self.cmp(other)) } } -impl Ord for RefBatch { - fn cmp(&self, other: &RefBatch) -> Ordering { +impl Ord for RefBatch { + fn cmp(&self, other: &RefBatch) -> Ordering { (&self.program_id, &self.state_id, &self.mesh_id).cmp( &(&other.program_id, &other.state_id, &other.mesh_id)) } } -impl RefBatch { +impl RefBatch { /// Compare meshes by Id - pub fn cmp_mesh(&self, other: &RefBatch) -> Ordering { + pub fn cmp_mesh(&self, other: &RefBatch) -> Ordering { self.mesh_id.cmp(&other.mesh_id) } /// Compare programs by Id - pub fn cmp_program(&self, other: &RefBatch) -> Ordering { + pub fn cmp_program(&self, other: &RefBatch) -> Ordering { self.program_id.cmp(&other.program_id) } /// Compare draw states by Id - pub fn cmp_state(&self, other: &RefBatch) -> Ordering { + pub fn cmp_state(&self, other: &RefBatch) -> Ordering { self.state_id.cmp(&other.state_id) } } @@ -327,12 +326,12 @@ impl Context { impl Context { /// Produce a new ref batch - pub fn make_batch(&mut self, + pub fn make_batch>(&mut self, program: &ProgramHandle, mesh: &mesh::Mesh, slice: mesh::Slice, state: &DrawState) - -> Result, BatchError> { + -> Result, BatchError> { let mesh_link = match link_mesh(mesh, program.get_info()) { Ok(l) => l, Err(e) => return Err(BatchError::Mesh(e)), @@ -365,11 +364,11 @@ impl Context { } } -impl<'a, T: ShaderParam> Batch for (&'a RefBatch, &'a T, &'a Context) { - type Resources = back::GlResources; +impl<'a, T: ShaderParam> Batch for (&'a RefBatch, &'a T, &'a Context) { + type Resources = T::Resources; type Error = OutOfBounds; - fn get_data(&self) -> Result { + fn get_data(&self) -> Result, OutOfBounds> { let (b, _, ctx) = *self; Ok((try!(ctx.meshes.get(b.mesh_id)), b.mesh_link.to_iter(), @@ -378,8 +377,8 @@ impl<'a, T: ShaderParam> Batch for (&'a RefBatch, &'a T, & )) } - fn fill_params(&self, values: ::shade::ParamValues) - -> Result<&ProgramHandle, OutOfBounds> { + fn fill_params(&self, values: ::shade::ParamValues) + -> Result<&ProgramHandle, OutOfBounds> { let (b, data, ctx) = *self; data.fill_params(&b.param_link, values); ctx.programs.get(b.program_id) diff --git a/src/render/lib.rs b/src/render/lib.rs index b93aac4dc96..89895bbea9e 100644 --- a/src/render/lib.rs +++ b/src/render/lib.rs @@ -81,10 +81,10 @@ impl RenderState { struct ParamStorage { uniforms: Vec, blocks : Vec>, - textures: Vec, + textures: Vec>, } -impl ParamStorage{ +impl ParamStorage { /// Create an empty parameter storage. fn new() -> ParamStorage { ParamStorage { @@ -94,7 +94,7 @@ impl ParamStorage{ } } - fn get_mut(&mut self) -> shade::ParamValues { + fn get_mut(&mut self) -> shade::ParamValues { self.uniforms.truncate(0); self.blocks.truncate(0); self.textures.truncate(0); diff --git a/src/render/shade.rs b/src/render/shade.rs index 7c3ede8bee1..fe4a9266e64 100644 --- a/src/render/shade.rs +++ b/src/render/shade.rs @@ -15,7 +15,7 @@ //! Shader parameter handling. use std::cell::Cell; -use device::{back, shade}; +use device::shade; use device::shade::UniformValue; use device::{Resources, RawBufferHandle, TextureHandle, SamplerHandle}; @@ -62,17 +62,21 @@ pub type VarBlock = u8; pub type VarTexture = u8; /// A texture parameter: consists of a texture handle with an optional sampler. -pub type TextureParam = (TextureHandle, Option>); +pub type TextureParam = (TextureHandle, Option>); /// A borrowed mutable storage for shader parameter values. // Not sure if it's the best data structure to represent it. -pub struct ParamValues<'a> { +pub struct ParamValues<'a, R: Resources> where + ::Buffer: 'a, + ::Sampler: 'a, + ::Texture: 'a, +{ /// uniform values to be provided pub uniforms: &'a mut Vec, /// uniform buffers to be provided - pub blocks : &'a mut Vec>, + pub blocks : &'a mut Vec>, /// textures to be provided - pub textures: &'a mut Vec, + pub textures: &'a mut Vec>, } /// An error type on either the parameter storage or the program side @@ -90,18 +94,20 @@ pub enum ParameterError { /// Abstracts the shader parameter structure, generated by the `shader_param` attribute pub trait ShaderParam { + type Resources: Resources; /// A helper structure to contain variable indices inside the shader type Link; /// Create a new link to be used with a given program fn create_link(Option<&Self>, &shade::ProgramInfo) -> Result; /// Get all the contained parameter values, using a given link - fn fill_params(&self, &Self::Link, ParamValues); + fn fill_params(&self, &Self::Link, ParamValues); } -impl ShaderParam for () { +impl ShaderParam for Option { + type Resources = R; type Link = (); - fn create_link(_: Option<&()>, info: &shade::ProgramInfo) -> Result<(), ParameterError> { + fn create_link(_: Option<&Option>, info: &shade::ProgramInfo) -> Result<(), ParameterError> { match info.uniforms[..].first() { Some(u) => return Err(ParameterError::MissingUniform(u.name.clone())), None => (), @@ -117,7 +123,7 @@ impl ShaderParam for () { Ok(()) } - fn fill_params(&self, _: &(), _: ParamValues) { + fn fill_params(&self, _: &(), _: ParamValues) { //empty } } @@ -137,7 +143,7 @@ pub struct ParamDictionary { /// Block dictionary pub blocks: Vec>>, /// Texture dictionary - pub textures: Vec>, + pub textures: Vec>>, } /// Redirects program input to the relevant ParamDictionary cell @@ -147,10 +153,11 @@ pub struct ParamDictionaryLink { textures: Vec, } -impl ShaderParam for ParamDictionary { +impl ShaderParam for ParamDictionary { + type Resources = R; type Link = ParamDictionaryLink; - fn create_link(this: Option<&ParamDictionary>, info: &shade::ProgramInfo) + fn create_link(this: Option<&ParamDictionary>, info: &shade::ProgramInfo) -> Result { let this = match this { Some(d) => d, @@ -170,7 +177,7 @@ impl ShaderParam for ParamDictionary { }) } - fn fill_params(&self, link: &ParamDictionaryLink, params: ParamValues) { + fn fill_params(&self, link: &ParamDictionaryLink, params: ParamValues) { for &id in link.uniforms.iter() { params.uniforms.push(self.uniforms[id].value.get()); } diff --git a/tests/shader_param.rs b/tests/shader_param.rs index ff14b810914..6c5419a7c37 100644 --- a/tests/shader_param.rs +++ b/tests/shader_param.rs @@ -25,7 +25,7 @@ use secret_lib::gfx; struct TestParam { a: i32, b: [f32; 4], - c: gfx::shade::TextureParam, + c: gfx::shade::TextureParam, d: gfx::RawBufferHandle, e: f32, #[name = "a_f"] @@ -36,7 +36,7 @@ struct TestParam { fn test_link_copy() { // testing if RefBatch is copyable fn _is_copy(_t: T) {} - fn _ref_copy(batch: gfx::batch::RefBatch) { + fn _ref_copy(batch: gfx::batch::RefBatch) { _is_copy(batch) } } @@ -44,7 +44,7 @@ fn test_link_copy() { #[test] fn test_shader_param() { // testing if RefBatch can be constructed - let _ref: gfx::batch::RefBatch; + let _ref: gfx::batch::RefBatch; // testing if OwnedBatch can be constructed - let _owned: gfx::batch::OwnedBatch; + let _owned: gfx::batch::OwnedBatch; } From 1631c79a759f5e5bc23a1cf4d74d7944bedaba20 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Mon, 23 Feb 2015 20:06:57 +1100 Subject: [PATCH 2/5] Parameterise ParamStorage over Resources --- src/render/lib.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/render/lib.rs b/src/render/lib.rs index 89895bbea9e..93dae180d27 100644 --- a/src/render/lib.rs +++ b/src/render/lib.rs @@ -22,7 +22,7 @@ extern crate "gfx_device_gl" as device; use std::mem; -use device::Device; +use device::{Device, Resources}; use device::attrib; use device::attrib::IntSize; use device::back; @@ -78,15 +78,15 @@ impl RenderState { } /// Temporary parameter storage, used for shader activation. -struct ParamStorage { +struct ParamStorage { uniforms: Vec, - blocks : Vec>, - textures: Vec>, + blocks : Vec>, + textures: Vec>, } -impl ParamStorage { +impl ParamStorage { /// Create an empty parameter storage. - fn new() -> ParamStorage { + fn new() -> ParamStorage { ParamStorage { uniforms: Vec::new(), blocks: Vec::new(), @@ -94,7 +94,7 @@ impl ParamStorage { } } - fn get_mut(&mut self) -> shade::ParamValues { + fn get_mut(&mut self) -> shade::ParamValues { self.uniforms.truncate(0); self.blocks.truncate(0); self.textures.truncate(0); @@ -151,7 +151,7 @@ pub struct Renderer { read_frame_buffer: device::FrameBufferHandle, default_frame_buffer: device::FrameBufferHandle, render_state: RenderState, - parameters: ParamStorage, + parameters: ParamStorage, } impl Renderer { From 58bb77e4111d201833f8c17902b575cda60abe6f Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Mon, 23 Feb 2015 20:08:41 +1100 Subject: [PATCH 3/5] Parameterise RenderState over Resources --- src/render/lib.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/render/lib.rs b/src/render/lib.rs index 93dae180d27..f5be7616219 100644 --- a/src/render/lib.rs +++ b/src/render/lib.rs @@ -47,29 +47,29 @@ pub mod target; const TRACKED_ATTRIBUTES: usize = 8; -type CachedAttribute = (device::RawBufferHandle, attrib::Format); +type CachedAttribute = (device::RawBufferHandle, attrib::Format); type Instancing = (device::InstanceCount, device::VertexCount); /// The internal state of the renderer. /// This is used as a cache to eliminate redundant state changes. -struct RenderState { +struct RenderState { is_frame_buffer_set: bool, - frame: target::Frame, + frame: target::Frame, is_array_buffer_set: bool, - program_name: device::back::Program, - index: Option>, - attributes: [Option; TRACKED_ATTRIBUTES], + program_name: Option, + index: Option>, + attributes: [Option>; TRACKED_ATTRIBUTES], draw: state::DrawState, } -impl RenderState { +impl RenderState { /// Generate the initial state matching `Device::reset_state` - fn new() -> RenderState { + fn new() -> RenderState { RenderState { is_frame_buffer_set: false, frame: target::Frame::new(0,0), is_array_buffer_set: false, - program_name: 0, + program_name: None, index: None, attributes: [None; TRACKED_ATTRIBUTES], draw: state::DrawState::new(), @@ -150,7 +150,7 @@ pub struct Renderer { draw_frame_buffer: device::FrameBufferHandle, read_frame_buffer: device::FrameBufferHandle, default_frame_buffer: device::FrameBufferHandle, - render_state: RenderState, + render_state: RenderState, parameters: ParamStorage, } @@ -375,9 +375,9 @@ impl Renderer { Err(e) => return Err(e), }; //Warning: this is not protected against deleted resources in single-threaded mode - if self.render_state.program_name != program.get_name() { + if self.render_state.program_name != Some(program.get_name()) { self.command_buffer.bind_program(program.get_name()); - self.render_state.program_name = program.get_name(); + self.render_state.program_name = Some(program.get_name()); } self.upload_parameters(program); Ok(program) From c2f2a6bdf4d84c6e343d680ca97cfa3244f1c229 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Mon, 23 Feb 2015 20:45:00 +1100 Subject: [PATCH 4/5] Decouple the most other types from GlDevice --- src/device/draw.rs | 27 ++++++++-------- src/device/gl_device/lib.rs | 4 +++ src/device/lib.rs | 62 ++++++++++++++++++------------------- src/gfx/lib.rs | 16 +++++----- src/render/device_ext.rs | 20 ++++++------ src/render/lib.rs | 57 +++++++++++++++++----------------- 6 files changed, 93 insertions(+), 93 deletions(-) diff --git a/src/device/draw.rs b/src/device/draw.rs index 3b9063c10fd..db649e32a9d 100644 --- a/src/device/draw.rs +++ b/src/device/draw.rs @@ -15,7 +15,6 @@ //! Command Buffer device interface use attrib; -use back; use shade; use target; use tex; @@ -85,30 +84,30 @@ pub trait CommandBuffer { /// Clear the command buffer contents, retain the allocated storage fn clear(&mut self); /// Bind a shader program - fn bind_program(&mut self, back::Program); + fn bind_program(&mut self, ::Program); /// Bind an array buffer object - fn bind_array_buffer(&mut self, back::ArrayBuffer); + fn bind_array_buffer(&mut self, ::ArrayBuffer); /// Bind a vertex attribute - fn bind_attribute(&mut self, ::AttributeSlot, back::Buffer, attrib::Format); + fn bind_attribute(&mut self, ::AttributeSlot, ::Buffer, attrib::Format); /// Bind an index buffer - fn bind_index(&mut self, back::Buffer); + fn bind_index(&mut self, ::Buffer); /// Bind a frame buffer object - fn bind_frame_buffer(&mut self, target::Access, back::FrameBuffer); + fn bind_frame_buffer(&mut self, target::Access, ::FrameBuffer); /// Unbind any surface from the specified target slot fn unbind_target(&mut self, target::Access, target::Target); /// Bind a surface to the specified target slot - fn bind_target_surface(&mut self, target::Access, target::Target, back::Surface); + fn bind_target_surface(&mut self, target::Access, target::Target, ::Surface); /// Bind a level of the texture to the specified target slot - fn bind_target_texture(&mut self, target::Access, target::Target, back::Texture, + fn bind_target_texture(&mut self, target::Access, target::Target, ::Texture, target::Level, Option); /// Bind a uniform block - fn bind_uniform_block(&mut self, back::Program, ::UniformBufferSlot, - ::UniformBlockIndex, back::Buffer); + fn bind_uniform_block(&mut self, ::Program, ::UniformBufferSlot, + ::UniformBlockIndex, ::Buffer); /// Bind a single uniform in the default block fn bind_uniform(&mut self, shade::Location, shade::UniformValue); /// Bind a texture - fn bind_texture(&mut self, ::TextureSlot, tex::TextureKind, back::Texture, - Option<::SamplerHandle>); + fn bind_texture(&mut self, ::TextureSlot, tex::TextureKind, ::Texture, + Option<::SamplerHandle>); /// Select, which color buffers are going to be targetted by the shader fn set_draw_color_buffers(&mut self, usize); /// Set primitive topology @@ -127,9 +126,9 @@ pub trait CommandBuffer { /// Set output color mask for all targets fn set_color_mask(&mut self, ::state::ColorMask); /// Update a vertex/index/uniform buffer - fn update_buffer(&mut self, back::Buffer, DataPointer, usize); + fn update_buffer(&mut self, ::Buffer, DataPointer, usize); /// Update a texture region - fn update_texture(&mut self, tex::TextureKind, back::Texture, + fn update_texture(&mut self, tex::TextureKind, ::Texture, tex::ImageInfo, DataPointer); /// Clear target surfaces fn call_clear(&mut self, target::ClearData, target::Mask); diff --git a/src/device/gl_device/lib.rs b/src/device/gl_device/lib.rs index 8944bf3d573..95ce6a65cac 100644 --- a/src/device/gl_device/lib.rs +++ b/src/device/gl_device/lib.rs @@ -68,6 +68,10 @@ impl Resources for GlResources { type Surface = Surface; type Texture = Texture; type Sampler = Sampler; + + fn get_main_frame_buffer() -> ::FrameBufferHandle { + ::Handle(0, ()) + } } #[derive(Copy, Eq, PartialEq, Debug)] diff --git a/src/device/lib.rs b/src/device/lib.rs index fbe5c680a6d..3e830d93268 100644 --- a/src/device/lib.rs +++ b/src/device/lib.rs @@ -237,11 +237,6 @@ pub fn make_fake_buffer() -> BufferHandle { BufferHandle::from_raw(Handle(0, info)) } -/// Return the framebuffer handle for the screen. -pub fn get_main_frame_buffer() -> FrameBufferHandle { - Handle(0, ()) -} - /// Treat a given slice as `&[u8]` for the given function call pub fn as_byte_slice(slice: &[T]) -> &[u8] { let len = mem::size_of::() * slice.len(); @@ -335,6 +330,9 @@ pub trait Resources: PhantomFn + Copy + Clone + PartialEq + fmt::Debug { type Surface: Copy + Clone + fmt::Debug + PartialEq + Send + Sync; type Texture: Copy + Clone + fmt::Debug + PartialEq + Send + Sync; type Sampler: Copy + Clone + fmt::Debug + PartialEq + Send + Sync; + + /// Return the framebuffer handle for the screen. + fn get_main_frame_buffer() -> FrameBufferHandle; } /// An interface for performing draw calls using a specific graphics API @@ -351,56 +349,56 @@ pub trait Device { fn submit(&mut self, buffer: (&Self::CommandBuffer, &draw::DataBuffer)); // resource creation - fn create_buffer_raw(&mut self, size: usize, usage: BufferUsage) -> BufferHandle; - fn create_buffer(&mut self, num: usize, usage: BufferUsage) -> BufferHandle { + fn create_buffer_raw(&mut self, size: usize, usage: BufferUsage) -> BufferHandle; + fn create_buffer(&mut self, num: usize, usage: BufferUsage) -> BufferHandle { self.create_buffer_raw(num * mem::size_of::(), usage).cast() } - fn create_buffer_static_raw(&mut self, data: &[u8]) -> BufferHandle; - fn create_buffer_static(&mut self, data: &[T]) -> BufferHandle { + fn create_buffer_static_raw(&mut self, data: &[u8]) -> BufferHandle; + fn create_buffer_static(&mut self, data: &[T]) -> BufferHandle { self.create_buffer_static_raw(as_byte_slice(data)).cast() } - fn create_array_buffer(&mut self) -> Result, ()>; + fn create_array_buffer(&mut self) -> Result, ()>; fn create_shader(&mut self, stage: shade::Stage, code: &[u8]) -> - Result, shade::CreateShaderError>; - fn create_program(&mut self, shaders: &[ShaderHandle], targets: Option<&[&str]>) -> Result, ()>; - fn create_frame_buffer(&mut self) -> FrameBufferHandle; - fn create_surface(&mut self, info: tex::SurfaceInfo) -> Result, tex::SurfaceError>; - fn create_texture(&mut self, info: tex::TextureInfo) -> Result, tex::TextureError>; - fn create_sampler(&mut self, info: tex::SamplerInfo) -> SamplerHandle; + Result, shade::CreateShaderError>; + fn create_program(&mut self, shaders: &[ShaderHandle], targets: Option<&[&str]>) -> Result, ()>; + fn create_frame_buffer(&mut self) -> FrameBufferHandle; + fn create_surface(&mut self, info: tex::SurfaceInfo) -> Result, tex::SurfaceError>; + fn create_texture(&mut self, info: tex::TextureInfo) -> Result, tex::TextureError>; + fn create_sampler(&mut self, info: tex::SamplerInfo) -> SamplerHandle; // resource deletion - fn delete_buffer_raw(&mut self, buf: BufferHandle); - fn delete_buffer(&mut self, buf: BufferHandle) { + fn delete_buffer_raw(&mut self, buf: BufferHandle); + fn delete_buffer(&mut self, buf: BufferHandle) { self.delete_buffer_raw(buf.cast()); } - fn delete_shader(&mut self, ShaderHandle); - fn delete_program(&mut self, ProgramHandle); - fn delete_surface(&mut self, SurfaceHandle); - fn delete_texture(&mut self, TextureHandle); - fn delete_sampler(&mut self, SamplerHandle); + fn delete_shader(&mut self, ShaderHandle); + fn delete_program(&mut self, ProgramHandle); + fn delete_surface(&mut self, SurfaceHandle); + fn delete_texture(&mut self, TextureHandle); + fn delete_sampler(&mut self, SamplerHandle); /// Update the information stored in a specific buffer - fn update_buffer_raw(&mut self, buf: BufferHandle, data: &[u8], + fn update_buffer_raw(&mut self, buf: BufferHandle, data: &[u8], offset_bytes: usize); - fn update_buffer(&mut self, buf: BufferHandle, data: &[T], + fn update_buffer(&mut self, buf: BufferHandle, data: &[T], offset_elements: usize) { self.update_buffer_raw(buf.cast(), as_byte_slice(data), mem::size_of::() * offset_elements) } - fn map_buffer_raw(&mut self, buf: BufferHandle, access: MapAccess) -> back::RawMapping; + fn map_buffer_raw(&mut self, buf: BufferHandle, access: MapAccess) -> back::RawMapping; fn unmap_buffer_raw(&mut self, map: back::RawMapping); - fn map_buffer_readable(&mut self, buf: BufferHandle) -> ReadableMapping; - fn map_buffer_writable(&mut self, buf: BufferHandle) -> WritableMapping; - fn map_buffer_rw(&mut self, buf: BufferHandle) -> RWMapping; + fn map_buffer_readable(&mut self, buf: BufferHandle) -> ReadableMapping; + fn map_buffer_writable(&mut self, buf: BufferHandle) -> WritableMapping; + fn map_buffer_rw(&mut self, buf: BufferHandle) -> RWMapping; /// Update the information stored in a texture - fn update_texture_raw(&mut self, tex: &TextureHandle, img: &tex::ImageInfo, + fn update_texture_raw(&mut self, tex: &TextureHandle, img: &tex::ImageInfo, data: &[u8]) -> Result<(), tex::TextureError>; - fn update_texture(&mut self, tex: &TextureHandle, + fn update_texture(&mut self, tex: &TextureHandle, img: &tex::ImageInfo, data: &[T]) -> Result<(), tex::TextureError> { self.update_texture_raw(tex, img, as_byte_slice(data)) } - fn generate_mipmap(&mut self, tex: &TextureHandle); + fn generate_mipmap(&mut self, tex: &TextureHandle); } #[cfg(test)] diff --git a/src/gfx/lib.rs b/src/gfx/lib.rs index 0066e044dc0..00cbc78b15d 100644 --- a/src/gfx/lib.rs +++ b/src/gfx/lib.rs @@ -57,7 +57,7 @@ pub struct Graphics { /// Renderer front-end. pub renderer: Renderer, /// Hidden batch context. - context: batch::Context, + context: batch::Context, } impl Graphics { @@ -72,23 +72,23 @@ impl Graphics { } /// Create a new ref batch. - pub fn make_batch>(&mut self, - program: &ProgramHandle, - mesh: &Mesh, - slice: Slice, + pub fn make_batch>(&mut self, + program: &ProgramHandle, + mesh: &Mesh, + slice: Slice, state: &DrawState) -> Result, batch::BatchError> { self.context.make_batch(program, mesh, slice, state) } /// Clear the `Frame` as the `ClearData` specifies. - pub fn clear(&mut self, data: ClearData, mask: Mask, frame: &Frame) { + pub fn clear(&mut self, data: ClearData, mask: Mask, frame: &Frame) { self.renderer.clear(data, mask, frame) } /// Draw a ref batch. - pub fn draw<'a, T: shade::ShaderParam>(&'a mut self, - batch: &'a batch::RefBatch, data: &'a T, frame: &Frame) + pub fn draw<'a, T: shade::ShaderParam>(&'a mut self, + batch: &'a batch::RefBatch, data: &'a T, frame: &Frame) -> Result<(), DrawError> { self.renderer.draw(&(batch, data, &self.context), frame) } diff --git a/src/render/device_ext.rs b/src/render/device_ext.rs index f18076cf36d..6a4db3da0a4 100644 --- a/src/render/device_ext.rs +++ b/src/render/device_ext.rs @@ -1,5 +1,5 @@ use device; -use device::back; +use device::Resources; use device::shade::{Stage, CreateShaderError, ShaderModel}; use super::mesh::{Mesh, VertexFormat}; @@ -63,15 +63,15 @@ pub trait DeviceExt: device::Device { fn create_renderer(&mut self) -> ::Renderer; /// Create a new mesh from the given vertex data. /// Convenience function around `create_buffer` and `Mesh::from_format`. - fn create_mesh(&mut self, data: &[T]) -> Mesh where - T: VertexFormat + Copy; + fn create_mesh(&mut self, data: &[T]) -> Mesh where + T: VertexFormat + Copy; /// Create a simple program given a vertex shader with a fragment one. fn link_program(&mut self, vs_code: &[u8], fs_code: &[u8]) - -> Result, ProgramError>; + -> Result, ProgramError>; /// Create a simple program given `ShaderSource` versions of vertex and /// fragment shaders, chooss the matching versions for the device. fn link_program_source(&mut self, vs_src: ShaderSource, fs_src: ShaderSource) - -> Result, ProgramError>; + -> Result, ProgramError>; } impl DeviceExt for D { @@ -82,14 +82,14 @@ impl DeviceExt for D { common_array_buffer: self.create_array_buffer(), draw_frame_buffer: self.create_frame_buffer(), read_frame_buffer: self.create_frame_buffer(), - default_frame_buffer: device::get_main_frame_buffer(), + default_frame_buffer: ::get_main_frame_buffer(), render_state: super::RenderState::new(), parameters: super::ParamStorage::new(), } } - fn create_mesh(&mut self, data: &[T]) -> Mesh where - T: VertexFormat + Copy, + fn create_mesh(&mut self, data: &[T]) -> Mesh where + T: VertexFormat + Copy, { let nv = data.len(); debug_assert!(nv < { @@ -102,7 +102,7 @@ impl DeviceExt for D { } fn link_program(&mut self, vs_code: &[u8], fs_code: &[u8]) - -> Result, ProgramError> { + -> Result, ProgramError> { let vs = match self.create_shader(Stage::Vertex, vs_code) { Ok(s) => s, Err(e) => return Err(ProgramError::Vertex(e)), @@ -117,7 +117,7 @@ impl DeviceExt for D { } fn link_program_source(&mut self, vs_src: ShaderSource, fs_src: ShaderSource) - -> Result, ProgramError> { + -> Result, ProgramError> { let model = self.get_capabilities().shader_model; let err_model = CreateShaderError::ModelNotSupported; diff --git a/src/render/lib.rs b/src/render/lib.rs index f5be7616219..fc5e312c2a5 100644 --- a/src/render/lib.rs +++ b/src/render/lib.rs @@ -25,7 +25,6 @@ use std::mem; use device::{Device, Resources}; use device::attrib; use device::attrib::IntSize; -use device::back; use device::draw::CommandBuffer; use device::shade::{ProgramInfo, UniformValue}; use device::target::{Rect, ClearData, Mirror, Mask, Access, Target}; @@ -108,14 +107,14 @@ impl ParamStorage { /// Extension methods for the command buffer. /// Useful when Renderer is borrowed, and we need to issue commands. -trait CommandBufferExt { +trait CommandBufferExt: CommandBuffer { /// Bind a plane to some target - fn bind_target(&mut self, Access, Target, Option<&target::Plane>); + fn bind_target(&mut self, Access, Target, Option<&target::Plane>); } impl CommandBufferExt for C { fn bind_target(&mut self, access: Access, to: Target, - plane: Option<&target::Plane>) { + plane: Option<&target::Plane>) { match plane { None => self.unbind_target(access, to), Some(&target::Plane::Surface(ref suf)) => @@ -146,12 +145,12 @@ pub enum DrawError { pub struct Renderer { command_buffer: D::CommandBuffer, data_buffer: device::draw::DataBuffer, - common_array_buffer: Result, ()>, - draw_frame_buffer: device::FrameBufferHandle, - read_frame_buffer: device::FrameBufferHandle, - default_frame_buffer: device::FrameBufferHandle, - render_state: RenderState, - parameters: ParamStorage, + common_array_buffer: Result, ()>, + draw_frame_buffer: device::FrameBufferHandle, + read_frame_buffer: device::FrameBufferHandle, + default_frame_buffer: device::FrameBufferHandle, + render_state: RenderState, + parameters: ParamStorage, } impl Renderer { @@ -182,29 +181,29 @@ impl Renderer { } /// Clear the `Frame` as the `ClearData` specifies. - pub fn clear(&mut self, data: ClearData, mask: Mask, frame: &target::Frame) { + pub fn clear(&mut self, data: ClearData, mask: Mask, frame: &target::Frame) { self.bind_frame(frame); self.command_buffer.call_clear(data, mask); } /// Draw a `batch` into the specified `frame` - pub fn draw>(&mut self, batch: &B, frame: &target::Frame) + pub fn draw>(&mut self, batch: &B, frame: &target::Frame) -> Result<(), DrawError> { self.draw_all(batch, None, frame) } /// Draw a `batch` multiple times using instancing - pub fn draw_instanced>(&mut self, batch: &B, + pub fn draw_instanced>(&mut self, batch: &B, count: device::InstanceCount, base: device::VertexCount, - frame: &target::Frame) + frame: &target::Frame) -> Result<(), DrawError> { self.draw_all(batch, Some((count, base)), frame) } /// Draw a 'batch' with all known parameters specified, internal use only. - fn draw_all>(&mut self, batch: &B, instances: Option, - frame: &target::Frame) -> Result<(), DrawError> { + fn draw_all>(&mut self, batch: &B, instances: Option, + frame: &target::Frame) -> Result<(), DrawError> { let (mesh, attrib_iter, slice, state) = match batch.get_data() { Ok(data) => data, Err(e) => return Err(DrawError::InvalidBatch(e)), @@ -225,8 +224,8 @@ impl Renderer { } /// Blit one frame onto another - pub fn blit(&mut self, source: &target::Frame, source_rect: Rect, - destination: &target::Frame, dest_rect: Rect, + pub fn blit(&mut self, source: &target::Frame, source_rect: Rect, + destination: &target::Frame, dest_rect: Rect, mirror: Mirror, mask: Mask) { // verify as much as possible here if mask.intersects(device::target::COLOR) { @@ -248,7 +247,7 @@ impl Renderer { } /// Update a buffer with data from a vector. - pub fn update_buffer_vec(&mut self, buf: device::BufferHandle, + pub fn update_buffer_vec(&mut self, buf: device::BufferHandle, data: &[T], offset_elements: usize) { let esize = mem::size_of::(); let offset_bytes = esize * offset_elements; @@ -259,21 +258,21 @@ impl Renderer { /// Update a buffer with data from a single type. pub fn update_buffer_struct(&mut self, - buf: device::BufferHandle, data: &T) { + buf: device::BufferHandle, data: &T) { debug_assert!(mem::size_of::() <= buf.get_info().size); let pointer = self.data_buffer.add_struct(data); self.command_buffer.update_buffer(buf.get_name(), pointer, 0); } /// Update the contents of a texture. - pub fn update_texture(&mut self, tex: device::TextureHandle, + pub fn update_texture(&mut self, tex: device::TextureHandle, img: device::tex::ImageInfo, data: &[T]) { debug_assert!(tex.get_info().contains(&img)); let pointer = self.data_buffer.add_vec(data); self.command_buffer.update_texture(tex.get_info().kind, tex.get_name(), img, pointer); } - fn bind_frame(&mut self, frame: &target::Frame) { + fn bind_frame(&mut self, frame: &target::Frame) { if self.render_state.frame.width != frame.width || self.render_state.frame.height != frame.height { self.command_buffer.set_viewport(Rect { @@ -331,7 +330,7 @@ impl Renderer { } } - fn bind_read_frame(&mut self, frame: &target::Frame) { + fn bind_read_frame(&mut self, frame: &target::Frame) { self.command_buffer.bind_frame_buffer(Access::Read, self.read_frame_buffer.get_name()); // color if frame.colors.is_empty() { @@ -368,8 +367,8 @@ impl Renderer { self.render_state.draw = *state; } - fn bind_program<'a, B: Batch>(&mut self, batch: &'a B) - -> Result<&'a device::ProgramHandle, B::Error> { + fn bind_program<'a, B: Batch>(&mut self, batch: &'a B) + -> Result<&'a device::ProgramHandle, B::Error> { let program = match batch.fill_params(self.parameters.get_mut()) { Ok(p) => p, Err(e) => return Err(e), @@ -383,7 +382,7 @@ impl Renderer { Ok(program) } - fn upload_parameters(&mut self, program: &device::ProgramHandle) { + fn upload_parameters(&mut self, program: &device::ProgramHandle) { let info = program.get_info(); if self.parameters.uniforms.len() != info.uniforms.len() || self.parameters.blocks.len() != info.blocks.len() || @@ -423,7 +422,7 @@ impl Renderer { } fn bind_mesh>(&mut self, - mesh: &mesh::Mesh, attrib_iter: I, info: &ProgramInfo) { + mesh: &mesh::Mesh, attrib_iter: I, info: &ProgramInfo) { if !self.render_state.is_array_buffer_set { // It's Ok if the array buffer is not supported. We can just ignore it. self.common_array_buffer.map(|ab| @@ -449,14 +448,14 @@ impl Renderer { } } - fn bind_index(&mut self, buf: device::BufferHandle) { + fn bind_index(&mut self, buf: device::BufferHandle) { if self.render_state.index != Some(buf.raw()) { self.command_buffer.bind_index(buf.get_name()); self.render_state.index = Some(buf.raw()); } } - fn draw_slice(&mut self, slice: &mesh::Slice, + fn draw_slice(&mut self, slice: &mesh::Slice, instances: Option<(device::InstanceCount, device::VertexCount)>) { let mesh::Slice { start, end, prim_type, kind } = slice.clone(); match kind { From 15b84aaca991ec9a4bee5b58911c8e7a1af443d2 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Mon, 23 Feb 2015 23:56:58 +1100 Subject: [PATCH 5/5] Decouple buffer mapping types from gl backend --- src/device/gl_device/lib.rs | 18 ++++++++++- src/device/lib.rs | 60 +++++++++++++++++++++++++------------ 2 files changed, 58 insertions(+), 20 deletions(-) diff --git a/src/device/gl_device/lib.rs b/src/device/gl_device/lib.rs index 95ce6a65cac..04f726a4b47 100644 --- a/src/device/gl_device/lib.rs +++ b/src/device/gl_device/lib.rs @@ -22,6 +22,7 @@ extern crate libc; extern crate "gfx_gl" as gl; use std::marker::PhantomData; +use std::slice; use log::LogLevel; use attrib::{SignFlag, IntSubType, IntSize, FloatSubType, FloatSize, Type}; @@ -41,12 +42,26 @@ mod tex; mod info; #[allow(raw_pointer_derive)] -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct RawMapping { pub pointer: *mut libc::c_void, target: gl::types::GLenum, } +impl ::RawMapping for RawMapping { + unsafe fn set(&self, index: usize, val: T) { + *(self.pointer as *mut T).offset(index as isize) = val; + } + + unsafe fn to_slice(&self, len: usize) -> &[T] { + slice::from_raw_parts(self.pointer as *const T, len) + } + + unsafe fn to_mut_slice(&self, len: usize) -> &mut [T] { + slice::from_raw_parts_mut(self.pointer as *mut T, len) + } +} + pub type Buffer = gl::types::GLuint; pub type ArrayBuffer = gl::types::GLuint; pub type Shader = gl::types::GLuint; @@ -60,6 +75,7 @@ pub type Texture = gl::types::GLuint; pub enum GlResources {} impl Resources for GlResources { + type RawMapping = RawMapping; type Buffer = Buffer; type ArrayBuffer = ArrayBuffer; type Shader = Shader; diff --git a/src/device/lib.rs b/src/device/lib.rs index 3e830d93268..e84c6e359cb 100644 --- a/src/device/lib.rs +++ b/src/device/lib.rs @@ -28,7 +28,6 @@ pub use self::gl_device as back; use std::fmt; use std::mem; -use std::slice; use std::ops::{Deref, DerefMut}; use std::marker::{PhantomData, PhantomFn}; @@ -67,32 +66,46 @@ pub enum MapAccess { RW } +/// Unsafe operations for a buffer mapping +pub trait RawMapping { + /// Set the element at `index` to `val`. Not bounds-checked. + unsafe fn set(&self, index: usize, val: T); + /// Returns a slice of the specified length. + unsafe fn to_slice(&self, len: usize) -> &[T]; + /// Returns a mutable slice of the specified length. + unsafe fn to_mut_slice(&self, len: usize) -> &mut [T]; +} + /// A handle to a readable map, which can be sliced. pub struct ReadableMapping<'a, T: Copy, D: 'a + Device> { - raw: back::RawMapping, + raw: ::RawMapping, len: usize, device: &'a mut D, phantom_t: PhantomData } -impl<'a, T: Copy, D: Device> Deref for ReadableMapping<'a, T, D> { +impl<'a, T: Copy, D: Device> Deref for ReadableMapping<'a, T, D> where + ::RawMapping: 'a, +{ type Target = [T]; fn deref(&self) -> &[T] { - unsafe { mem::transmute(slice::from_raw_parts(self.raw.pointer as *const T, self.len)) } + unsafe { self.raw.to_slice(self.len) } } } #[unsafe_destructor] -impl<'a, T: Copy, D: Device> Drop for ReadableMapping<'a, T, D> { +impl<'a, T: Copy, D: Device> Drop for ReadableMapping<'a, T, D> where + ::RawMapping: 'a, +{ fn drop(&mut self) { - self.device.unmap_buffer_raw(self.raw) + self.device.unmap_buffer_raw(self.raw.clone()) } } /// A handle to a writable map, which only allows setting elements. pub struct WritableMapping<'a, T: Copy, D: 'a + Device> { - raw: back::RawMapping, + raw: ::RawMapping, len: usize, device: &'a mut D, phantom_t: PhantomData @@ -104,43 +117,51 @@ impl<'a, T: Copy, D: Device> WritableMapping<'a, T, D> { if idx >= self.len { panic!("Tried to write out of bounds to a WritableMapping!") } - unsafe { *(std::mem::transmute::<_, *mut T>(self.raw.pointer).offset(idx as isize)) = val } + unsafe { self.raw.set(idx, val); } } } #[unsafe_destructor] -impl<'a, T: Copy, D: Device> Drop for WritableMapping<'a, T, D> { +impl<'a, T: Copy, D: Device> Drop for WritableMapping<'a, T, D> where + ::RawMapping: 'a, +{ fn drop(&mut self) { - self.device.unmap_buffer_raw(self.raw) + self.device.unmap_buffer_raw(self.raw.clone()) } } /// A handle to a complete readable/writable map, which can be sliced both ways. pub struct RWMapping<'a, T: Copy, D: 'a + Device> { - raw: back::RawMapping, + raw: ::RawMapping, len: usize, device: &'a mut D, phantom_t: PhantomData } -impl<'a, T: Copy, D: Device> Deref for RWMapping<'a, T, D> { +impl<'a, T: Copy, D: Device> Deref for RWMapping<'a, T, D> where + ::RawMapping: 'a, +{ type Target = [T]; fn deref(&self) -> &[T] { - unsafe { mem::transmute(slice::from_raw_parts(self.raw.pointer as *const T, self.len)) } + unsafe { self.raw.to_slice(self.len) } } } -impl<'a, T: Copy, D: Device> DerefMut for RWMapping<'a, T, D> { +impl<'a, T: Copy, D: Device> DerefMut for RWMapping<'a, T, D> where + ::RawMapping: 'a, +{ fn deref_mut(&mut self) -> &mut [T] { - unsafe { mem::transmute(slice::from_raw_parts_mut(self.raw.pointer, self.len)) } + unsafe { self.raw.to_mut_slice(self.len) } } } #[unsafe_destructor] -impl<'a, T: Copy, D: Device> Drop for RWMapping<'a, T, D> { +impl<'a, T: Copy, D: Device> Drop for RWMapping<'a, T, D> where + ::RawMapping: 'a, +{ fn drop(&mut self) { - self.device.unmap_buffer_raw(self.raw) + self.device.unmap_buffer_raw(self.raw.clone()) } } @@ -322,6 +343,7 @@ pub struct BufferInfo { /// Resources pertaining to a specific API. pub trait Resources: PhantomFn + Copy + Clone + PartialEq + fmt::Debug { + type RawMapping: Clone + RawMapping; type Buffer: Copy + Clone + fmt::Debug + PartialEq + Send + Sync; type ArrayBuffer: Copy + Clone + fmt::Debug + PartialEq + Send + Sync; type Shader: Copy + Clone + fmt::Debug + PartialEq + Send + Sync; @@ -384,8 +406,8 @@ pub trait Device { offset_elements: usize) { self.update_buffer_raw(buf.cast(), as_byte_slice(data), mem::size_of::() * offset_elements) } - fn map_buffer_raw(&mut self, buf: BufferHandle, access: MapAccess) -> back::RawMapping; - fn unmap_buffer_raw(&mut self, map: back::RawMapping); + fn map_buffer_raw(&mut self, buf: BufferHandle, access: MapAccess) -> ::RawMapping; + fn unmap_buffer_raw(&mut self, map: ::RawMapping); fn map_buffer_readable(&mut self, buf: BufferHandle) -> ReadableMapping; fn map_buffer_writable(&mut self, buf: BufferHandle) -> WritableMapping; fn map_buffer_rw(&mut self, buf: BufferHandle) -> RWMapping;