Draft triangle
pipeline in iced_glow
This commit is contained in:
parent
d54f17c6aa
commit
60dcfc354e
@ -5,6 +5,7 @@
|
||||
#![forbid(rust_2018_idioms)]
|
||||
|
||||
mod backend;
|
||||
mod program;
|
||||
mod quad;
|
||||
mod text;
|
||||
mod triangle;
|
||||
|
39
glow/src/program.rs
Normal file
39
glow/src/program.rs
Normal file
@ -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
|
||||
}
|
@ -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,
|
||||
|
8
glow/src/shader/triangle.frag
Normal file
8
glow/src/shader/triangle.frag
Normal file
@ -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;
|
||||
}
|
13
glow/src/shader/triangle.vert
Normal file
13
glow/src/shader/triangle.vert
Normal file
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user