From c25ef1d024f517a58651fdf5b8c5adf6c864ccad Mon Sep 17 00:00:00 2001
From: Brendan Zabarauskas <bjzaba@yahoo.com.au>
Date: Sun, 15 Feb 2015 12:53:43 +1100
Subject: [PATCH] Parameterise handles over Device

For now we just use `GlDevice` when we refer to them
---
 examples/deferred/main.rs       |  13 ++--
 src/device/draw.rs              |  18 +++--
 src/device/gl_device/draw.rs    |   6 +-
 src/device/gl_device/lib.rs     |  90 +++++++++++-----------
 src/device/gl_device/shade.rs   |   4 +-
 src/device/lib.rs               | 129 +++++++++++++++++++-------------
 src/gfx/lib.rs                  |   2 +-
 src/gfx_macros/vertex_format.rs |  10 ++-
 src/render/batch.rs             |  21 +++---
 src/render/device_ext.rs        |   9 ++-
 src/render/lib.rs               |  27 +++----
 src/render/mesh.rs              |  24 +++---
 src/render/shade.rs             |   8 +-
 src/render/target.rs            |   5 +-
 tests/shader_param.rs           |   2 +-
 15 files changed, 199 insertions(+), 169 deletions(-)

diff --git a/examples/deferred/main.rs b/examples/deferred/main.rs
index 549ab6e4d30..d9281b9eec8 100644
--- a/examples/deferred/main.rs
+++ b/examples/deferred/main.rs
@@ -101,7 +101,7 @@ struct LightParams {
     #[name = "u_Transform"]
     transform: [[f32; 4]; 4],
     #[name = "u_LightPosBlock"]
-    light_pos_buf: gfx::RawBufferHandle,
+    light_pos_buf: gfx::RawBufferHandle<gfx::GlDevice>,
     #[name = "u_Radius"]
     radius: f32,
     #[name = "u_CameraPos"]
@@ -121,7 +121,7 @@ struct EmitterParams {
     #[name = "u_Transform"]
     transform: [[f32; 4]; 4],
     #[name = "u_LightPosBlock"]
-    light_pos_buf: gfx::RawBufferHandle,
+    light_pos_buf: gfx::RawBufferHandle<gfx::GlDevice>,
     #[name = "u_Radius"]
     radius: f32,
 }
@@ -307,7 +307,9 @@ fn calculate_color(height: f32) -> [f32; 3] {
     }
 }
 
