Skip to content

Commit

Permalink
Implement base indexes
Browse files Browse the repository at this point in the history
This removes `IndexCount`, as it will never be distinct from `VertexCount`,
and cleans up the `Slice` representation to factor out common fields with
names, because it was becoming unmanageable. Changes the `DrawCommand`
slightly to take a buffer handle when binding the index buffer, because the
size of the buffer is needed in the fallback for when base indexes are not
supported. This code path should be very rare.

First half of gfx-rs#355
  • Loading branch information
emberian committed Nov 7, 2014
1 parent 6af1e07 commit c04def3
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 57 deletions.
6 changes: 3 additions & 3 deletions src/device/draw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ pub trait CommandBuffer {
fn bind_program(&mut self, back::Program);
fn bind_array_buffer(&mut self, back::ArrayBuffer);
fn bind_attribute(&mut self, ::AttributeSlot, back::Buffer, attrib::Format);
fn bind_index(&mut self, back::Buffer);
fn bind_index(&mut self, ::BufferHandle<()>);
fn bind_frame_buffer(&mut self, target::Access, back::FrameBuffer);
/// Unbind any surface from the specified target slot
fn unbind_target(&mut self, target::Access, target::Target);
Expand Down Expand Up @@ -113,8 +113,8 @@ pub trait CommandBuffer {
fn call_clear(&mut self, target::ClearData, target::Mask);
fn call_draw(&mut self, ::PrimitiveType, ::VertexCount, ::VertexCount,
Option<::InstanceCount>);
fn call_draw_indexed(&mut self, ::PrimitiveType, ::IndexType, ::IndexCount,
::IndexCount, Option<::InstanceCount>);
fn call_draw_indexed(&mut self, ::PrimitiveType, ::IndexType, ::VertexCount,
::VertexCount, ::VertexCount, Option<::InstanceCount>);
fn call_blit(&mut self, target::Rect, target::Rect, target::Mask);
}

Expand Down
7 changes: 3 additions & 4 deletions src/device/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ pub mod tex;

/// Draw vertex count.
pub type VertexCount = u32;
/// Draw index count.
pub type IndexCount = u32;
/// Draw number of instances
pub type InstanceCount = u32;
/// Index of a uniform block.
Expand Down Expand Up @@ -256,6 +254,7 @@ pub struct Capabilities {
pub instance_call_supported: bool,
pub instance_rate_supported: bool,
pub render_targets_supported: bool,
pub vertex_base_supported: bool,
}

/// Describes what geometric primitives are created from vertex data.
Expand Down Expand Up @@ -322,7 +321,7 @@ pub enum Command {
BindProgram(back::Program),
BindArrayBuffer(back::ArrayBuffer),
BindAttribute(AttributeSlot, back::Buffer, attrib::Format),
BindIndex(back::Buffer),
BindIndex(back::Buffer, uint),
BindFrameBuffer(target::Access, back::FrameBuffer),
/// Unbind any surface from the specified target slot
UnbindTarget(target::Access, target::Target),
Expand All @@ -346,7 +345,7 @@ pub enum Command {
// drawing
Clear(target::ClearData, target::Mask),
Draw(PrimitiveType, VertexCount, VertexCount, Option<InstanceCount>),
DrawIndexed(PrimitiveType, IndexType, IndexCount, IndexCount, Option<InstanceCount>),
DrawIndexed(PrimitiveType, IndexType, VertexCount, VertexCount, VertexCount, Option<InstanceCount>),
Blit(target::Rect, target::Rect, target::Mask),
}

Expand Down
2 changes: 1 addition & 1 deletion src/gfx/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub use device::with_slice;
pub use device::{BufferHandle, BufferInfo, RawBufferHandle, ShaderHandle};
pub use device::{ProgramHandle, SurfaceHandle, TextureHandle};
pub use device::{BufferUsage, UsageStatic, UsageDynamic, UsageStream};
pub use device::{VertexCount, IndexCount, InstanceCount};
pub use device::{VertexCount, InstanceCount};
pub use device::{PrimitiveType, Point, Line, LineStrip,
TriangleList, TriangleStrip, TriangleFan};
pub use device::draw::CommandBuffer;
Expand Down
8 changes: 4 additions & 4 deletions src/gl_device/draw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ impl ::draw::CommandBuffer for GlCommandBuffer {
self.buf.push(::BindAttribute(slot, buf, format));
}

fn bind_index(&mut self, buf: super::Buffer) {
self.buf.push(::BindIndex(buf));
fn bind_index(&mut self, buf: ::BufferHandle<()>) {
self.buf.push(::BindIndex(buf.get_name(), buf.get_info().size));
}

fn bind_frame_buffer(&mut self, access: ::target::Access, fbo: super::FrameBuffer) {
Expand Down Expand Up @@ -135,9 +135,9 @@ impl ::draw::CommandBuffer for GlCommandBuffer {
}

fn call_draw_indexed(&mut self, ptype: ::PrimitiveType, itype: ::IndexType,
start: ::IndexCount, count: ::IndexCount,
start: ::VertexCount, count: ::VertexCount, base: ::VertexCount,
instances: Option<::InstanceCount>) {
self.buf.push(::DrawIndexed(ptype, itype, start, count, instances));
self.buf.push(::DrawIndexed(ptype, itype, start, count, base, instances));
}

fn call_blit(&mut self, s_rect: ::target::Rect, d_rect: ::target::Rect,
Expand Down
2 changes: 2 additions & 0 deletions src/gl_device/info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@ pub fn get(gl: &gl::Gl) -> (Info, Capabilities) {
|| info.is_extension_supported("GL_ARB_instanced_arrays"),
render_targets_supported: info.version >= Version::new(3, 0, None, "")
|| info.is_extension_supported("GL_ARB_framebuffer_object"),
vertex_base_supported: info.version >= Version::new(3, 2, None, "")
|| info.is_extension_supported("GL_ARB_draw_elements_base_vertex"),
};
(info, caps)
}
Expand Down
95 changes: 79 additions & 16 deletions src/gl_device/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ static RESET_CB: &'static [::Command] = &[
::BindProgram(0),
::BindArrayBuffer(0),
//BindAttribute
::BindIndex(0),
::BindIndex(0, 0),
::BindFrameBuffer(::target::Draw, 0),
::BindFrameBuffer(::target::Read, 0),
//UnbindTarget
Expand Down Expand Up @@ -133,6 +133,7 @@ pub struct GlDevice {
info: Info,
caps: ::Capabilities,
gl: gl::Gl,
current_ebo_len: gl::types::GLsizeiptr,
}

impl GlDevice {
Expand All @@ -155,6 +156,7 @@ impl GlDevice {
info: info,
caps: caps,
gl: gl,
current_ebo_len: 0,
}
}

Expand Down Expand Up @@ -217,6 +219,45 @@ impl GlDevice {
}
}

/// An incredibly wasteful subroutine for compatability with opengl < 3.2. Emulates
/// DrawElementsBaseVertex by making a new element array buffer and adding the base to them all
/// manually.
fn adjust_ebo_for_base(&mut self, base: ::VertexCount, cb: |&mut GlDevice|) {
if base == 0 {
cb(self);
return;
}

let mut data = Vec::from_elem(self.current_ebo_len as uint, 0);
unsafe { self.gl.GetBufferSubData(gl::ELEMENT_ARRAY_BUFFER, 0, self.current_ebo_len,
data.as_mut_ptr() as *mut _) };
for val in data.iter_mut() {
*val += 1;
}

let mut old_array_buf = 0;
let mut old_ebo = 0;
let len =self.current_ebo_len as uint;
unsafe {
self.gl.GetIntegerv(gl::ARRAY_BUFFER_BINDING, &mut old_array_buf);
self.gl.GetIntegerv(gl::ELEMENT_ARRAY_BUFFER_BINDING, &mut old_ebo);
};

let buf = self.create_buffer_internal();
self.init_buffer(buf, &::BufferInfo {
usage: ::UsageStatic,
size: len,
});
self.update_sub_buffer(buf, data.as_ptr(), len, 0);
unsafe { self.gl.BindBuffer(gl::ELEMENT_ARRAY_BUFFER, buf) };
cb(self);
unsafe {
self.gl.BindBuffer(gl::ELEMENT_ARRAY_BUFFER, old_ebo as Buffer);
self.gl.BindBuffer(gl::ARRAY_BUFFER, old_array_buf as Buffer);
self.gl.DeleteBuffers(1, &buf);
}
}

fn process(&mut self, cmd: &::Command, data_buf: &::draw::DataBuffer) {
match *cmd {
::Clear(ref data, mask) => {
Expand Down Expand Up @@ -307,7 +348,8 @@ impl GlDevice {
error!("Instanced arrays are not supported");
}
},
::BindIndex(buffer) => {
::BindIndex(buffer, len) => {
self.current_ebo_len = len as gl::types::GLsizeiptr;
unsafe { self.gl.BindBuffer(gl::ELEMENT_ARRAY_BUFFER, buffer) };
},
::BindFrameBuffer(access, frame_buffer) => {
Expand Down Expand Up @@ -428,32 +470,53 @@ impl GlDevice {
}},
}
},
::DrawIndexed(prim_type, index_type, start, count, instances) => {
::DrawIndexed(prim_type, index_type, start, count, base, instances) => {
let (offset, gl_index) = match index_type {
attrib::U8 => (start * 1u32, gl::UNSIGNED_BYTE),
attrib::U16 => (start * 2u32, gl::UNSIGNED_SHORT),
attrib::U32 => (start * 4u32, gl::UNSIGNED_INT),
};
match instances {
Some(num) if self.caps.instance_call_supported => unsafe {
self.gl.DrawElementsInstanced(
primitive_to_gl(prim_type),
count as gl::types::GLsizei,
gl_index,
offset as *const gl::types::GLvoid,
num as gl::types::GLsizei
);
if !self.caps.vertex_base_supported {
self.adjust_ebo_for_base(base, |this| this.gl.DrawElementsInstanced(
primitive_to_gl(prim_type),
count as gl::types::GLsizei,
gl_index,
offset as *const gl::types::GLvoid,
num as gl::types::GLsizei,
));
} else {
self.gl.DrawElementsInstancedBaseVertex(
primitive_to_gl(prim_type),
count as gl::types::GLsizei,
gl_index,
offset as *const gl::types::GLvoid,
num as gl::types::GLsizei,
base as gl::types::GLint,
);
}
},
Some(_) => {
error!("Instanced draw calls are not supported");
},
None => unsafe {
self.gl.DrawElements(
primitive_to_gl(prim_type),
count as gl::types::GLsizei,
gl_index,
offset as *const gl::types::GLvoid
);
if !self.caps.vertex_base_supported {
self.adjust_ebo_for_base(base, |this| this.gl.DrawElements(
primitive_to_gl(prim_type),
count as gl::types::GLsizei,
gl_index,
offset as *const gl::types::GLvoid,
));
} else {
self.gl.DrawElementsBaseVertex(
primitive_to_gl(prim_type),
count as gl::types::GLsizei,
gl_index,
offset as *const gl::types::GLvoid,
base as gl::types::GLint,
);
}
},
}
},
Expand Down
19 changes: 10 additions & 9 deletions src/render/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,28 +418,29 @@ impl<C: CommandBuffer> Renderer<C> {

fn bind_index<T>(&mut self, buf: device::BufferHandle<T>) {
if self.render_state.index != Some(buf.raw()) {
self.command_buffer.bind_index(buf.get_name());
self.command_buffer.bind_index(buf.cast());
self.render_state.index = Some(buf.raw());
}
}

fn draw_slice(&mut self, slice: &mesh::Slice,
instances: Option<device::InstanceCount>) {
match *slice {
mesh::VertexSlice(prim_type, start, end) => {
let mesh::Slice { start, end, prim_type, kind } = *slice;
match kind {
mesh::VertexSlice => {
self.command_buffer.call_draw(prim_type, start, end, instances);
},
mesh::IndexSlice8(prim_type, buf, start, end) => {
mesh::IndexSlice8(buf, base) => {
self.bind_index(buf);
self.command_buffer.call_draw_indexed(prim_type, attrib::U8, start, end, instances);
self.command_buffer.call_draw_indexed(prim_type, attrib::U8, start, end, base, instances);
},
mesh::IndexSlice16(prim_type, buf, start, end) => {
mesh::IndexSlice16(buf, base) => {
self.bind_index(buf);
self.command_buffer.call_draw_indexed(prim_type, attrib::U16, start, end, instances);
self.command_buffer.call_draw_indexed(prim_type, attrib::U16, start, end, base, instances);
},
mesh::IndexSlice32(prim_type, buf, start, end) => {
mesh::IndexSlice32(buf, base) => {
self.bind_index(buf);
self.command_buffer.call_draw_indexed(prim_type, attrib::U32, start, end, instances);
self.command_buffer.call_draw_indexed(prim_type, attrib::U32, start, end, base, instances);
},
}
}
Expand Down
Loading

0 comments on commit c04def3

Please sign in to comment.