use super::framebuffer::*;
use super::texture::*;
use super::pipeline::*;
use super::buffer::*;
use super::raw::*;
use vertex_array_object::*;
use compute_program::ComputeProgram;
use std;
use glutin;
mod errors {
error_chain! {
errors {
}
}
}
use self::errors::*;
#[derive(Copy, Clone)]
pub struct BufferObjectTargetLocation<'a> {
pub target: BufferBaseTarget,
pub index: BlockIndex,
pub buffer: &'a Buffer,
}
impl<'a> std::fmt::Debug for BufferObjectTargetLocation<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"BufferObjectTargetLocation {{ target: {:?}, index: {:?}, buffer id: {:?} }}",
self.target,
self.index,
self.buffer.get_id()
)
}
}
pub struct Renderer<'a, C: glutin::GlContext + 'a> {
context: &'a C,
state: FramebufferState,
vertex_array_object: VertexArrayObjectId,
default_framebuffer: DefaultFramebuffer,
}
impl<'a, C: glutin::GlContext> Renderer<'a, C> {
pub fn new(context: &'a C) -> Result<Renderer<'a, C>> {
unsafe {
context
.make_current()
.chain_err(|| "Unable to make Renderer context current")?;
}
gl::load_with(|symbol| context.get_proc_address(symbol) as *const _);
let vao;
unsafe {
vao = create_vertex_array();
bind_vertex_array(vao);
}
Ok(Renderer {
context: context,
state: FramebufferState::default(),
vertex_array_object: vao,
default_framebuffer: DefaultFramebuffer::new(),
})
}
pub fn bind_default_framebuffer(&mut self) {
self.default_framebuffer.bind();
self.state.sync(&self.default_framebuffer.state());
}
pub fn bind_framebuffer(&mut self, framebuffer: &GeneralFramebuffer) {
framebuffer.bind();
self.state.sync(&framebuffer.state());
}
pub fn clear_default_framebuffer(&mut self, buffers: ClearBuffers) -> () {
self.bind_default_framebuffer();
unsafe {
clear(buffers);
}
}
pub fn clear_framebuffer(
&mut self,
framebuffer: &GeneralFramebuffer,
buffers: ClearBuffers,
) -> () {
self.bind_framebuffer(framebuffer);
unsafe {
clear(buffers);
}
}
pub fn multi_draw_arrays_indirect(
&mut self,
framebuffer: &FramebufferRenderTarget,
buffers: &[BufferObjectTargetLocation],
textures: &[&Texture],
pipeline: &Pipeline,
mode: DrawMode,
draw_commands_buffer: (&Buffer, usize),
clear_buffers: ClearBuffers,
) -> Result<()> {
match *framebuffer {
FramebufferRenderTarget::Default => self.bind_default_framebuffer(),
FramebufferRenderTarget::General(framebuffer, attachments) => {
self.bind_framebuffer(framebuffer);
framebuffer
.attach_textures(attachments)
.chain_err(|| "Could not attach textures")?;
}
}
if let &FramebufferRenderTarget::General(fbo, attachments) = framebuffer {
fbo.attach_textures(attachments)
.chain_err(|| "Could not attach textures")?;
};
let res_textures: Vec<ResidentTexture> = textures
.iter()
.map(|t| t.make_resident_texture())
.collect::<_>();
unsafe {
if clear_buffers != ClearBuffers::None {
clear(clear_buffers);
}
}
pipeline.bind().chain_err(|| "Could not bind pipeline")?;
for buffer_target in buffers {
unsafe {
bind_buffer_base(
buffer_target.target,
buffer_target.index,
buffer_target.buffer.get_id(),
).chain_err(
|| format!("Unable to bind buffer {:?}", buffer_target),
)?;
}
}
unsafe {
bind_buffer(
BindBufferTarget::DrawIndirectBuffer,
draw_commands_buffer.0.get_id(),
).chain_err(|| "Could not bind draw indirect buffer")?;
multi_draw_arrays_indirect(mode.into(), draw_commands_buffer.1)
.chain_err(|| "Could not draw")?;
}
Ok(())
}
pub fn multi_draw_elements_indirect(
&mut self,
framebuffer: &FramebufferRenderTarget,
buffers: &[BufferObjectTargetLocation],
textures: &[&Texture],
pipeline: &Pipeline,
mode: DrawMode,
draw_commands_buffer: (&Buffer, usize),
clear_buffers: ClearBuffers,
) -> Result<()> {
match *framebuffer {
FramebufferRenderTarget::Default => self.bind_default_framebuffer(),
FramebufferRenderTarget::General(framebuffer, attachments) => {
self.bind_framebuffer(framebuffer);
framebuffer
.attach_textures(attachments)
.chain_err(|| "Could not attach textures")?;
}
}
let res_textures: Vec<ResidentTexture> = textures
.iter()
.map(|t| t.make_resident_texture())
.collect::<_>();
unsafe {
if clear_buffers != ClearBuffers::None {
clear(clear_buffers);
}
}
pipeline.bind().chain_err(|| "Could not bind pipeline")?;
for buffer_target in buffers {
unsafe {
bind_buffer_base(
buffer_target.target,
buffer_target.index,
buffer_target.buffer.get_id(),
).chain_err(
|| format!("Unable to bind buffer {:?}", buffer_target),
)?;
}
}
unsafe {
bind_buffer(
BindBufferTarget::DrawIndirectBuffer,
draw_commands_buffer.0.get_id(),
).chain_err(|| "Could not bind draw indirect buffer")?;
multi_draw_elements_indirect(mode.into(), draw_commands_buffer.1)
.chain_err(|| "Could not draw")?;
}
Ok(())
}
pub fn draw_arrays(
&mut self,
framebuffer: &FramebufferRenderTarget,
buffers: &[BufferObjectTargetLocation],
textures: &[&Texture],
pipeline: &Pipeline,
mode: DrawMode,
first: usize,
count: usize,
clear_buffers: ClearBuffers,
) -> Result<()> {
match *framebuffer {
FramebufferRenderTarget::Default => self.bind_default_framebuffer(),
FramebufferRenderTarget::General(framebuffer, attachments) => {
self.bind_framebuffer(framebuffer);
framebuffer
.attach_textures(attachments)
.chain_err(|| "Could not attach textures")?;
}
}
let res_textures: Vec<ResidentTexture> = textures
.iter()
.map(|t| t.make_resident_texture())
.collect::<_>();
unsafe {
if clear_buffers != ClearBuffers::None {
clear(clear_buffers);
}
}
pipeline.bind().chain_err(|| "Could not bind pipeline")?;
for buffer_target in buffers {
unsafe {
bind_buffer_base(
buffer_target.target,
buffer_target.index,
buffer_target.buffer.get_id(),
).chain_err(
|| format!("Unable to bind buffer {:?}", buffer_target),
)?;
}
}
unsafe {
draw_arrays(mode, first, count).chain_err(|| "Could not draw")?;
}
Ok(())
}
pub fn dispatch_compute(
&mut self,
buffers: &[BufferObjectTargetLocation],
textures: &[&Texture],
program: &ComputeProgram,
command: DispatchCommand,
) -> Result<()> {
let res_textures: Vec<ResidentTexture> = textures
.iter()
.map(|t| t.make_resident_texture())
.collect::<_>();
program.bind().chain_err(|| "Unable to bind program")?;
for buffer_target in buffers {
unsafe {
bind_buffer_base(
buffer_target.target,
buffer_target.index,
buffer_target.buffer.get_id(),
).chain_err(|| "Unable to bind buffer")?;
}
}
unsafe {
dispatch_compute(
command.num_groups_x,
command.num_groups_y,
command.num_groups_z,
).chain_err(|| "Error during command dispatch")?;
}
Ok(())
}
pub fn dispatch_compute_indirect<T: Buffer>(
&mut self,
buffers: &[BufferObjectTargetLocation],
textures: &[&Texture],
program: &ComputeProgram,
command_buffer: &T,
command_offset: usize,
) -> Result<()> {
let res_textures: Vec<ResidentTexture> = textures
.iter()
.map(|t| t.make_resident_texture())
.collect::<_>();
program.bind().chain_err(|| "Unable to bind program")?;
for buffer_target in buffers {
unsafe {
bind_buffer_base(
buffer_target.target,
buffer_target.index,
buffer_target.buffer.get_id(),
).chain_err(|| "Unable to bind buffer")?;
}
}
unsafe {
bind_buffer(
BindBufferTarget::DispatchIndirectBuffer,
command_buffer.get_id(),
).chain_err(|| "Could not bind dispatch indirect buffer")?;
dispatch_compute_indirect(command_offset).chain_err(
|| "Error during command dispatch",
)?;
}
Ok(())
}
pub fn default_framebuffer(&self) -> &DefaultFramebuffer {
&self.default_framebuffer
}
pub fn mut_default_framebuffer(&mut self) -> &mut DefaultFramebuffer {
&mut self.default_framebuffer
}
pub fn make_current(&mut self) -> Result<()> {
unsafe {
self.context
.make_current()
.chain_err(|| "Unable to make Renderer context current")?;
}
Ok(())
}
pub fn swap_buffers(&mut self) -> Result<()> {
self.context
.swap_buffers()
.chain_err(|| "Unable to swap buffers")?;
Ok(())
}
pub fn set_viewport(&mut self, viewport: Viewport) {
self.default_framebuffer.set_viewport(viewport);
}
pub fn set_enable(&mut self, option: EnableOption) {
self.default_framebuffer.set_enable(option);
}
pub fn set_disable(&mut self, option: EnableOption) {
self.default_framebuffer.set_disable(option);
}
pub fn set_stencil_test(&mut self, face: Face, stencil_test: StencilTest) {
self.default_framebuffer
.set_stencil_test(face, stencil_test);
}
pub fn set_depth_test(&mut self, depth_test: DepthTest) {
self.default_framebuffer.set_depth_test(depth_test);
}
pub fn set_depth_mask(&mut self, depth_mask: DepthMask) {
self.default_framebuffer.set_depth_mask(depth_mask);
}
pub fn set_depth_range(&mut self, depth_range: DepthRange) {
self.default_framebuffer.set_depth_range(depth_range);
}
pub fn set_logic_operation(&mut self, logic_operation: LogicOperation) {
self.default_framebuffer
.set_logic_operation(logic_operation);
}
pub fn set_blending_equation(
&mut self,
blending_equation_rgb: BlendingEquation,
blending_equation_alpha: BlendingEquation,
) {
self.default_framebuffer
.set_blending_equation(blending_equation_rgb, blending_equation_alpha);
}
pub fn set_linear_blending_factors(
&mut self,
source_rgb: LinearBlendingFactor,
destination_rgb: LinearBlendingFactor,
source_alpha: LinearBlendingFactor,
destination_alpha: LinearBlendingFactor,
) {
self.default_framebuffer.set_linear_blending_factors(
source_rgb,
destination_rgb,
source_alpha,
destination_alpha,
);
}
pub fn set_face_orientation(&mut self, face_orientation: FaceOrientation) {
self.default_framebuffer
.set_face_orientation(face_orientation);
}
pub fn set_cull_face(&mut self, cull_face: Face) {
self.default_framebuffer.set_cull_face(cull_face);
}
pub fn set_clear_color(&mut self, clear_color: ClearColor) {
self.default_framebuffer.set_clear_color(clear_color);
}
pub fn set_color_mask(&mut self, color_mask: [bool; 4]) {
self.default_framebuffer.set_color_mask(color_mask);
}
}
impl<'a, C: glutin::GlContext> Drop for Renderer<'a, C> {
fn drop(&mut self) {
unsafe {
delete_vertex_array(self.vertex_array_object);
}
}
}