summaryrefslogtreecommitdiffstats
path: root/glow
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2020-05-21 19:07:33 +0200
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2020-05-21 19:07:33 +0200
commit60dcfc354e844757d2291bf44cb21c624bc270c2 (patch)
treecc1ee2d923e8deb79c968dc96a918ec086b7dcf7 /glow
parentd54f17c6aa1cc90d97c63781e7d06af1b919ef0c (diff)
downloadiced-60dcfc354e844757d2291bf44cb21c624bc270c2.tar.gz
iced-60dcfc354e844757d2291bf44cb21c624bc270c2.tar.bz2
iced-60dcfc354e844757d2291bf44cb21c624bc270c2.zip
Draft `triangle` pipeline in `iced_glow`
Diffstat (limited to 'glow')
-rw-r--r--glow/src/lib.rs1
-rw-r--r--glow/src/program.rs39
-rw-r--r--glow/src/quad.rs41
-rw-r--r--glow/src/shader/triangle.frag8
-rw-r--r--glow/src/shader/triangle.vert13
-rw-r--r--glow/src/triangle.rs251
6 files changed, 301 insertions, 52 deletions
diff --git a/glow/src/lib.rs b/glow/src/lib.rs
index d40ed0ae..a32c787e 100644
--- a/glow/src/lib.rs
+++ b/glow/src/lib.rs
@@ -5,6 +5,7 @@
#![forbid(rust_2018_idioms)]
mod backend;
+mod program;
mod quad;
mod text;
mod triangle;
diff --git a/glow/src/program.rs b/glow/src/program.rs
new file mode 100644
index 00000000..489a194f
--- /dev/null
+++ b/glow/src/program.rs
@@ -0,0 +1,39 @@
+use glow::HasContext;
+
+pub unsafe fn create(
+ gl: &glow::Context,
+ shader_sources: &[(u32, &str)],
+) -> <glow::Context as HasContext>::Program {
+ let program = gl.create_program().expect("Cannot create program");
+
+ let mut shaders = Vec::with_capacity(shader_sources.len());
+
+ for (shader_type, shader_source) in shader_sources.iter() {
+ let shader = gl
+ .create_shader(*shader_type)
+ .expect("Cannot create shader");
+
+ gl.shader_source(shader, shader_source);
+ gl.compile_shader(shader);
+
+ if !gl.get_shader_compile_status(shader) {
+ panic!(gl.get_shader_info_log(shader));
+ }
+
+ gl.attach_shader(program, shader);
+
+ shaders.push(shader);
+ }
+
+ gl.link_program(program);
+ if !gl.get_program_link_status(program) {
+ panic!(gl.get_program_info_log(program));
+ }
+
+ for shader in shaders {
+ gl.detach_shader(program, shader);
+ gl.delete_shader(shader);
+ }
+
+ program
+}
diff --git a/glow/src/quad.rs b/glow/src/quad.rs
index acac3219..3a051268 100644
--- a/glow/src/quad.rs
+++ b/glow/src/quad.rs
@@ -1,3 +1,4 @@
+use crate::program;
use crate::Transformation;
use glow::HasContext;
use iced_graphics::layer;
@@ -18,7 +19,7 @@ pub struct Pipeline {
impl Pipeline {
pub fn new(gl: &glow::Context) -> Pipeline {
let program = unsafe {
- create_program(
+ program::create(
gl,
&[
(glow::VERTEX_SHADER, include_str!("shader/quad.vert")),
@@ -138,44 +139,6 @@ impl Pipeline {
}
}
-unsafe fn create_program(
- gl: &glow::Context,
- shader_sources: &[(u32, &str)],
-) -> <glow::Context as HasContext>::Program {
- let program = gl.create_program().expect("Cannot create program");
-
- let mut shaders = Vec::with_capacity(shader_sources.len());
-
- for (shader_type, shader_source) in shader_sources.iter() {
- let shader = gl
- .create_shader(*shader_type)
- .expect("Cannot create shader");
-
- gl.shader_source(shader, shader_source);
- gl.compile_shader(shader);
-
- if !gl.get_shader_compile_status(shader) {
- panic!(gl.get_shader_info_log(shader));
- }
-
- gl.attach_shader(program, shader);
-
- shaders.push(shader);
- }
-
- gl.link_program(program);
- if !gl.get_program_link_status(program) {
- panic!(gl.get_program_info_log(program));
- }
-
- for shader in shaders {
- gl.detach_shader(program, shader);
- gl.delete_shader(shader);
- }
-
- program
-}
-
unsafe fn create_instance_buffer(
gl: &glow::Context,
size: usize,
diff --git a/glow/src/shader/triangle.frag b/glow/src/shader/triangle.frag
new file mode 100644
index 00000000..e39c45e7
--- /dev/null
+++ b/glow/src/shader/triangle.frag
@@ -0,0 +1,8 @@
+#version 450
+
+layout(location = 0) in vec4 i_Color;
+layout(location = 0) out vec4 o_Color;
+
+void main() {
+ o_Color = i_Color;
+}
diff --git a/glow/src/shader/triangle.vert b/glow/src/shader/triangle.vert
new file mode 100644
index 00000000..cfa4e995
--- /dev/null
+++ b/glow/src/shader/triangle.vert
@@ -0,0 +1,13 @@
+#version 450
+
+layout(location = 0) uniform mat4 u_Transform;
+
+layout(location = 0) in vec2 i_Position;
+layout(location = 1) in vec4 i_Color;
+
+layout(location = 0) out vec4 o_Color;
+
+void main() {
+ gl_Position = u_Transform * vec4(i_Position, 0.0, 1.0);
+ o_Color = i_Color;
+}
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;
}
}
}