-fn create_g_buffer(width: u16, height: u16, device: &mut gfx::GlDevice) -> (gfx::Frame, TextureHandle, TextureHandle, TextureHandle, TextureHandle) {
+fn create_g_buffer(width: u16, height: u16, device: &mut gfx::GlDevice)
+        -> (gfx::Frame, TextureHandle<gfx::GlDevice>, TextureHandle<gfx::GlDevice>,
+            TextureHandle<gfx::GlDevice>, TextureHandle<gfx::GlDevice>) {
     let mut frame = gfx::Frame::new(width, height);
 
     let texture_info_float = gfx::tex::TextureInfo {
@@ -343,7 +345,8 @@ fn create_g_buffer(width: u16, height: u16, device: &mut gfx::GlDevice) -> (gfx:
     (frame, texture_pos, texture_normal, texture_diffuse, texture_depth)
 }
 
-fn create_res_buffer(width: u16, height: u16, device: &mut gfx::GlDevice, texture_depth: TextureHandle) -> (gfx::Frame, TextureHandle, TextureHandle) {
+fn create_res_buffer(width: u16, height: u16, device: &mut gfx::GlDevice, texture_depth: TextureHandle<gfx::GlDevice>)
+        -> (gfx::Frame, TextureHandle<gfx::GlDevice>, TextureHandle<gfx::GlDevice>) {
     let mut frame = gfx::Frame::new(width, height);
 
     let texture_info_float = gfx::tex::TextureInfo {
@@ -567,7 +570,7 @@ fn main() {
         tex: (texture_pos, Some(sampler)),
     };
 
-    let mut debug_buf: Option<TextureHandle> = None;
+    let mut debug_buf: Option<TextureHandle<gfx::GlDevice>> = None;
 
     let mut light_pos_vec: Vec<[f32; 4]> = (0 ..NUM_LIGHTS).map(|_| {
         [0.0, 0.0, 0.0, 0.0]
diff --git a/src/device/draw.rs b/src/device/draw.rs
index b21d7465520..a83c2aeb185 100644
--- a/src/device/draw.rs
+++ b/src/device/draw.rs
@@ -14,6 +14,8 @@
 
 //! Command Buffer device interface
 
+use std::fmt;
+
 use attrib;
 use back;
 use shade;
@@ -77,13 +79,13 @@ impl DataBuffer {
 /// An interface of the abstract command buffer. It collects commands in an
 /// efficient API-specific manner, to be ready for execution on the device.
 pub trait CommandBuffer {
-    type Buffer;
-    type ArrayBuffer;
-    type Program;
-    type FrameBuffer;
-    type Surface;
-    type Texture;
-    type Sampler;
+    type Buffer:        Copy + fmt::Debug + PartialEq + Clone;
+    type ArrayBuffer:   Copy + fmt::Debug + PartialEq + Clone;
+    type Program:       Copy + fmt::Debug + PartialEq + Clone;
+    type FrameBuffer:   Copy + fmt::Debug + PartialEq + Clone;
+    type Surface:       Copy + fmt::Debug + PartialEq + Clone;
+    type Texture:       Copy + fmt::Debug + PartialEq + Clone;
+    type Sampler:       Copy + fmt::Debug + PartialEq + Clone;
 
     /// An empty constructor
     fn new() -> Self;
@@ -113,7 +115,7 @@ pub trait CommandBuffer {
     fn bind_uniform(&mut self, shade::Location, shade::UniformValue);
     /// Bind a texture
     fn bind_texture(&mut self, ::TextureSlot, tex::TextureKind, back::Texture,
-                    Option<::SamplerHandle>);
+                    Option<::SamplerHandle<back::GlDevice>>);
     /// Select, which color buffers are going to be targetted by the shader
     fn set_draw_color_buffers(&mut self, usize);
     /// Set primitive topology
diff --git a/src/device/gl_device/draw.rs b/src/device/gl_device/draw.rs
index e05f8136a4e..3bfe9390a18 100644
--- a/src/device/gl_device/draw.rs
+++ b/src/device/gl_device/draw.rs
@@ -16,7 +16,7 @@
 
 use std::slice;
 
-use {attrib, draw, target, tex, shade, state};
+use {attrib, back, draw, target, tex, shade, state};
 use {AttributeSlot, IndexType, InstanceCount, PrimitiveType, TextureSlot, UniformBlockIndex, UniformBufferSlot, VertexCount};
 use super::{ArrayBuffer, Buffer, FrameBuffer, Program, Sampler, Surface, Texture};
 
@@ -33,7 +33,7 @@ pub enum Command {
     BindTargetTexture(target::Access, target::Target, Texture, target::Level, Option<target::Layer>),
     BindUniformBlock(Program, UniformBufferSlot, UniformBlockIndex, Buffer),
     BindUniform(shade::Location, shade::UniformValue),
-    BindTexture(TextureSlot, tex::TextureKind, Texture, Option<::SamplerHandle>),
+    BindTexture(TextureSlot, tex::TextureKind, Texture, Option<::SamplerHandle<back::GlDevice>>),
     SetDrawColorBuffers(usize),
     SetPrimitiveState(state::Primitive),
     SetViewport(target::Rect),
@@ -125,7 +125,7 @@ impl draw::CommandBuffer for CommandBuffer {
         self.buf.push(Command::BindUniform(loc, value));
     }
     fn bind_texture(&mut self, slot: ::TextureSlot, kind: ::tex::TextureKind,
-                    tex: Texture, sampler: Option<::SamplerHandle>) {
+                    tex: Texture, sampler: Option<::SamplerHandle<back::GlDevice>>) {
         self.buf.push(Command::BindTexture(slot, kind, tex, sampler));
     }
 
diff --git a/src/device/gl_device/lib.rs b/src/device/gl_device/lib.rs
index 4adbc62252b..bfcf258192f 100644
--- a/src/device/gl_device/lib.rs
+++ b/src/device/gl_device/lib.rs
@@ -80,29 +80,6 @@ impl GlError {
     }
 }
 
-static RESET_CB: &'static [Command] = &[
-    Command::BindProgram(0),
-    Command::BindArrayBuffer(0),
-    //BindAttribute
-    Command::BindIndex(0),
-    Command::BindFrameBuffer(Access::Draw, 0),
-    Command::BindFrameBuffer(Access::Read, 0),
-    //UnbindTarget
-    //BindUniformBlock
-    //BindUniform
-    //BindTexture
-    Command::SetPrimitiveState(::state::Primitive {
-        front_face: WindingOrder::CounterClockwise,
-        method: RasterMethod::Fill(CullMode::Back),
-        offset: None,
-    }),
-    Command::SetViewport(::target::Rect{x: 0, y: 0, w: 0, h: 0}),
-    Command::SetScissor(None),
-    Command::SetDepthStencilState(None, None, CullMode::Nothing),
-    Command::SetBlendState(None),
-    Command::SetColorMask(::state::MASK_ALL),
-];
-
 fn primitive_to_gl(prim_type: ::PrimitiveType) -> gl::types::GLenum {
     match prim_type {
         PrimitiveType::Point => gl::POINTS,
@@ -582,9 +559,26 @@ impl Device for GlDevice {
 
     fn reset_state(&mut self) {
         let data = ::draw::DataBuffer::new();
-        for com in RESET_CB.iter() {
-            self.process(com, &data);
-        }
+        self.process(&Command::BindProgram(0), &data);
+        self.process(&Command::BindArrayBuffer(0), &data);
+        // self.process(&command::BindAttribute, &data);
+        self.process(&Command::BindIndex(0), &data);
+        self.process(&Command::BindFrameBuffer(Access::Draw, 0), &data);
+        self.process(&Command::BindFrameBuffer(Access::Read, 0), &data);
+        // self.process(&command::UnbindTarget, &data);
+        // self.process(&command::BindUniformBlock, &data);
+        // self.process(&command::BindUniform, &data);
+        // self.process(&command::BindTexture, &data);
+        self.process(&Command::SetPrimitiveState(::state::Primitive {
+            front_face: WindingOrder::CounterClockwise,
+            method: RasterMethod::Fill(CullMode::Back),
+            offset: None,
+        }), &data);
+        self.process(&Command::SetViewport(::target::Rect{x: 0, y: 0, w: 0, h: 0}), &data);
+        self.process(&Command::SetScissor(None), &data);
+        self.process(&Command::SetDepthStencilState(None, None, CullMode::Nothing), &data);
+        self.process(&Command::SetBlendState(None), &data);
+        self.process(&Command::SetColorMask(::state::MASK_ALL), &data);
     }
 
     fn submit(&mut self, (cb, db): (&CommandBuffer, &::draw::DataBuffer)) {
@@ -594,7 +588,7 @@ impl Device for GlDevice {
         }
     }
 
-    fn create_buffer_raw(&mut self, size: usize, usage: BufferUsage) -> ::BufferHandle<()> {
+    fn create_buffer_raw(&mut self, size: usize, usage: BufferUsage) -> ::BufferHandle<GlDevice, ()> {
         let name = self.create_buffer_internal();
         let info = ::BufferInfo {
             usage: usage,
@@ -604,7 +598,7 @@ impl Device for GlDevice {
         ::BufferHandle::from_raw(::Handle(name, info))
     }
 
-    fn create_buffer_static_raw(&mut self, data: &[u8]) -> ::BufferHandle<()> {
+    fn create_buffer_static_raw(&mut self, data: &[u8]) -> ::BufferHandle<GlDevice, ()> {
         let name = self.create_buffer_internal();
 
         let info = ::BufferInfo {
@@ -616,7 +610,7 @@ impl Device for GlDevice {
         ::BufferHandle::from_raw(::Handle(name, info))
     }
 
-    fn create_array_buffer(&mut self) -> Result<::ArrayBufferHandle, ()> {
+    fn create_array_buffer(&mut self) -> Result<::ArrayBufferHandle<GlDevice>, ()> {
         if self.caps.array_buffer_supported {
             let mut name = 0 as ArrayBuffer;
             unsafe {
@@ -631,7 +625,7 @@ impl Device for GlDevice {
     }
 
     fn create_shader(&mut self, stage: ::shade::Stage, code: &[u8])
-                     -> Result<::ShaderHandle, ::shade::CreateShaderError> {
+                     -> Result<::ShaderHandle<GlDevice>, ::shade::CreateShaderError> {
         let (name, info) = shade::create_shader(&self.gl, stage, code);
         info.map(|info| {
             let level = if name.is_err() { LogLevel::Error } else { LogLevel::Warn };
@@ -640,7 +634,7 @@ impl Device for GlDevice {
         name.map(|sh| ::Handle(sh, stage))
     }
 
-    fn create_program(&mut self, shaders: &[::ShaderHandle], targets: Option<&[&str]>) -> Result<::ProgramHandle, ()> {
+    fn create_program(&mut self, shaders: &[::ShaderHandle<GlDevice>], targets: Option<&[&str]>) -> Result<::ProgramHandle<GlDevice>, ()> {
         let (prog, log) = shade::create_program(&self.gl, &self.caps, shaders, targets);
         log.map(|log| {
             let level = if prog.is_err() { LogLevel::Error } else { LogLevel::Warn };
@@ -649,7 +643,7 @@ impl Device for GlDevice {
         prog
     }
 
-    fn create_frame_buffer(&mut self) -> ::FrameBufferHandle {
+    fn create_frame_buffer(&mut self) -> ::FrameBufferHandle<GlDevice> {
         if !self.caps.render_targets_supported {
             panic!("No framebuffer objects, can't make a new one!");
         }
@@ -663,12 +657,12 @@ impl Device for GlDevice {
     }
 
     fn create_surface(&mut self, info: ::tex::SurfaceInfo) ->
-                      Result<::SurfaceHandle, ::tex::SurfaceError> {
+                      Result<::SurfaceHandle<GlDevice>, ::tex::SurfaceError> {
         tex::make_surface(&self.gl, &info).map(|suf| ::Handle(suf, info))
     }
 
     fn create_texture(&mut self, info: ::tex::TextureInfo) ->
-                      Result<::TextureHandle, ::tex::TextureError> {
+                      Result<::TextureHandle<GlDevice>, ::tex::TextureError> {
         if info.width == 0 || info.height == 0 || info.levels == 0 {
             return Err(::tex::TextureError::InvalidTextureInfo(info))
         }
@@ -681,7 +675,7 @@ impl Device for GlDevice {
         name.map(|tex| ::Handle(tex, info))
     }
 
-    fn create_sampler(&mut self, info: ::tex::SamplerInfo) -> ::SamplerHandle {
+    fn create_sampler(&mut self, info: ::tex::SamplerInfo) -> ::SamplerHandle<GlDevice> {
         let sam = if self.caps.sampler_objects_supported {
             tex::make_sampler(&self.gl, &info)
         } else {
@@ -690,61 +684,61 @@ impl Device for GlDevice {
         ::Handle(sam, info)
     }
 
-    fn delete_buffer_raw(&mut self, handle: ::BufferHandle<()>) {
+    fn delete_buffer_raw(&mut self, handle: ::BufferHandle<GlDevice, ()>) {
         let name = handle.get_name();
         unsafe {
             self.gl.DeleteBuffers(1, &name);
         }
     }
 
-    fn delete_shader(&mut self, handle: ::ShaderHandle) {
+    fn delete_shader(&mut self, handle: ::ShaderHandle<GlDevice>) {
         unsafe { self.gl.DeleteShader(handle.get_name()) };
     }
 
-    fn delete_program(&mut self, handle: ::ProgramHandle) {
+    fn delete_program(&mut self, handle: ::ProgramHandle<GlDevice>) {
         unsafe { self.gl.DeleteProgram(handle.get_name()) };
     }
 
-    fn delete_surface(&mut self, handle: ::SurfaceHandle) {
+    fn delete_surface(&mut self, handle: ::SurfaceHandle<GlDevice>) {
         let name = handle.get_name();
         unsafe {
             self.gl.DeleteRenderbuffers(1, &name);
         }
     }
 
-    fn delete_texture(&mut self, handle: ::TextureHandle) {
+    fn delete_texture(&mut self, handle: ::TextureHandle<GlDevice>) {
         let name = handle.get_name();
         unsafe {
             self.gl.DeleteTextures(1, &name);
         }
     }
 
-    fn delete_sampler(&mut self, handle: ::SamplerHandle) {
+    fn delete_sampler(&mut self, handle: ::SamplerHandle<GlDevice>) {
         let name = handle.get_name();
         unsafe {
             self.gl.DeleteSamplers(1, &name);
         }
     }
 
-    fn update_buffer_raw(&mut self, buffer: ::BufferHandle<()>, data: &[u8],
+    fn update_buffer_raw(&mut self, buffer: ::BufferHandle<GlDevice, ()>, data: &[u8],
                          offset_bytes: usize) {
         debug_assert!(offset_bytes + data.len() <= buffer.get_info().size);
         self.update_sub_buffer(buffer.get_name(), data.as_ptr(), data.len(),
                                offset_bytes)
     }
 
-    fn update_texture_raw(&mut self, texture: &::TextureHandle,
+    fn update_texture_raw(&mut self, texture: &::TextureHandle<GlDevice>,
                           img: &::tex::ImageInfo, data: &[u8])
                           -> Result<(), ::tex::TextureError> {
         tex::update_texture(&self.gl, texture.get_info().kind,
                             texture.get_name(), img, data.as_ptr(), data.len())
     }
 
-    fn generate_mipmap(&mut self, texture: &::TextureHandle) {
+    fn generate_mipmap(&mut self, texture: &::TextureHandle<GlDevice>) {
         tex::generate_mipmap(&self.gl, texture.get_info().kind, texture.get_name());
     }
 
-    fn map_buffer_raw(&mut self, buf: BufferHandle<()>, access: MapAccess) -> RawMapping {
+    fn map_buffer_raw(&mut self, buf: BufferHandle<GlDevice, ()>, access: MapAccess) -> RawMapping {
         let ptr;
         unsafe { self.gl.BindBuffer(gl::ARRAY_BUFFER, buf.get_name()) };
         ptr = unsafe { self.gl.MapBuffer(gl::ARRAY_BUFFER, match access {
@@ -762,7 +756,7 @@ impl Device for GlDevice {
         unsafe { self.gl.UnmapBuffer(map.target) };
     }
 
-    fn map_buffer_readable<T: Copy>(&mut self, buf: BufferHandle<T>) -> ReadableMapping<T, GlDevice> {
+    fn map_buffer_readable<T: Copy>(&mut self, buf: BufferHandle<GlDevice, T>) -> ReadableMapping<T, GlDevice> {
         let map = self.map_buffer_raw(buf.cast(), MapAccess::Readable);
         ReadableMapping {
             raw: map,
@@ -771,7 +765,7 @@ impl Device for GlDevice {
         }
     }
 
-    fn map_buffer_writable<T: Copy>(&mut self, buf: BufferHandle<T>) -> WritableMapping<T, GlDevice> {
+    fn map_buffer_writable<T: Copy>(&mut self, buf: BufferHandle<GlDevice, T>) -> WritableMapping<T, GlDevice> {
         let map = self.map_buffer_raw(buf.cast(), MapAccess::Writable);
         WritableMapping {
             raw: map,
@@ -780,7 +774,7 @@ impl Device for GlDevice {
         }
     }
 
-    fn map_buffer_rw<T: Copy>(&mut self, buf: BufferHandle<T>) -> RWMapping<T, GlDevice> {
+    fn map_buffer_rw<T: Copy>(&mut self, buf: BufferHandle<GlDevice, T>) -> RWMapping<T, GlDevice> {
         let map = self.map_buffer_raw(buf.cast(), MapAccess::RW);
         RWMapping {
             raw: map,
diff --git a/src/device/gl_device/shade.rs b/src/device/gl_device/shade.rs
index 7400326658f..7bc6165e5f3 100644
--- a/src/device/gl_device/shade.rs
+++ b/src/device/gl_device/shade.rs
@@ -279,8 +279,8 @@ fn query_parameters(gl: &gl::Gl, caps: &::Capabilities, prog: super::Program) ->
     (uniforms, textures)
 }
 
-pub fn create_program(gl: &gl::Gl, caps: &::Capabilities, shaders: &[::ShaderHandle], targets: Option<&[&str]>)
-        -> (Result<::ProgramHandle, ()>, Option<String>) {
+pub fn create_program(gl: &gl::Gl, caps: &::Capabilities, shaders: &[::ShaderHandle<super::GlDevice>], targets: Option<&[&str]>)
+        -> (Result<::ProgramHandle<super::GlDevice>, ()>, Option<String>) {
     let name = unsafe { gl.CreateProgram() };
     for sh in shaders.iter() {
         unsafe { gl.AttachShader(name, sh.get_name()) };
diff --git a/src/device/lib.rs b/src/device/lib.rs
index 5b6908a731e..3070c785222 100644
--- a/src/device/lib.rs
+++ b/src/device/lib.rs
@@ -26,6 +26,7 @@ extern crate libc;
 // TODO: Remove these exports once `gl_device` becomes a separate crate.
 pub use self::gl_device as back;
 
+use std::fmt;
 use std::mem;
 use std::slice;
 use std::ops::{Deref, DerefMut};
@@ -149,7 +150,9 @@ impl<T: Copy, I> Handle<T, I> {
         let Handle(name, _) = *self;
         name
     }
+}
 
+impl<T, I> Handle<T, I> {
     /// Get the info reference
     pub fn get_info(&self) -> &I {
         let Handle(_, ref info) = *self;
@@ -158,21 +161,40 @@ impl<T: Copy, I> Handle<T, I> {
 }
 
 /// Type-safe buffer handle
-#[derive(Copy, Debug, PartialEq, Clone)]
-pub struct BufferHandle<T> {
-    raw: RawBufferHandle,
+pub struct BufferHandle<D: Device, T> {
+    raw: RawBufferHandle<D>,
+}
+
+impl<D: Device, T> Copy for BufferHandle<D, T> {}
+
+impl<D: Device, T> Clone for BufferHandle<D, T> {
+    fn clone(&self) -> BufferHandle<D, T> {
+        BufferHandle { raw: self.raw }
+    }
+}
+
+impl<D: Device, T> PartialEq for BufferHandle<D, T> {
+    fn eq(&self, other: &BufferHandle<D, T>) -> bool {
+        self.raw == other.raw
+    }
+}
+
+impl<D: Device, T> fmt::Debug for BufferHandle<D, T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "BufferHandle {{ raw: {:?} }}", self.raw)
+    }
 }
 
-impl<T> BufferHandle<T> {
+impl<T> BufferHandle<back::GlDevice, T> {
     /// Create a type-safe BufferHandle from a RawBufferHandle
-    pub fn from_raw(handle: RawBufferHandle) -> BufferHandle<T> {
+    pub fn from_raw(handle: RawBufferHandle<back::GlDevice>) -> BufferHandle<back::GlDevice, T> {
         BufferHandle {
             raw: handle,
         }
     }
 
     /// Cast the type this BufferHandle references
-    pub fn cast<U>(self) -> BufferHandle<U> {
+    pub fn cast<U>(self) -> BufferHandle<back::GlDevice, U> {
         BufferHandle::from_raw(self.raw)
     }
 
@@ -187,7 +209,7 @@ impl<T> BufferHandle<T> {
     }
 
     /// Get the underlying raw Handle
-    pub fn raw(&self) -> RawBufferHandle {
+    pub fn raw(&self) -> RawBufferHandle<back::GlDevice> {
         self.raw
     }
 
@@ -201,25 +223,25 @@ impl<T> BufferHandle<T> {
 }
 
 /// Raw (untyped) Buffer Handle
-pub type RawBufferHandle = Handle<back::Buffer, BufferInfo>;
+pub type RawBufferHandle<D: Device> = Handle<<D as Device>::Buffer, BufferInfo>;
 /// Array Buffer Handle
-pub type ArrayBufferHandle = Handle<back::ArrayBuffer, ()>;
+pub type ArrayBufferHandle<D: Device> = Handle<<D as Device>::ArrayBuffer, ()>;
 /// Shader Handle
-pub type ShaderHandle  = Handle<back::Shader, shade::Stage>;
+pub type ShaderHandle<D: Device>  = Handle<<D as Device>::Shader, shade::Stage>;
 /// Program Handle
-pub type ProgramHandle = Handle<back::Program, shade::ProgramInfo>;
+pub type ProgramHandle<D: Device> = Handle<<D as Device>::Program, shade::ProgramInfo>;
 /// Frame Buffer Handle
-pub type FrameBufferHandle = Handle<back::FrameBuffer, ()>;
+pub type FrameBufferHandle<D: Device> = Handle<<D as Device>::FrameBuffer, ()>;
 /// Surface Handle
-pub type SurfaceHandle = Handle<back::Surface, tex::SurfaceInfo>;
+pub type SurfaceHandle<D: Device> = Handle<<D as Device>::Surface, tex::SurfaceInfo>;
 /// Texture Handle
-pub type TextureHandle = Handle<back::Texture, tex::TextureInfo>;
+pub type TextureHandle<D: Device> = Handle<<D as Device>::Texture, tex::TextureInfo>;
 /// Sampler Handle
-pub type SamplerHandle = Handle<back::Sampler, tex::SamplerInfo>;
+pub type SamplerHandle<D: Device> = Handle<<D as Device>::Sampler, tex::SamplerInfo>;
 
 /// A helper method to test `#[vertex_format]` without GL context
 //#[cfg(test)]
-pub fn make_fake_buffer<T>() -> BufferHandle<T> {
+pub fn make_fake_buffer<T>() -> BufferHandle<back::GlDevice, T> {
     let info = BufferInfo {
         usage: BufferUsage::Static,
         size: 0,
@@ -228,7 +250,7 @@ pub fn make_fake_buffer<T>() -> BufferHandle<T> {
 }
 
 /// Return the framebuffer handle for the screen.
-pub fn get_main_frame_buffer() -> FrameBufferHandle {
+pub fn get_main_frame_buffer() -> FrameBufferHandle<back::GlDevice> {
     Handle(0, ())
 }
 
@@ -329,14 +351,14 @@ pub trait Device {
             Sampler         = Self::Sampler,
         >;
 
-    type Buffer;
-    type ArrayBuffer;
-    type Shader;
-    type Program;
-    type FrameBuffer;
-    type Surface;
-    type Texture;
-    type Sampler;
+    type Buffer:        Copy + fmt::Debug + PartialEq + Clone;
+    type ArrayBuffer:   Copy + fmt::Debug + PartialEq + Clone;
+    type Shader:        Copy + fmt::Debug + PartialEq + Clone;
+    type Program:       Copy + fmt::Debug + PartialEq + Clone;
+    type FrameBuffer:   Copy + fmt::Debug + PartialEq + Clone;
+    type Surface:       Copy + fmt::Debug + PartialEq + Clone;
+    type Texture:       Copy + fmt::Debug + PartialEq + Clone;
+    type Sampler:       Copy + fmt::Debug + PartialEq + Clone;
 
     /// Returns the capabilities available to the specific API implementation
     fn get_capabilities<'a>(&'a self) -> &'a Capabilities;
@@ -346,56 +368,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<T>(&mut self, num: usize, usage: BufferUsage) -> BufferHandle<T> {
+    fn create_buffer_raw(&mut self, size: usize, usage: BufferUsage) -> BufferHandle<back::GlDevice, ()>;
+    fn create_buffer<T>(&mut self, num: usize, usage: BufferUsage) -> BufferHandle<back::GlDevice, T> {
         self.create_buffer_raw(num * mem::size_of::<T>(), usage).cast()
     }
-    fn create_buffer_static_raw(&mut self, data: &[u8]) -> BufferHandle<()>;
-    fn create_buffer_static<T: Copy>(&mut self, data: &[T]) -> BufferHandle<T> {
+    fn create_buffer_static_raw(&mut self, data: &[u8]) -> BufferHandle<back::GlDevice, ()>;
+    fn create_buffer_static<T: Copy>(&mut self, data: &[T]) -> BufferHandle<back::GlDevice, T> {
         self.create_buffer_static_raw(as_byte_slice(data)).cast()
     }
-    fn create_array_buffer(&mut self) -> Result<ArrayBufferHandle, ()>;
+    fn create_array_buffer(&mut self) -> Result<ArrayBufferHandle<back::GlDevice>, ()>;
     fn create_shader(&mut self, stage: shade::Stage, code: &[u8]) ->
-                     Result<ShaderHandle, shade::CreateShaderError>;
-    fn create_program(&mut self, shaders: &[ShaderHandle], targets: Option<&[&str]>) -> Result<ProgramHandle, ()>;
-    fn create_frame_buffer(&mut self) -> FrameBufferHandle;
-    fn create_surface(&mut self, info: tex::SurfaceInfo) -> Result<SurfaceHandle, tex::SurfaceError>;
-    fn create_texture(&mut self, info: tex::TextureInfo) -> Result<TextureHandle, tex::TextureError>;
-    fn create_sampler(&mut self, info: tex::SamplerInfo) -> SamplerHandle;
+                     Result<ShaderHandle<back::GlDevice>, shade::CreateShaderError>;
+    fn create_program(&mut self, shaders: &[ShaderHandle<back::GlDevice>], targets: Option<&[&str]>) -> Result<ProgramHandle<back::GlDevice>, ()>;
+    fn create_frame_buffer(&mut self) -> FrameBufferHandle<back::GlDevice>;
+    fn create_surface(&mut self, info: tex::SurfaceInfo) -> Result<SurfaceHandle<back::GlDevice>, tex::SurfaceError>;
+    fn create_texture(&mut self, info: tex::TextureInfo) -> Result<TextureHandle<back::GlDevice>, tex::TextureError>;
+    fn create_sampler(&mut self, info: tex::SamplerInfo) -> SamplerHandle<back::GlDevice>;
 
     // resource deletion
-    fn delete_buffer_raw(&mut self, buf: BufferHandle<()>);
-    fn delete_buffer<T>(&mut self, buf: BufferHandle<T>) {
+    fn delete_buffer_raw(&mut self, buf: BufferHandle<back::GlDevice, ()>);
+    fn delete_buffer<T>(&mut self, buf: BufferHandle<back::GlDevice, T>) {
         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<back::GlDevice>);
+    fn delete_program(&mut self, ProgramHandle<back::GlDevice>);
+    fn delete_surface(&mut self, SurfaceHandle<back::GlDevice>);
+    fn delete_texture(&mut self, TextureHandle<back::GlDevice>);
+    fn delete_sampler(&mut self, SamplerHandle<back::GlDevice>);
 
     /// 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<back::GlDevice, ()>, data: &[u8],
                          offset_bytes: usize);
-    fn update_buffer<T: Copy>(&mut self, buf: BufferHandle<T>, data: &[T],
+    fn update_buffer<T: Copy>(&mut self, buf: BufferHandle<back::GlDevice, T>, data: &[T],
                      offset_elements: usize) {
         self.update_buffer_raw(buf.cast(), as_byte_slice(data), mem::size_of::<T>() * offset_elements)
     }
-    fn map_buffer_raw(&mut self, buf: BufferHandle<()>, access: MapAccess) -> back::RawMapping;
+    fn map_buffer_raw(&mut self, buf: BufferHandle<back::GlDevice, ()>, access: MapAccess) -> back::RawMapping;
     fn unmap_buffer_raw(&mut self, map: back::RawMapping);
-    fn map_buffer_readable<T: Copy>(&mut self, buf: BufferHandle<T>) -> ReadableMapping<T, Self>;
-    fn map_buffer_writable<T: Copy>(&mut self, buf: BufferHandle<T>) -> WritableMapping<T, Self>;
-    fn map_buffer_rw<T: Copy>(&mut self, buf: BufferHandle<T>) -> RWMapping<T, Self>;
+    fn map_buffer_readable<T: Copy>(&mut self, buf: BufferHandle<back::GlDevice, T>) -> ReadableMapping<T, Self>;
+    fn map_buffer_writable<T: Copy>(&mut self, buf: BufferHandle<back::GlDevice, T>) -> WritableMapping<T, Self>;
+    fn map_buffer_rw<T: Copy>(&mut self, buf: BufferHandle<back::GlDevice, T>) -> RWMapping<T, Self>;
 
     /// 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<back::GlDevice>, img: &tex::ImageInfo,
                           data: &[u8]) -> Result<(), tex::TextureError>;
-    fn update_texture<T: Copy>(&mut self, tex: &TextureHandle,
+    fn update_texture<T: Copy>(&mut self, tex: &TextureHandle<back::GlDevice>,
                       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<back::GlDevice>);
 }
 
 #[cfg(test)]
@@ -403,8 +425,9 @@ mod test {
     use std::mem;
     use super::{BufferHandle, Handle};
     use super::{BufferInfo, BufferUsage};
+    use super::back;
 
-    fn mock_buffer<T>(usage: BufferUsage, len: usize) -> BufferHandle<T> {
+    fn mock_buffer<T>(usage: BufferUsage, len: usize) -> BufferHandle<back::GlDevice, T> {
         BufferHandle {
             raw: Handle(
                 0,
diff --git a/src/gfx/lib.rs b/src/gfx/lib.rs
index 80de9ea0936..09153f8ffc8 100644
--- a/src/gfx/lib.rs
+++ b/src/gfx/lib.rs
@@ -73,7 +73,7 @@ impl<D: device::Device> Graphics<D> {
 
     /// Create a new ref batch.
     pub fn make_batch<T: shade::ShaderParam>(&mut self,
-                      program: &ProgramHandle,
+                      program: &ProgramHandle<GlDevice>,
                       mesh: &Mesh,
                       slice: Slice,
                       state: &DrawState)
diff --git a/src/gfx_macros/vertex_format.rs b/src/gfx_macros/vertex_format.rs
index 915b8f26274..07092fb68f7 100644
--- a/src/gfx_macros/vertex_format.rs
+++ b/src/gfx_macros/vertex_format.rs
@@ -258,9 +258,13 @@ impl ItemDecorator for VertexFormat {
                             params: vec![box generic::ty::Self_],
                             global: false,
                         }),
-                        generic::ty::Literal(generic::ty::Path::new(
-                            vec![super::EXTERN_CRATE_HACK, "gfx", "RawBufferHandle"]
-                        )),
+                        generic::ty::Literal(generic::ty::Path {
+                            path: vec![super::EXTERN_CRATE_HACK, "gfx", "RawBufferHandle"],
+                            lifetime: None,
+                            params: vec![box generic::ty::Literal(generic::ty::Path::new(
+                                             vec![super::EXTERN_CRATE_HACK, "gfx", "GlDevice"]))],
+                            global: false,
+                        }),
                     ],
                     ret_ty: generic::ty::Literal(
                         generic::ty::Path {
diff --git a/src/render/batch.rs b/src/render/batch.rs
index fabe4430769..ea32f6e3b27 100644
--- a/src/render/batch.rs
+++ b/src/render/batch.rs
@@ -19,6 +19,7 @@
 use std::fmt;
 use std::num::from_uint;
 use std::cmp::Ordering;
+use device::back;
 use device::{PrimitiveType, ProgramHandle};
 use device::shade::ProgramInfo;
 use render::mesh;
@@ -78,11 +79,11 @@ pub trait Batch {
     fn get_data(&self) -> Result<BatchData, Self::Error>;
     /// Fill shader parameter values
     fn fill_params(&self, ::shade::ParamValues)
-                   -> Result<&ProgramHandle, Self::Error>;
+                   -> Result<&ProgramHandle<back::GlDevice>, Self::Error>;
 }
 
 impl<'a, T: ShaderParam> Batch for (&'a mesh::Mesh, mesh::Slice,
-                                    &'a ProgramHandle, &'a T, &'a DrawState) {
+                                    &'a ProgramHandle<back::GlDevice>, &'a T, &'a DrawState) {
     type Error = BatchError;
 
     fn get_data(&self) -> Result<BatchData, BatchError> {
@@ -94,7 +95,7 @@ impl<'a, T: ShaderParam> Batch for (&'a mesh::Mesh, mesh::Slice,
     }
 
     fn fill_params(&self, values: ::shade::ParamValues)
-                   -> Result<&ProgramHandle, BatchError> {
+                   -> Result<&ProgramHandle<back::GlDevice>, BatchError> {
         let (_, _, program, params, _) = *self;
         match ShaderParam::create_link(None::<&T>, program.get_info()) {
             Ok(link) => {
@@ -114,7 +115,7 @@ pub struct OwnedBatch<T: ShaderParam> {
     pub slice: mesh::Slice,
     /// Parameter data.
     pub param: T,
-    program: ProgramHandle,
+    program: ProgramHandle<back::GlDevice>,
     param_link: T::Link,
     /// Draw state
     pub state: DrawState,
@@ -122,7 +123,7 @@ pub struct OwnedBatch<T: ShaderParam> {
 
 impl<T: ShaderParam> OwnedBatch<T> {
     /// Create a new owned batch
-    pub fn new(mesh: mesh::Mesh, program: ProgramHandle, param: T)
+    pub fn new(mesh: mesh::Mesh, program: ProgramHandle<back::GlDevice>, param: T)
            -> Result<OwnedBatch<T>, BatchError> {
         let slice = mesh.to_slice(PrimitiveType::TriangleList);
         let mesh_link = match link_mesh(&mesh, program.get_info()) {
@@ -153,7 +154,7 @@ impl<T: ShaderParam> Batch for OwnedBatch<T> {
     }
 
     fn fill_params(&self, values: ::shade::ParamValues)
-                   -> Result<&ProgramHandle, ()> {
+                   -> Result<&ProgramHandle<back::GlDevice>, ()> {
         self.param.fill_params(&self.param_link, values);
         Ok(&self.program)
     }
@@ -250,7 +251,7 @@ pub struct RefBatch<T: ShaderParam> {
     mesh_link: mesh::Link,
     /// Mesh slice
     pub slice: mesh::Slice,
-    program_id: Id<ProgramHandle>,
+    program_id: Id<ProgramHandle<back::GlDevice>>,
     param_link: T::Link,
     state_id: Id<DrawState>,
 }
@@ -290,7 +291,7 @@ impl<T> Ord for RefBatch<T> {
 /// Factory of ref batches, required to always be used with them.
 pub struct Context {
     meshes: Array<mesh::Mesh>,
-    programs: Array<ProgramHandle>,
+    programs: Array<ProgramHandle<back::GlDevice>>,
     states: Array<DrawState>,
 }
 
@@ -308,7 +309,7 @@ impl Context {
 impl Context {
     /// Produce a new ref batch
     pub fn make_batch<T: ShaderParam>(&mut self,
-                      program: &ProgramHandle,
+                      program: &ProgramHandle<back::GlDevice>,
                       mesh: &mesh::Mesh,
                       slice: mesh::Slice,
                       state: &DrawState)
@@ -358,7 +359,7 @@ impl<'a, T: ShaderParam> Batch for (&'a RefBatch<T>, &'a T, &'a Context) {
     }
 
     fn fill_params(&self, values: ::shade::ParamValues)
-                   -> Result<&ProgramHandle, OutOfBounds> {
+                   -> Result<&ProgramHandle<back::GlDevice>, OutOfBounds> {
         let (b, data, ctx) = *self;
         data.fill_params(&b.param_link, values);
         ctx.programs.get(b.program_id)
diff --git a/src/render/device_ext.rs b/src/render/device_ext.rs
index 5737a187e0c..0ce4c16c911 100644
--- a/src/render/device_ext.rs
+++ b/src/render/device_ext.rs
@@ -1,4 +1,5 @@
 use device;
+use device::back;
 use device::shade::{Stage, CreateShaderError, ShaderModel};
 use super::mesh::{Mesh, VertexFormat};
 
@@ -65,11 +66,11 @@ pub trait DeviceExt: device::Device {
     fn create_mesh<T: VertexFormat + Copy>(&mut self, data: &[T]) -> Mesh;
     /// Create a simple program given a vertex shader with a fragment one.
     fn link_program(&mut self, vs_code: &[u8], fs_code: &[u8])
-                    -> Result<device::ProgramHandle, ProgramError>;
+                    -> Result<device::ProgramHandle<back::GlDevice>, 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<device::ProgramHandle, ProgramError>;
+                           -> Result<device::ProgramHandle<back::GlDevice>, ProgramError>;
 }
 
 impl<D: device::Device> DeviceExt for D {
@@ -98,7 +99,7 @@ impl<D: device::Device> DeviceExt for D {
     }
 
     fn link_program(&mut self, vs_code: &[u8], fs_code: &[u8])
-                    -> Result<device::ProgramHandle, ProgramError> {
+                    -> Result<device::ProgramHandle<back::GlDevice>, ProgramError> {
         let vs = match self.create_shader(Stage::Vertex, vs_code) {
             Ok(s) => s,
             Err(e) => return Err(ProgramError::Vertex(e)),
@@ -113,7 +114,7 @@ impl<D: device::Device> DeviceExt for D {
     }
 
     fn link_program_source(&mut self, vs_src: ShaderSource, fs_src: ShaderSource)
-                           -> Result<device::ProgramHandle, ProgramError> {
+                           -> Result<device::ProgramHandle<back::GlDevice>, 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 d63f40c3f56..ace7b7354c8 100644
--- a/src/render/lib.rs
+++ b/src/render/lib.rs
@@ -25,6 +25,7 @@ use std::mem;
 use device::Device;
 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};
@@ -46,7 +47,7 @@ pub mod target;
 
 
 const TRACKED_ATTRIBUTES: usize = 8;
-type CachedAttribute = (device::RawBufferHandle, attrib::Format);
+type CachedAttribute = (device::RawBufferHandle<back::GlDevice>, attrib::Format);
 type Instancing = (device::InstanceCount, device::VertexCount);
 
 /// The internal state of the renderer.
@@ -56,7 +57,7 @@ struct RenderState {
     frame: target::Frame,
     is_array_buffer_set: bool,
     program_name: device::back::Program,
-    index: Option<device::RawBufferHandle>,
+    index: Option<device::RawBufferHandle<back::GlDevice>>,
     attributes: [Option<CachedAttribute>; TRACKED_ATTRIBUTES],
     draw: state::DrawState,
 }
@@ -79,7 +80,7 @@ impl RenderState {
 /// Temporary parameter storage, used for shader activation.
 struct ParamStorage {
     uniforms: Vec<UniformValue>,
-    blocks  : Vec<device::RawBufferHandle>,
+    blocks  : Vec<device::RawBufferHandle<back::GlDevice>>,
     textures: Vec<shade::TextureParam>,
 }
 
@@ -145,10 +146,10 @@ pub enum DrawError<E> {
 pub struct Renderer<D: Device> {
     command_buffer: D::CommandBuffer,
     data_buffer: device::draw::DataBuffer,
-    common_array_buffer: Result<device::ArrayBufferHandle, ()>,
-    draw_frame_buffer: device::FrameBufferHandle,
-    read_frame_buffer: device::FrameBufferHandle,
-    default_frame_buffer: device::FrameBufferHandle,
+    common_array_buffer: Result<device::ArrayBufferHandle<back::GlDevice>, ()>,
+    draw_frame_buffer: device::FrameBufferHandle<back::GlDevice>,
+    read_frame_buffer: device::FrameBufferHandle<back::GlDevice>,
+    default_frame_buffer: device::FrameBufferHandle<back::GlDevice>,
     render_state: RenderState,
     parameters: ParamStorage,
 }
@@ -247,7 +248,7 @@ impl<D: Device> Renderer<D> {
     }
 
     /// Update a buffer with data from a vector.
-    pub fn update_buffer_vec<T: Copy>(&mut self, buf: device::BufferHandle<T>,
+    pub fn update_buffer_vec<T: Copy>(&mut self, buf: device::BufferHandle<back::GlDevice, T>,
                              data: &[T], offset_elements: usize) {
         let esize = mem::size_of::<T>();
         let offset_bytes = esize * offset_elements;
@@ -258,14 +259,14 @@ impl<D: Device> Renderer<D> {
 
     /// Update a buffer with data from a single type.
     pub fn update_buffer_struct<U, T: Copy>(&mut self,
-                                buf: device::BufferHandle<U>, data: &T) {
+                                buf: device::BufferHandle<back::GlDevice, U>, data: &T) {
         debug_assert!(mem::size_of::<T>() <= 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<T: Copy>(&mut self, tex: device::TextureHandle,
+    pub fn update_texture<T: Copy>(&mut self, tex: device::TextureHandle<back::GlDevice>,
                           img: device::tex::ImageInfo, data: &[T]) {
         debug_assert!(tex.get_info().contains(&img));
         let pointer = self.data_buffer.add_vec(data);
@@ -368,7 +369,7 @@ impl<D: Device> Renderer<D> {
     }
 
     fn bind_program<'a, B: Batch>(&mut self, batch: &'a B)
-                    -> Result<&'a device::ProgramHandle, B::Error> {
+                    -> Result<&'a device::ProgramHandle<back::GlDevice>, B::Error> {
         let program = match batch.fill_params(self.parameters.get_mut()) {
             Ok(p) => p,
             Err(e) => return Err(e),
@@ -382,7 +383,7 @@ impl<D: Device> Renderer<D> {
         Ok(program)
     }
 
-    fn upload_parameters(&mut self, program: &device::ProgramHandle) {
+    fn upload_parameters(&mut self, program: &device::ProgramHandle<back::GlDevice>) {
         let info = program.get_info();
         if self.parameters.uniforms.len() != info.uniforms.len() ||
             self.parameters.blocks.len() != info.blocks.len() ||
@@ -448,7 +449,7 @@ impl<D: Device> Renderer<D> {
         }
     }
 
-    fn bind_index<T>(&mut self, buf: device::BufferHandle<T>) {
+    fn bind_index<T>(&mut self, buf: device::BufferHandle<back::GlDevice, T>) {
         if self.render_state.index != Some(buf.raw()) {
             self.command_buffer.bind_index(buf.get_name());
             self.render_state.index = Some(buf.raw());
diff --git a/src/render/mesh.rs b/src/render/mesh.rs
index 331ba84d9de..0a369189f70 100644
--- a/src/render/mesh.rs
+++ b/src/render/mesh.rs
@@ -22,7 +22,7 @@
 
 use device;
 use device::{PrimitiveType, BufferHandle, VertexCount};
-use device::attrib;
+use device::{attrib, back};
 
 /// Describes a single attribute of a vertex buffer, including its type, name, etc.
 #[derive(Clone, PartialEq, Debug)]
@@ -30,7 +30,7 @@ pub struct Attribute {
     /// A name to match the shader input
     pub name: String,
     /// Vertex buffer to contain the data
-    pub buffer: device::RawBufferHandle,
+    pub buffer: device::RawBufferHandle<back::GlDevice>,
     /// Format of the attribute
     pub format: attrib::Format,
 }
@@ -39,7 +39,7 @@ pub struct Attribute {
 /// `#[vertex_format] attribute
 pub trait VertexFormat {
     /// Create the attributes for this type, using the given buffer.
-    fn generate(Option<Self>, buffer: device::RawBufferHandle) -> Vec<Attribute>;
+    fn generate(Option<Self>, buffer: device::RawBufferHandle<back::GlDevice>) -> Vec<Attribute>;
 }
 
 /// Describes geometry to render.
@@ -61,7 +61,7 @@ impl Mesh {
     }
 
     /// Create a new `Mesh` from a struct that implements `VertexFormat` and a buffer.
-    pub fn from_format<V: VertexFormat>(buf: device::BufferHandle<V>, nv: device::VertexCount) -> Mesh {
+    pub fn from_format<V: VertexFormat>(buf: device::BufferHandle<back::GlDevice, V>, nv: device::VertexCount) -> Mesh {
         Mesh {
             num_vertices: nv,
             attributes: VertexFormat::generate(None::<V>, buf.raw()),
@@ -70,8 +70,8 @@ impl Mesh {
 
     /// Create a new intanced `Mesh` given a vertex buffer and an instance buffer.
     pub fn from_format_instanced<V: VertexFormat, U: VertexFormat>(
-                                 buf: device::BufferHandle<V>, nv: device::VertexCount,
-                                 inst: device::BufferHandle<U>) -> Mesh {
+                                 buf: device::BufferHandle<back::GlDevice, V>, nv: device::VertexCount,
+                                 inst: device::BufferHandle<back::GlDevice, U>) -> Mesh {
         let per_vertex   = VertexFormat::generate(None::<V>, buf.raw());
         let per_instance = VertexFormat::generate(None::<U>, inst.raw());
 
@@ -122,11 +122,11 @@ pub enum SliceKind {
     /// the vertices will be identical, wasting space for the duplicated
     /// attributes.  Instead, the `Mesh` can store 4 vertices and an
     /// `Index8` can be used instead.
-    Index8(BufferHandle<u8>, VertexCount),
+    Index8(BufferHandle<back::GlDevice, u8>, VertexCount),
     /// As `Index8` but with `u16` indices
-    Index16(BufferHandle<u16>, VertexCount),
+    Index16(BufferHandle<back::GlDevice, u16>, VertexCount),
     /// As `Index8` but with `u32` indices
-    Index32(BufferHandle<u32>, VertexCount),
+    Index32(BufferHandle<back::GlDevice, u32>, VertexCount),
 }
 
 /// Helper methods for cleanly getting the slice of a type.
@@ -147,7 +147,7 @@ impl ToSlice for Mesh {
     }
 }
 
-impl ToSlice for BufferHandle<u8> {
+impl ToSlice for BufferHandle<back::GlDevice, u8> {
     /// Return an index slice of the whole buffer.
     fn to_slice(&self, ty: PrimitiveType) -> Slice {
         Slice {
@@ -159,7 +159,7 @@ impl ToSlice for BufferHandle<u8> {
     }
 }
 
-impl ToSlice for BufferHandle<u16> {
+impl ToSlice for BufferHandle<back::GlDevice, u16> {
     /// Return an index slice of the whole buffer.
     fn to_slice(&self, ty: PrimitiveType) -> Slice {
         Slice {
@@ -171,7 +171,7 @@ impl ToSlice for BufferHandle<u16> {
     }
 }
 
-impl ToSlice for BufferHandle<u32> {
+impl ToSlice for BufferHandle<back::GlDevice, u32> {
     /// Return an index slice of the whole buffer.
     fn to_slice(&self, ty: PrimitiveType) -> Slice {
         Slice {
diff --git a/src/render/shade.rs b/src/render/shade.rs
index 893d200ffcf..92b3a51a812 100644
--- a/src/render/shade.rs
+++ b/src/render/shade.rs
@@ -15,7 +15,7 @@
 //! Shader parameter handling.
 
 use std::cell::Cell;
-use device::shade;
+use device::{back, shade};
 use device::shade::UniformValue;
 use device::{RawBufferHandle, TextureHandle, SamplerHandle};
 
@@ -62,7 +62,7 @@ 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<SamplerHandle>);
+pub type TextureParam = (TextureHandle<back::GlDevice>, Option<SamplerHandle<back::GlDevice>>);
 
 /// A borrowed mutable storage for shader parameter values.
 // Not sure if it's the best data structure to represent it.
@@ -70,7 +70,7 @@ pub struct ParamValues<'a> {
     /// uniform values to be provided
     pub uniforms: &'a mut Vec<UniformValue>,
     /// uniform buffers to be provided
-    pub blocks  : &'a mut Vec<RawBufferHandle>,
+    pub blocks  : &'a mut Vec<RawBufferHandle<back::GlDevice>>,
     /// textures to be provided
     pub textures: &'a mut Vec<TextureParam>,
 }
@@ -135,7 +135,7 @@ pub struct ParamDictionary {
     /// Uniform dictionary
     pub uniforms: Vec<NamedCell<shade::UniformValue>>,
     /// Block dictionary
-    pub blocks: Vec<NamedCell<RawBufferHandle>>,
+    pub blocks: Vec<NamedCell<RawBufferHandle<back::GlDevice>>>,
     /// Texture dictionary
     pub textures: Vec<NamedCell<TextureParam>>,
 }
diff --git a/src/render/target.rs b/src/render/target.rs
index 616413d63f2..002b630a51e 100644
--- a/src/render/target.rs
+++ b/src/render/target.rs
@@ -15,16 +15,17 @@
 //! Render target specification.
 
 use device;
+use device::back;
 use device::target::{Level, Layer, Mask};
 
 #[derive(Copy, Clone, PartialEq, Debug)]
 /// A single buffer that can be bound to a render target.
 pub enum Plane {
     /// Render to a `Surface` (corresponds to a renderbuffer in GL).
-    Surface(device::SurfaceHandle),
+    Surface(device::SurfaceHandle<back::GlDevice>),
     /// Render to a texture at a specific mipmap level
     /// If `Layer` is set, it is selecting a single 2D slice of a given 3D texture
-    Texture(device::TextureHandle, Level, Option<Layer>),
+    Texture(device::TextureHandle<back::GlDevice>, Level, Option<Layer>),
 }
 
 impl Plane {
diff --git a/tests/shader_param.rs b/tests/shader_param.rs
index 2bdb1d29d1d..3345263bc57 100644
--- a/tests/shader_param.rs
+++ b/tests/shader_param.rs
@@ -26,7 +26,7 @@ struct TestParam {
     a: i32,
     b: [f32; 4],
     c: gfx::shade::TextureParam,
-    d: gfx::RawBufferHandle,
+    d: gfx::RawBufferHandle<gfx::GlDevice>,
     e: f32,
     #[name = "a_f"]
     f: [f32; 4],