#![feature(unsafe_destructor)]
#![deny(missing_docs)]
#![deny(missing_copy_implementations)]
#![allow(unstable)]
#[macro_use]
extern crate log;
#[macro_use]
extern crate bitflags;
extern crate libc;
pub use self::gl_device as back;
use std::mem;
use std::slice;
use std::ops::{Deref, DerefMut};
pub mod attrib;
pub mod draw;
pub mod shade;
pub mod state;
pub mod target;
pub mod tex;
#[path = "gl_device/lib.rs"] pub mod gl_device;
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 struct ReadableMapping<'a, T: Copy, D: 'a + Device> {
raw: back::RawMapping,
len: usize,
device: &'a mut D,
}
impl<'a, T: Copy, D: Device> Deref for ReadableMapping<'a, T, D> {
type Target = [T];
fn deref(&self) -> &[T] {
unsafe { mem::transmute(slice::from_raw_buf(&(self.raw.pointer as *const T), self.len)) }
}
}
#[unsafe_destructor]
impl<'a, T: Copy, D: Device> Drop for ReadableMapping<'a, T, D> {
fn drop(&mut self) {
self.device.unmap_buffer_raw(self.raw)
}
}
pub struct WritableMapping<'a, T: Copy, D: 'a + Device> {
raw: back::RawMapping,
len: usize,
device: &'a mut D,
}
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 { *(std::mem::transmute::<_, *mut T>(self.raw.pointer).offset(idx as isize)) = val }
}
}
#[unsafe_destructor]
impl<'a, T: Copy, D: Device> Drop for WritableMapping<'a, T, D> {
fn drop(&mut self) {
self.device.unmap_buffer_raw(self.raw)
}
}
pub struct RWMapping<'a, T: Copy, D: 'a + Device> {
raw: back::RawMapping,
len: usize,
device: &'a mut D,
}
impl<'a, T: Copy, D: Device> Deref for RWMapping<'a, T, D> {
type Target = [T];
fn deref(&self) -> &[T] {
unsafe { mem::transmute(slice::from_raw_buf(&(self.raw.pointer as *const T), self.len)) }
}
}
impl<'a, T: Copy, D: Device> DerefMut for RWMapping<'a, T, D> {
fn deref_mut(&mut self) -> &mut [T] {
unsafe { mem::transmute(slice::from_raw_mut_buf(&self.raw.pointer, self.len)) }
}
}
#[unsafe_destructor]
impl<'a, T: Copy, D: Device> Drop for RWMapping<'a, T, D> {
fn drop(&mut self) {
self.device.unmap_buffer_raw(self.raw)
}
}
#[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
}
pub fn get_info(&self) -> &I {
let Handle(_, ref info) = *self;
info
}
}
#[derive(Copy, Debug, PartialEq, Clone)]
pub struct BufferHandle<T> {
raw: RawBufferHandle,
}
impl<T> BufferHandle<T> {
pub fn from_raw(handle: RawBufferHandle) -> BufferHandle<T> {
BufferHandle {
raw: handle,
}
}
pub fn cast<U>(self) -> BufferHandle<U> {
BufferHandle::from_raw(self.raw)
}
pub fn get_name(&self) -> back::Buffer {
self.raw.get_name()
}
pub fn get_info(&self) -> &BufferInfo {
self.raw.get_info()
}
pub fn raw(&self) -> RawBufferHandle {
self.raw
}
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 = Handle<back::Buffer, BufferInfo>;
pub type ArrayBufferHandle = Handle<back::ArrayBuffer, ()>;
pub type ShaderHandle = Handle<back::Shader, shade::Stage>;
pub type ProgramHandle = Handle<back::Program, shade::ProgramInfo>;
pub type FrameBufferHandle = Handle<back::FrameBuffer, ()>;
pub type SurfaceHandle = Handle<back::Surface, tex::SurfaceInfo>;
pub type TextureHandle = Handle<back::Texture, tex::TextureInfo>;
pub type SamplerHandle = Handle<back::Sampler, tex::SamplerInfo>;
pub fn make_fake_buffer<T>() -> BufferHandle<T> {
let info = BufferInfo {
usage: BufferUsage::Static,
size: 0,
};
BufferHandle::from_raw(Handle(0, info))
}
pub fn get_main_frame_buffer() -> FrameBufferHandle {
Handle(0, ())
}
pub fn as_byte_slice<T>(slice: &[T]) -> &[u8] {
let len = mem::size_of::<T>() * slice.len();
let slice = std::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)]
#[derive(Copy, Debug)]
pub enum Command {
BindProgram(back::Program),
BindArrayBuffer(back::ArrayBuffer),
BindAttribute(AttributeSlot, back::Buffer, attrib::Format),
BindIndex(back::Buffer),
BindFrameBuffer(target::Access, back::FrameBuffer),
UnbindTarget(target::Access, target::Target),
BindTargetSurface(target::Access, target::Target, back::Surface),
BindTargetTexture(target::Access, target::Target, back::Texture,
target::Level, Option<target::Layer>),
BindUniformBlock(back::Program, UniformBufferSlot, UniformBlockIndex, back::Buffer),
BindUniform(shade::Location, shade::UniformValue),
BindTexture(TextureSlot, tex::TextureKind, back::Texture, Option<SamplerHandle>),
SetDrawColorBuffers(usize),
SetPrimitiveState(state::Primitive),
SetViewport(target::Rect),
SetMultiSampleState(Option<state::MultiSample>),
SetScissor(Option<target::Rect>),
SetDepthStencilState(Option<state::Depth>, Option<state::Stencil>, state::CullMode),
SetBlendState(Option<state::Blend>),
SetColorMask(state::ColorMask),
UpdateBuffer(back::Buffer, draw::DataPointer, usize),
UpdateTexture(tex::TextureKind, back::Texture, tex::ImageInfo, draw::DataPointer),
Clear(target::ClearData, target::Mask),
Draw(PrimitiveType, VertexCount, VertexCount, Option<(InstanceCount, VertexCount)>),
DrawIndexed(PrimitiveType, IndexType, VertexCount, VertexCount, VertexCount, Option<(InstanceCount, VertexCount)>),
Blit(target::Rect, target::Rect, target::Mask),
}
#[allow(missing_docs)]
pub trait Device {
type CommandBuffer: draw::CommandBuffer;
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<()>;
fn create_buffer<T>(&mut self, num: usize, usage: BufferUsage) -> BufferHandle<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> {
self.create_buffer_static_raw(as_byte_slice(data)).cast()
}
fn create_array_buffer(&mut self) -> Result<ArrayBufferHandle, ()>;
fn create_shader(&mut self, stage: shade::Stage, code: shade::ShaderSource) ->
Result<ShaderHandle, shade::CreateShaderError>;
fn shader_targets<'a>(&mut self, code: &'a ::shade::ShaderSource) -> Option<Vec<&'a str>>;
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;
fn delete_buffer_raw(&mut self, buf: BufferHandle<()>);
fn delete_buffer<T>(&mut self, buf: BufferHandle<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 update_buffer_raw(&mut self, buf: BufferHandle<()>, data: &[u8],
offset_bytes: usize);
fn update_buffer<T: Copy>(&mut self, buf: BufferHandle<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 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 update_texture_raw(&mut self, tex: &TextureHandle, img: &tex::ImageInfo,
data: &[u8]) -> Result<(), tex::TextureError>;
fn update_texture<T: Copy>(&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);
}
#[cfg(test)]
mod test {
use std::mem;
use super::{BufferHandle, Handle};
use super::{BufferInfo, BufferUsage};
fn mock_buffer<T>(usage: BufferUsage, len: usize) -> BufferHandle<T> {
BufferHandle {
raw: Handle(
0,
BufferInfo {
usage: usage,
size: mem::size_of::<T>() * len,
},
),
}
}
#[test]
fn test_buffer_len() {
assert_eq!(mock_buffer::<u8>(BufferUsage::Static, 8).len(), 8);
assert_eq!(mock_buffer::<u16>(BufferUsage::Static, 8).len(), 8);
}
#[test]
#[should_fail]
fn test_buffer_zero_len() {
let _ = mock_buffer::<()>(BufferUsage::Static, 0).len();
}
}