diff options
author | 2020-05-21 19:07:33 +0200 | |
---|---|---|
committer | 2020-05-21 19:07:33 +0200 | |
commit | 60dcfc354e844757d2291bf44cb21c624bc270c2 (patch) | |
tree | cc1ee2d923e8deb79c968dc96a918ec086b7dcf7 /glow/src/triangle.rs | |
parent | d54f17c6aa1cc90d97c63781e7d06af1b919ef0c (diff) | |
download | iced-60dcfc354e844757d2291bf44cb21c624bc270c2.tar.gz iced-60dcfc354e844757d2291bf44cb21c624bc270c2.tar.bz2 iced-60dcfc354e844757d2291bf44cb21c624bc270c2.zip |
Draft `triangle` pipeline in `iced_glow`
Diffstat (limited to 'glow/src/triangle.rs')
-rw-r--r-- | glow/src/triangle.rs | 251 |
1 files changed, 238 insertions, 13 deletions
diff --git a/glow/src/triangle.rs b/glow/src/triangle.rs index 5836f0cf..3f4aaa1b 100644 --- a/glow/src/triangle.rs +++ b/glow/src/triangle.rs @@ -1,22 +1,106 @@ //! Draw meshes of triangles. -use crate::{settings, Transformation}; +use crate::program; +use crate::settings; +use crate::Transformation; +use glow::HasContext; use iced_graphics::layer; +use std::marker::PhantomData; -pub use iced_graphics::triangle::Mesh2D; +pub use iced_graphics::triangle::{Mesh2D, Vertex2D}; -const UNIFORM_BUFFER_SIZE: usize = 100; const VERTEX_BUFFER_SIZE: usize = 10_000; const INDEX_BUFFER_SIZE: usize = 10_000; #[derive(Debug)] -pub(crate) struct Pipeline {} +pub(crate) struct Pipeline { + program: <glow::Context as HasContext>::Program, + vertex_array: <glow::Context as HasContext>::VertexArray, + vertices: Buffer<Vertex2D>, + indices: Buffer<u32>, + current_transform: Transformation, +} impl Pipeline { pub fn new( gl: &glow::Context, antialiasing: Option<settings::Antialiasing>, ) -> Pipeline { - Pipeline {} + let program = unsafe { + program::create( + gl, + &[ + (glow::VERTEX_SHADER, include_str!("shader/triangle.vert")), + ( + glow::FRAGMENT_SHADER, + include_str!("shader/triangle.frag"), + ), + ], + ) + }; + + unsafe { + gl.use_program(Some(program)); + + gl.uniform_matrix_4_f32_slice( + Some(0), + false, + &Transformation::identity().into(), + ); + + gl.use_program(None); + } + + let vertex_array = + unsafe { gl.create_vertex_array().expect("Create vertex array") }; + + unsafe { + gl.bind_vertex_array(Some(vertex_array)); + } + + let vertices = unsafe { + Buffer::new( + gl, + glow::ARRAY_BUFFER, + glow::DYNAMIC_DRAW, + VERTEX_BUFFER_SIZE, + ) + }; + + let indices = unsafe { + Buffer::new( + gl, + glow::ELEMENT_ARRAY_BUFFER, + glow::DYNAMIC_DRAW, + INDEX_BUFFER_SIZE, + ) + }; + + unsafe { + let stride = std::mem::size_of::<Vertex2D>() as i32; + + gl.enable_vertex_attrib_array(0); + gl.vertex_attrib_pointer_f32(0, 2, glow::FLOAT, false, stride, 0); + + gl.enable_vertex_attrib_array(1); + gl.vertex_attrib_pointer_f32( + 1, + 4, + glow::FLOAT, + false, + stride, + 4 * 2, + ); + + gl.bind_vertex_array(None); + } + + Pipeline { + program, + vertex_array, + vertices, + indices, + current_transform: Transformation::identity(), + } } pub fn draw( @@ -28,6 +112,106 @@ impl Pipeline { scale_factor: f32, meshes: &[layer::Mesh<'_>], ) { + unsafe { + gl.enable(glow::SCISSOR_TEST); + gl.use_program(Some(self.program)); + gl.bind_vertex_array(Some(self.vertex_array)); + } + + // This looks a bit crazy, but we are just counting how many vertices + // and indices we will need to handle. + // TODO: Improve readability + let (total_vertices, total_indices) = meshes + .iter() + .map(|layer::Mesh { buffers, .. }| { + (buffers.vertices.len(), buffers.indices.len()) + }) + .fold((0, 0), |(total_v, total_i), (v, i)| { + (total_v + v, total_i + i) + }); + + // Then we ensure the current buffers are big enough, resizing if + // necessary + unsafe { + self.vertices.bind(gl, total_vertices); + self.indices.bind(gl, total_indices); + } + + // We upload all the vertices and indices upfront + let mut last_vertex = 0; + let mut last_index = 0; + + for layer::Mesh { buffers, .. } in meshes { + unsafe { + gl.buffer_sub_data_u8_slice( + glow::ARRAY_BUFFER, + (last_vertex * std::mem::size_of::<Vertex2D>()) as i32, + bytemuck::cast_slice(&buffers.vertices), + ); + + gl.buffer_sub_data_u8_slice( + glow::ELEMENT_ARRAY_BUFFER, + (last_index * std::mem::size_of::<u32>()) as i32, + bytemuck::cast_slice(&buffers.indices), + ); + + last_vertex += buffers.vertices.len(); + last_index += buffers.indices.len(); + } + } + + // Then we draw each mesh using offsets + let mut last_vertex = 0; + let mut last_index = 0; + + for layer::Mesh { + buffers, + origin, + clip_bounds, + } in meshes + { + let transform = + transformation * Transformation::translate(origin.x, origin.y); + + let clip_bounds = (*clip_bounds * scale_factor).round(); + + unsafe { + if self.current_transform != transform { + gl.uniform_matrix_4_f32_slice( + Some(0), + false, + &transform.into(), + ); + + self.current_transform = transform; + } + + gl.scissor( + clip_bounds.x as i32, + (target_height - (clip_bounds.y + clip_bounds.height)) + as i32, + clip_bounds.width as i32, + clip_bounds.height as i32, + ); + + gl.draw_elements_base_vertex( + glow::TRIANGLES, + buffers.indices.len() as i32, + glow::UNSIGNED_INT, + (last_index * std::mem::size_of::<u32>()) as i32, + last_vertex as i32, + ); + + last_vertex += buffers.vertices.len(); + last_index += buffers.indices.len(); + } + } + + unsafe { + gl.bind_vertex_array(None); + gl.use_program(None); + gl.disable(glow::SCISSOR_TEST); + } } } @@ -35,18 +219,15 @@ impl Pipeline { #[derive(Debug, Clone, Copy)] struct Uniforms { transform: [f32; 16], - // We need to align this to 256 bytes to please `wgpu`... - // TODO: Be smarter and stop wasting memory! - _padding_a: [f32; 32], - _padding_b: [f32; 16], } +unsafe impl bytemuck::Zeroable for Uniforms {} +unsafe impl bytemuck::Pod for Uniforms {} + impl Default for Uniforms { fn default() -> Self { Self { transform: *Transformation::identity().as_ref(), - _padding_a: [0.0; 32], - _padding_b: [0.0; 16], } } } @@ -55,8 +236,52 @@ impl From<Transformation> for Uniforms { fn from(transformation: Transformation) -> Uniforms { Self { transform: transformation.into(), - _padding_a: [0.0; 32], - _padding_b: [0.0; 16], + } + } +} + +#[derive(Debug)] +struct Buffer<T> { + raw: <glow::Context as HasContext>::Buffer, + target: u32, + usage: u32, + size: usize, + phantom: PhantomData<T>, +} + +impl<T> Buffer<T> { + pub unsafe fn new( + gl: &glow::Context, + target: u32, + usage: u32, + size: usize, + ) -> Self { + let raw = gl.create_buffer().expect("Create buffer"); + + let mut buffer = Buffer { + raw, + target, + usage, + size: 0, + phantom: PhantomData, + }; + + buffer.bind(gl, size); + + buffer + } + + pub unsafe fn bind(&mut self, gl: &glow::Context, size: usize) { + gl.bind_buffer(self.target, Some(self.raw)); + + if self.size < size { + gl.buffer_data_size( + self.target, + (size * std::mem::size_of::<T>()) as i32, + self.usage, + ); + + self.size = size; } } } |