#![deny(missing_docs, missing_copy_implementations)]
use std::{fmt, mem, raw};
use std::ops::{Deref, DerefMut};
use std::marker::{PhantomData, PhantomFn};
pub mod attrib;
pub mod draw;
pub mod shade;
pub mod state;
pub mod target;
pub mod tex;
pub type VertexCount = u32;
pub type InstanceCount = u32;
pub type UniformBlockIndex = u8;
pub type AttributeSlot = u8;
pub type UniformBufferSlot = u8;
pub type TextureSlot = u8;
#[derive(Copy)]
pub enum MapAccess {
Readable,
Writable,
RW
}
pub trait RawMapping {
unsafe fn set<T>(&self, index: usize, val: T);
unsafe fn to_slice<T>(&self, len: usize) -> &[T];
unsafe fn to_mut_slice<T>(&self, len: usize) -> &mut [T];
}
pub struct ReadableMapping<'a, T: Copy, D: 'a + Device> {
raw: D::Mapper,
len: usize,
device: &'a mut D,
phantom_t: PhantomData<T>
}
impl<'a, T: Copy, D: Device> Deref for ReadableMapping<'a, T, D> where
D::Mapper: 'a,
{
type Target = [T];
fn deref(&self) -> &[T] {
unsafe { self.raw.to_slice(self.len) }
}
}
#[unsafe_destructor]
impl<'a, T: Copy, D: Device> Drop for ReadableMapping<'a, T, D> where
D::Mapper: 'a,
{
fn drop(&mut self) {
self.device.unmap_buffer_raw(self.raw.clone())
}
}
pub struct WritableMapping<'a, T: Copy, D: 'a + Device> {
raw: D::Mapper,
len: usize,
device: &'a mut D,
phantom_t: PhantomData<T>
}
impl<'a, T: Copy, D: Device> WritableMapping<'a, T, D> {
pub fn set(&mut self, idx: usize, val: T) {
if idx >= self.len {
panic!("Tried to write out of bounds to a WritableMapping!")
}
unsafe { self.raw.set(idx, val); }
}
}
#[unsafe_destructor]
impl<'a, T: Copy, D: Device> Drop for WritableMapping<'a, T, D> where
D::Mapper: 'a,
{
fn drop(&mut self) {
self.device.unmap_buffer_raw(self.raw.clone())
}
}
pub struct RWMapping<'a, T: Copy, D: 'a + Device> {
raw: D::Mapper,
len: usize,
device: &'a mut D,
phantom_t: PhantomData<T>
}
impl<'a, T: Copy, D: Device> Deref for RWMapping<'a, T, D> where D::Mapper: 'a {
type Target = [T];
fn deref(&self) -> &[T] {
unsafe { self.raw.to_slice(self.len) }
}
}
impl<'a, T: Copy, D: Device> DerefMut for RWMapping<'a, T, D> where D::Mapper: 'a {
fn deref_mut(&mut self) -> &mut [T] {
unsafe { self.raw.to_mut_slice(self.len) }
}
}
#[unsafe_destructor]
impl<'a, T: Copy, D: Device> Drop for RWMapping<'a, T, D> where D::Mapper: 'a {
fn drop(&mut self) {
self.device.unmap_buffer_raw(self.raw.clone())
}
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Handle<T, I>(T, I);
impl<T: Copy, I> Handle<T, I> {
pub fn get_name(&self) -> T {
let Handle(name, _) = *self;
name
}
}
impl<T, I> Handle<T, I> {
pub fn get_info(&self) -> &I {
let Handle(_, ref info) = *self;
info
}
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct BufferHandle<R: Resources, T> {
raw: RawBufferHandle<R>,
phantom_t: PhantomData<T>,
}
impl<R: Resources, T> BufferHandle<R, T> {
pub fn from_raw(handle: RawBufferHandle<R>) -> BufferHandle<R, T> {
BufferHandle {
raw: handle,
phantom_t: PhantomData,
}
}
pub fn cast<U>(self) -> BufferHandle<R, U> {
BufferHandle::from_raw(self.raw)
}
pub fn get_name(&self) -> <R as Resources>::Buffer {
self.raw.get_name()
}
pub fn raw(&self) -> RawBufferHandle<R> {
self.raw
}
pub fn get_info(&self) -> &BufferInfo {
self.raw.get_info()
}
pub fn len(&self) -> usize {
assert!(mem::size_of::<T>() != 0, "Cannot determine the length of zero-sized buffers.");
self.get_info().size / mem::size_of::<T>()
}
}
pub type RawBufferHandle<R: Resources> = Handle<<R as Resources>::Buffer, BufferInfo>;
pub type ArrayBufferHandle<R: Resources> = Handle<<R as Resources>::ArrayBuffer, ()>;
pub type ShaderHandle<R: Resources> = Handle<<R as Resources>::Shader, shade::Stage>;
pub type ProgramHandle<R: Resources> = Handle<<R as Resources>::Program, shade::ProgramInfo>;
pub type FrameBufferHandle<R: Resources> = Handle<<R as Resources>::FrameBuffer, ()>;
pub type SurfaceHandle<R: Resources> = Handle<<R as Resources>::Surface, tex::SurfaceInfo>;
pub type TextureHandle<R: Resources> = Handle<<R as Resources>::Texture, tex::TextureInfo>;
pub type SamplerHandle<R: Resources> = Handle<<R as Resources>::Sampler, tex::SamplerInfo>;
pub fn as_byte_slice<T>(slice: &[T]) -> &[u8] {
let len = mem::size_of::<T>() * slice.len();
let slice = raw::Slice { data: slice.as_ptr(), len: len };
unsafe { mem::transmute(slice) }
}
#[derive(Copy, Debug)]
#[allow(missing_docs)] pub struct Capabilities {
pub shader_model: shade::ShaderModel,
pub max_draw_buffers: usize,
pub max_texture_size: usize,
pub max_vertex_attributes: usize,
pub array_buffer_supported: bool,
pub fragment_output_supported: bool,
pub immutable_storage_supported: bool,
pub instance_base_supported: bool,
pub instance_call_supported: bool,
pub instance_rate_supported: bool,
pub render_targets_supported: bool,
pub sampler_objects_supported: bool,
pub uniform_block_supported: bool,
pub vertex_base_supported: bool,
}
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum PrimitiveType {
Point,
Line,
LineStrip,
TriangleList,
TriangleStrip,
TriangleFan,
}
pub type IndexType = attrib::IntSize;
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum BufferUsage {
Static,
Dynamic,
Stream,
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct BufferInfo {
pub usage: BufferUsage,
pub size: usize,
}
#[allow(missing_docs)]
pub trait Resources: PhantomFn<Self> + Copy + Clone + PartialEq + fmt::Debug {
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;
type Program: Copy + Clone + fmt::Debug + PartialEq + Send + Sync;
type FrameBuffer: Copy + Clone + fmt::Debug + PartialEq + Send + Sync;
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;
}
impl Resources for () {
type Buffer = ();
type ArrayBuffer = ();
type Shader = ();
type Program = ();
type FrameBuffer = ();
type Surface = ();
type Texture = ();
type Sampler = ();
}
#[allow(missing_docs)]
pub trait Device {
type Resources: Resources;
type Mapper: Clone + RawMapping;
type CommandBuffer: draw::CommandBuffer<Resources = Self::Resources>;
fn get_capabilities<'a>(&'a self) -> &'a Capabilities;
fn reset_state(&mut self);
fn submit(&mut self, buffer: (&Self::CommandBuffer, &draw::DataBuffer));
fn create_buffer_raw(&mut self, size: usize, usage: BufferUsage) -> BufferHandle<Self::Resources, ()>;
fn create_buffer<T>(&mut self, num: usize, usage: BufferUsage) -> BufferHandle<Self::Resources, T> {
self.create_buffer_raw(num * mem::size_of::<T>(), usage).cast()
}
fn create_buffer_static_raw(&mut self, data: &[u8]) -> BufferHandle<Self::Resources, ()>;
fn create_buffer_static<T: Copy>(&mut self, data: &[T]) -> BufferHandle<Self::Resources, T> {
self.create_buffer_static_raw(as_byte_slice(data)).cast()
}
fn create_array_buffer(&mut self) -> Result<ArrayBufferHandle<Self::Resources>, ()>;
fn create_shader(&mut self, stage: shade::Stage, code: &[u8]) ->
Result<ShaderHandle<Self::Resources>, shade::CreateShaderError>;
fn create_program(&mut self, shaders: &[ShaderHandle<Self::Resources>], targets: Option<&[&str]>) -> Result<ProgramHandle<Self::Resources>, ()>;
fn create_frame_buffer(&mut self) -> FrameBufferHandle<Self::Resources>;
fn create_surface(&mut self, info: tex::SurfaceInfo) -> Result<SurfaceHandle<Self::Resources>, tex::SurfaceError>;
fn create_texture(&mut self, info: tex::TextureInfo) -> Result<TextureHandle<Self::Resources>, tex::TextureError>;
fn create_sampler(&mut self, info: tex::SamplerInfo) -> SamplerHandle<Self::Resources>;
fn get_main_frame_buffer(&self) -> FrameBufferHandle<Self::Resources>;
fn delete_buffer_raw(&mut self, buf: BufferHandle<Self::Resources, ()>);
fn delete_buffer<T>(&mut self, buf: BufferHandle<Self::Resources, T>) {
self.delete_buffer_raw(buf.cast());
}
fn delete_shader(&mut self, ShaderHandle<Self::Resources>);
fn delete_program(&mut self, ProgramHandle<Self::Resources>);
fn delete_surface(&mut self, SurfaceHandle<Self::Resources>);
fn delete_texture(&mut self, TextureHandle<Self::Resources>);
fn delete_sampler(&mut self, SamplerHandle<Self::Resources>);
fn update_buffer_raw(&mut self, buf: BufferHandle<Self::Resources, ()>, data: &[u8],
offset_bytes: usize);
fn update_buffer<T: Copy>(&mut self, buf: BufferHandle<Self::Resources, 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<Self::Resources, ()>, access: MapAccess) -> Self::Mapper;
fn unmap_buffer_raw(&mut self, map: Self::Mapper);
fn map_buffer_readable<T: Copy>(&mut self, buf: BufferHandle<Self::Resources, T>) -> ReadableMapping<T, Self>;
fn map_buffer_writable<T: Copy>(&mut self, buf: BufferHandle<Self::Resources, T>) -> WritableMapping<T, Self>;
fn map_buffer_rw<T: Copy>(&mut self, buf: BufferHandle<Self::Resources, T>) -> RWMapping<T, Self>;
fn update_texture_raw(&mut self, tex: &TextureHandle<Self::Resources>, img: &tex::ImageInfo,
data: &[u8]) -> Result<(), tex::TextureError>;
fn update_texture<T: Copy>(&mut self, tex: &TextureHandle<Self::Resources>,
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<Self::Resources>);
}
pub trait HandleFactory {
fn make_handle<T, I>(&self, value: T, info: I) -> Handle<T, I> {
Handle(value, info)
}
}
impl HandleFactory for () {}
impl<D: Device> HandleFactory for D {}
#[allow(missing_docs)]
pub trait MapFactory {
type RawMapping: RawMapping;
fn map_readable<T: Copy>(&mut self, Self::RawMapping, usize)
-> ReadableMapping<T, Self>;
fn map_writable<T: Copy>(&mut self, Self::RawMapping, usize)
-> WritableMapping<T, Self>;
fn map_read_write<T: Copy>(&mut self, Self::RawMapping, usize)
-> RWMapping<T, Self>;
}
impl<D: Device> MapFactory for D {
type RawMapping = D::Mapper;
fn map_readable<T: Copy>(&mut self, map: <Self as MapFactory>::RawMapping,
length: usize) -> ReadableMapping<T, Self> {
ReadableMapping {
raw: map,
len: length,
device: self,
phantom_t: PhantomData,
}
}
fn map_writable<T: Copy>(&mut self, map: <Self as MapFactory>::RawMapping,
length: usize) -> WritableMapping<T, Self> {
WritableMapping {
raw: map,
len: length,
device: self,
phantom_t: PhantomData,
}
}
fn map_read_write<T: Copy>(&mut self, map: <Self as MapFactory>::RawMapping,
length: usize) -> RWMapping<T, Self> {
RWMapping {
raw: map,
len: length,
device: self,
phantom_t: PhantomData,
}
}
}
#[cfg(test)]
mod test {
use std::mem;
use std::marker::PhantomData;
use super::{BufferHandle, Handle};
use super::{BufferInfo, BufferUsage};
fn mock_buffer<T>(len: usize) -> BufferHandle<(), T> {
BufferHandle {
raw: Handle(
(),
BufferInfo {
usage: BufferUsage::Static,
size: mem::size_of::<T>() * len,
},
),
phantom_t: PhantomData,
}
}
#[test]
fn test_buffer_len() {
assert_eq!(mock_buffer::<u8>(8).len(), 8);
assert_eq!(mock_buffer::<u16>(8).len(), 8);
}
#[test]
#[should_fail]
fn test_buffer_zero_len() {
let _ = mock_buffer::<()>(0).len();
}
}