summaryrefslogtreecommitdiffstats
path: root/glow
diff options
context:
space:
mode:
authorLibravatar Richard <richardsoncusto@gmail.com>2021-11-04 19:26:49 -0300
committerLibravatar Richard <richardsoncusto@gmail.com>2022-01-19 17:40:17 -0300
commit381052c50e8c3458a681ec4f2df6c74a40baf5d2 (patch)
treed669c6c02c7f3b4d9f1675648e075851e2f39b57 /glow
parent3c5ab3011772bf7dbdceafd00c0059dfac5aa40f (diff)
downloadiced-381052c50e8c3458a681ec4f2df6c74a40baf5d2.tar.gz
iced-381052c50e8c3458a681ec4f2df6c74a40baf5d2.tar.bz2
iced-381052c50e8c3458a681ec4f2df6c74a40baf5d2.zip
Split `quad::Pipeline` into `core` and `compatibility`
Diffstat (limited to 'glow')
-rw-r--r--glow/src/quad.rs234
-rw-r--r--glow/src/quad/compatibility.rs347
-rw-r--r--glow/src/quad/core.rs233
-rw-r--r--glow/src/shader/compatibility/quad.frag62
-rw-r--r--glow/src/shader/compatibility/quad.vert46
-rw-r--r--glow/src/shader/compatibility/triangle.frag8
-rw-r--r--glow/src/shader/compatibility/triangle.vert13
-rw-r--r--glow/src/shader/core/quad.frag (renamed from glow/src/shader/quad.frag)2
-rw-r--r--glow/src/shader/core/quad.vert (renamed from glow/src/shader/quad.vert)14
-rw-r--r--glow/src/shader/core/triangle.frag (renamed from glow/src/shader/triangle.frag)2
-rw-r--r--glow/src/shader/core/triangle.vert (renamed from glow/src/shader/triangle.vert)6
-rw-r--r--glow/src/triangle.rs7
12 files changed, 754 insertions, 220 deletions
diff --git a/glow/src/quad.rs b/glow/src/quad.rs
index a8fbb9e5..5438024c 100644
--- a/glow/src/quad.rs
+++ b/glow/src/quad.rs
@@ -1,77 +1,24 @@
-use crate::program;
+mod compatibility;
+mod core;
+
use crate::Transformation;
use glow::HasContext;
use iced_graphics::layer;
use iced_native::Rectangle;
-const MAX_INSTANCES: usize = 100_000;
-
#[derive(Debug)]
-pub struct Pipeline {
- program: <glow::Context as HasContext>::Program,
- vertex_array: <glow::Context as HasContext>::VertexArray,
- instances: <glow::Context as HasContext>::Buffer,
- transform_location: <glow::Context as HasContext>::UniformLocation,
- scale_location: <glow::Context as HasContext>::UniformLocation,
- screen_height_location: <glow::Context as HasContext>::UniformLocation,
- current_transform: Transformation,
- current_scale: f32,
- current_target_height: u32,
+pub enum Pipeline {
+ Core(core::Pipeline),
+ Compatibility(compatibility::Pipeline),
}
impl Pipeline {
pub fn new(gl: &glow::Context) -> Pipeline {
- let program = unsafe {
- program::create(
- gl,
- &[
- (glow::VERTEX_SHADER, include_str!("shader/quad.vert")),
- (glow::FRAGMENT_SHADER, include_str!("shader/quad.frag")),
- ],
- )
- };
-
- let transform_location =
- unsafe { gl.get_uniform_location(program, "u_Transform") }
- .expect("Get transform location");
-
- let scale_location =
- unsafe { gl.get_uniform_location(program, "u_Scale") }
- .expect("Get scale location");
-
- let screen_height_location =
- unsafe { gl.get_uniform_location(program, "u_ScreenHeight") }
- .expect("Get target height location");
-
- unsafe {
- gl.use_program(Some(program));
-
- let matrix: [f32; 16] = Transformation::identity().into();
- gl.uniform_matrix_4_f32_slice(
- Some(&transform_location),
- false,
- &matrix,
- );
-
- gl.uniform_1_f32(Some(&scale_location), 1.0);
- gl.uniform_1_f32(Some(&screen_height_location), 0.0);
-
- gl.use_program(None);
- }
-
- let (vertex_array, instances) =
- unsafe { create_instance_buffer(gl, MAX_INSTANCES) };
-
- Pipeline {
- program,
- vertex_array,
- instances,
- transform_location,
- scale_location,
- screen_height_location,
- current_transform: Transformation::identity(),
- current_scale: 1.0,
- current_target_height: 0,
+ let version = gl.version();
+ if version.is_embedded || version.major == 2 {
+ Pipeline::Compatibility(compatibility::Pipeline::new(gl))
+ } else {
+ Pipeline::Core(core::Pipeline::new(gl))
}
}
@@ -84,152 +31,27 @@ impl Pipeline {
scale: f32,
bounds: Rectangle<u32>,
) {
- unsafe {
- gl.enable(glow::SCISSOR_TEST);
- gl.scissor(
- bounds.x as i32,
- (target_height - (bounds.y + bounds.height)) as i32,
- bounds.width as i32,
- bounds.height as i32,
- );
-
- gl.use_program(Some(self.program));
- gl.bind_vertex_array(Some(self.vertex_array));
- gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.instances));
- }
-
- if transformation != self.current_transform {
- unsafe {
- let matrix: [f32; 16] = transformation.into();
- gl.uniform_matrix_4_f32_slice(
- Some(&self.transform_location),
- false,
- &matrix,
- );
-
- self.current_transform = transformation;
- }
- }
-
- if scale != self.current_scale {
- unsafe {
- gl.uniform_1_f32(Some(&self.scale_location), scale);
- }
-
- self.current_scale = scale;
- }
-
- if target_height != self.current_target_height {
- unsafe {
- gl.uniform_1_f32(
- Some(&self.screen_height_location),
- target_height as f32,
+ match self {
+ Pipeline::Core(pipeline) => {
+ pipeline.draw(
+ gl,
+ target_height,
+ instances,
+ transformation,
+ scale,
+ bounds,
);
}
-
- self.current_target_height = target_height;
- }
-
- let mut i = 0;
- let total = instances.len();
-
- while i < total {
- let end = (i + MAX_INSTANCES).min(total);
- let amount = end - i;
-
- unsafe {
- gl.buffer_sub_data_u8_slice(
- glow::ARRAY_BUFFER,
- 0,
- bytemuck::cast_slice(&instances[i..end]),
- );
-
- gl.draw_arrays_instanced(
- glow::TRIANGLE_STRIP,
- 0,
- 4,
- amount as i32,
+ Pipeline::Compatibility(pipeline) => {
+ pipeline.draw(
+ gl,
+ target_height,
+ instances,
+ transformation,
+ scale,
+ bounds,
);
}
-
- i += MAX_INSTANCES;
- }
-
- unsafe {
- gl.bind_vertex_array(None);
- gl.use_program(None);
- gl.disable(glow::SCISSOR_TEST);
}
}
}
-
-unsafe fn create_instance_buffer(
- gl: &glow::Context,
- size: usize,
-) -> (
- <glow::Context as HasContext>::VertexArray,
- <glow::Context as HasContext>::Buffer,
-) {
- let vertex_array = gl.create_vertex_array().expect("Create vertex array");
- let buffer = gl.create_buffer().expect("Create instance buffer");
-
- gl.bind_vertex_array(Some(vertex_array));
- gl.bind_buffer(glow::ARRAY_BUFFER, Some(buffer));
- gl.buffer_data_size(
- glow::ARRAY_BUFFER,
- (size * std::mem::size_of::<layer::Quad>()) as i32,
- glow::DYNAMIC_DRAW,
- );
-
- let stride = std::mem::size_of::<layer::Quad>() as i32;
-
- gl.enable_vertex_attrib_array(0);
- gl.vertex_attrib_pointer_f32(0, 2, glow::FLOAT, false, stride, 0);
- gl.vertex_attrib_divisor(0, 1);
-
- gl.enable_vertex_attrib_array(1);
- gl.vertex_attrib_pointer_f32(1, 2, glow::FLOAT, false, stride, 4 * 2);
- gl.vertex_attrib_divisor(1, 1);
-
- gl.enable_vertex_attrib_array(2);
- gl.vertex_attrib_pointer_f32(2, 4, glow::FLOAT, false, stride, 4 * (2 + 2));
- gl.vertex_attrib_divisor(2, 1);
-
- gl.enable_vertex_attrib_array(3);
- gl.vertex_attrib_pointer_f32(
- 3,
- 4,
- glow::FLOAT,
- false,
- stride,
- 4 * (2 + 2 + 4),
- );
- gl.vertex_attrib_divisor(3, 1);
-
- gl.enable_vertex_attrib_array(4);
- gl.vertex_attrib_pointer_f32(
- 4,
- 1,
- glow::FLOAT,
- false,
- stride,
- 4 * (2 + 2 + 4 + 4),
- );
- gl.vertex_attrib_divisor(4, 1);
-
- gl.enable_vertex_attrib_array(5);
- gl.vertex_attrib_pointer_f32(
- 5,
- 1,
- glow::FLOAT,
- false,
- stride,
- 4 * (2 + 2 + 4 + 4 + 1),
- );
- gl.vertex_attrib_divisor(5, 1);
-
- gl.bind_vertex_array(None);
- gl.bind_buffer(glow::ARRAY_BUFFER, None);
-
- (vertex_array, buffer)
-}
diff --git a/glow/src/quad/compatibility.rs b/glow/src/quad/compatibility.rs
new file mode 100644
index 00000000..e083dcf1
--- /dev/null
+++ b/glow/src/quad/compatibility.rs
@@ -0,0 +1,347 @@
+use crate::program;
+use crate::Transformation;
+use glow::HasContext;
+use iced_graphics::layer;
+use iced_native::Rectangle;
+
+// Only change `MAX_QUADS`, otherwise you could cause problems
+// by splitting a triangle into different render passes.
+const MAX_QUADS: usize = 100_000;
+const MAX_VERTICES: usize = MAX_QUADS * 4;
+const MAX_INDICES: usize = MAX_QUADS * 6;
+
+#[derive(Debug)]
+pub struct Pipeline {
+ program: <glow::Context as HasContext>::Program,
+ vertex_array: <glow::Context as HasContext>::VertexArray,
+ vertex_buffer: <glow::Context as HasContext>::Buffer,
+ index_buffer: <glow::Context as HasContext>::Buffer,
+ transform_location: <glow::Context as HasContext>::UniformLocation,
+ scale_location: <glow::Context as HasContext>::UniformLocation,
+ screen_height_location: <glow::Context as HasContext>::UniformLocation,
+ current_transform: Transformation,
+ current_scale: f32,
+ current_target_height: u32,
+}
+
+impl Pipeline {
+ pub fn new(gl: &glow::Context) -> Pipeline {
+ let program = unsafe {
+ program::create(
+ gl,
+ &[
+ (
+ glow::VERTEX_SHADER,
+ include_str!("../shader/compatibility/quad.vert"),
+ ),
+ (
+ glow::FRAGMENT_SHADER,
+ include_str!("../shader/compatibility/quad.frag"),
+ ),
+ ],
+ )
+ };
+
+ let transform_location =
+ unsafe { gl.get_uniform_location(program, "u_Transform") }
+ .expect("Get transform location");
+
+ let scale_location =
+ unsafe { gl.get_uniform_location(program, "u_Scale") }
+ .expect("Get scale location");
+
+ let screen_height_location =
+ unsafe { gl.get_uniform_location(program, "u_ScreenHeight") }
+ .expect("Get target height location");
+
+ unsafe {
+ gl.use_program(Some(program));
+
+ let matrix: [f32; 16] = Transformation::identity().into();
+ gl.uniform_matrix_4_f32_slice(
+ Some(&transform_location),
+ false,
+ &matrix,
+ );
+
+ gl.uniform_1_f32(Some(&scale_location), 1.0);
+ gl.uniform_1_f32(Some(&screen_height_location), 0.0);
+
+ gl.use_program(None);
+ }
+
+ let (vertex_array, vertex_buffer, index_buffer) =
+ unsafe { create_buffers(gl, MAX_VERTICES) };
+
+ Pipeline {
+ program,
+ vertex_array,
+ vertex_buffer,
+ index_buffer,
+ transform_location,
+ scale_location,
+ screen_height_location,
+ current_transform: Transformation::identity(),
+ current_scale: 1.0,
+ current_target_height: 0,
+ }
+ }
+
+ pub fn draw(
+ &mut self,
+ gl: &glow::Context,
+ target_height: u32,
+ instances: &[layer::Quad],
+ transformation: Transformation,
+ scale: f32,
+ bounds: Rectangle<u32>,
+ ) {
+ // TODO: Remove this allocation (probably by changing the shader and removing the need of two `position`)
+ let vertices: Vec<Vertex> = instances
+ .iter()
+ .flat_map(|quad| Vertex::from_quad(quad))
+ .collect();
+
+ // TODO: Remove this allocation (or allocate only when needed)
+ let indices: Vec<i32> = (0..instances.len().min(MAX_QUADS) as i32)
+ .flat_map(|i| {
+ [
+ 0 + i * 4,
+ 1 + i * 4,
+ 2 + i * 4,
+ 2 + i * 4,
+ 1 + i * 4,
+ 3 + i * 4,
+ ]
+ })
+ .cycle()
+ .take(instances.len() * 6)
+ .collect();
+
+ unsafe {
+ gl.enable(glow::SCISSOR_TEST);
+ gl.scissor(
+ bounds.x as i32,
+ (target_height - (bounds.y + bounds.height)) as i32,
+ bounds.width as i32,
+ bounds.height as i32,
+ );
+
+ gl.use_program(Some(self.program));
+ gl.bind_vertex_array(Some(self.vertex_array));
+ gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.vertex_buffer));
+ gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(self.index_buffer));
+ }
+
+ if transformation != self.current_transform {
+ unsafe {
+ let matrix: [f32; 16] = transformation.into();
+ gl.uniform_matrix_4_f32_slice(
+ Some(&self.transform_location),
+ false,
+ &matrix,
+ );
+
+ self.current_transform = transformation;
+ }
+ }
+
+ if scale != self.current_scale {
+ unsafe {
+ gl.uniform_1_f32(Some(&self.scale_location), scale);
+ }
+
+ self.current_scale = scale;
+ }
+
+ if target_height != self.current_target_height {
+ unsafe {
+ gl.uniform_1_f32(
+ Some(&self.screen_height_location),
+ target_height as f32,
+ );
+ }
+
+ self.current_target_height = target_height;
+ }
+
+ let passes = vertices
+ .chunks(MAX_VERTICES)
+ .zip(indices.chunks(MAX_INDICES));
+
+ for (vertices, indices) in passes {
+ unsafe {
+ gl.buffer_sub_data_u8_slice(
+ glow::ARRAY_BUFFER,
+ 0,
+ bytemuck::cast_slice(&vertices),
+ );
+
+ gl.buffer_sub_data_u8_slice(
+ glow::ELEMENT_ARRAY_BUFFER,
+ 0,
+ bytemuck::cast_slice(&indices),
+ );
+
+ gl.draw_elements(
+ glow::TRIANGLES,
+ indices.len() as i32,
+ glow::UNSIGNED_INT,
+ 0,
+ );
+ }
+ }
+
+ unsafe {
+ gl.bind_vertex_array(None);
+ gl.use_program(None);
+ gl.disable(glow::SCISSOR_TEST);
+ }
+ }
+}
+
+unsafe fn create_buffers(
+ gl: &glow::Context,
+ size: usize,
+) -> (
+ <glow::Context as HasContext>::VertexArray,
+ <glow::Context as HasContext>::Buffer,
+ <glow::Context as HasContext>::Buffer,
+) {
+ let vertex_array = gl.create_vertex_array().expect("Create vertex array");
+ let vertex_buffer = gl.create_buffer().expect("Create vertex buffer");
+ let index_buffer = gl.create_buffer().expect("Create index buffer");
+
+ gl.bind_vertex_array(Some(vertex_array));
+
+ gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(index_buffer));
+ gl.buffer_data_size(
+ glow::ELEMENT_ARRAY_BUFFER,
+ 12 * size as i32,
+ glow::DYNAMIC_DRAW,
+ );
+
+ gl.bind_buffer(glow::ARRAY_BUFFER, Some(vertex_buffer));
+ gl.buffer_data_size(
+ glow::ARRAY_BUFFER,
+ (size * Vertex::SIZE) as i32,
+ glow::DYNAMIC_DRAW,
+ );
+
+ let stride = Vertex::SIZE 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, 2, glow::FLOAT, false, stride, 4 * 2);
+
+ gl.enable_vertex_attrib_array(2);
+ gl.vertex_attrib_pointer_f32(2, 4, glow::FLOAT, false, stride, 4 * (2 + 2));
+
+ gl.enable_vertex_attrib_array(3);
+ gl.vertex_attrib_pointer_f32(
+ 3,
+ 4,
+ glow::FLOAT,
+ false,
+ stride,
+ 4 * (2 + 2 + 4),
+ );
+
+ gl.enable_vertex_attrib_array(4);
+ gl.vertex_attrib_pointer_f32(
+ 4,
+ 1,
+ glow::FLOAT,
+ false,
+ stride,
+ 4 * (2 + 2 + 4 + 4),
+ );
+
+ gl.enable_vertex_attrib_array(5);
+ gl.vertex_attrib_pointer_f32(
+ 5,
+ 1,
+ glow::FLOAT,
+ false,
+ stride,
+ 4 * (2 + 2 + 4 + 4 + 1),
+ );
+
+ gl.enable_vertex_attrib_array(6);
+ gl.vertex_attrib_pointer_f32(
+ 6,
+ 2,
+ glow::FLOAT,
+ false,
+ stride,
+ 4 * (2 + 2 + 4 + 4 + 1 + 1),
+ );
+
+ gl.bind_vertex_array(None);
+ gl.bind_buffer(glow::ARRAY_BUFFER, None);
+ gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, None);
+
+ (vertex_array, vertex_buffer, index_buffer)
+}
+
+/// The vertex of a colored rectangle with a border.
+///
+/// This type can be directly uploaded to GPU memory.
+#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
+#[repr(C)]
+pub struct Vertex {
+ /// The position of the [`Vertex`].
+ pub position: [f32; 2],
+
+ /// The size of the [`Vertex`].
+ pub size: [f32; 2],
+
+ /// The color of the [`Vertex`], in __linear RGB__.
+ pub color: [f32; 4],
+
+ /// The border color of the [`Vertex`], in __linear RGB__.
+ pub border_color: [f32; 4],
+
+ /// The border radius of the [`Vertex`].
+ pub border_radius: f32,
+
+ /// The border width of the [`Vertex`].
+ pub border_width: f32,
+
+ /// The __quad__ position of the [`Vertex`].
+ pub q_position: [f32; 2],
+}
+
+impl Vertex {
+ const SIZE: usize = std::mem::size_of::<Self>();
+
+ fn from_quad(quad: &layer::Quad) -> [Vertex; 4] {
+ let base = Vertex {
+ position: quad.position,
+ size: quad.size,
+ color: quad.color,
+ border_color: quad.color,
+ border_radius: quad.border_radius,
+ border_width: quad.border_width,
+ q_position: [0.0, 0.0],
+ };
+
+ [
+ base,
+ Self {
+ q_position: [0.0, 1.0],
+ ..base
+ },
+ Self {
+ q_position: [1.0, 0.0],
+ ..base
+ },
+ Self {
+ q_position: [1.0, 1.0],
+ ..base
+ },
+ ]
+ }
+}
diff --git a/glow/src/quad/core.rs b/glow/src/quad/core.rs
new file mode 100644
index 00000000..c843e8c7
--- /dev/null
+++ b/glow/src/quad/core.rs
@@ -0,0 +1,233 @@
+use crate::program;
+use crate::Transformation;
+use glow::HasContext;
+use iced_graphics::layer;
+use iced_native::Rectangle;
+
+const MAX_INSTANCES: usize = 100_000;
+
+#[derive(Debug)]
+pub struct Pipeline {
+ program: <glow::Context as HasContext>::Program,
+ vertex_array: <glow::Context as HasContext>::VertexArray,
+ instances: <glow::Context as HasContext>::Buffer,
+ transform_location: <glow::Context as HasContext>::UniformLocation,
+ scale_location: <glow::Context as HasContext>::UniformLocation,
+ screen_height_location: <glow::Context as HasContext>::UniformLocation,
+ current_transform: Transformation,
+ current_scale: f32,
+ current_target_height: u32,
+}
+
+impl Pipeline {
+ pub fn new(gl: &glow::Context) -> Pipeline {
+ let program = unsafe {
+ program::create(
+ gl,
+ &[
+ (
+ glow::VERTEX_SHADER,
+ include_str!("../shader/core/quad.vert"),
+ ),
+ (
+ glow::FRAGMENT_SHADER,
+ include_str!("../shader/core/quad.frag"),
+ ),
+ ],
+ )
+ };
+
+ let transform_location =
+ unsafe { gl.get_uniform_location(program, "u_Transform") }
+ .expect("Get transform location");
+
+ let scale_location =
+ unsafe { gl.get_uniform_location(program, "u_Scale") }
+ .expect("Get scale location");
+
+ let screen_height_location =
+ unsafe { gl.get_uniform_location(program, "u_ScreenHeight") }
+ .expect("Get target height location");
+
+ unsafe {
+ gl.use_program(Some(program));
+
+ let matrix: [f32; 16] = Transformation::identity().into();
+ gl.uniform_matrix_4_f32_slice(
+ Some(&transform_location),
+ false,
+ &matrix,
+ );
+
+ gl.uniform_1_f32(Some(&scale_location), 1.0);
+ gl.uniform_1_f32(Some(&screen_height_location), 0.0);
+
+ gl.use_program(None);
+ }
+
+ let (vertex_array, instances) =
+ unsafe { create_instance_buffer(gl, MAX_INSTANCES) };
+
+ Pipeline {
+ program,
+ vertex_array,
+ instances,
+ transform_location,
+ scale_location,
+ screen_height_location,
+ current_transform: Transformation::identity(),
+ current_scale: 1.0,
+ current_target_height: 0,
+ }
+ }
+
+ pub fn draw(
+ &mut self,
+ gl: &glow::Context,
+ target_height: u32,
+ instances: &[layer::Quad],
+ transformation: Transformation,
+ scale: f32,
+ bounds: Rectangle<u32>,
+ ) {
+ unsafe {
+ gl.enable(glow::SCISSOR_TEST);
+ gl.scissor(
+ bounds.x as i32,
+ (target_height - (bounds.y + bounds.height)) as i32,
+ bounds.width as i32,
+ bounds.height as i32,
+ );
+
+ gl.use_program(Some(self.program));
+ gl.bind_vertex_array(Some(self.vertex_array));
+ gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.instances));
+ }
+
+ if transformation != self.current_transform {
+ unsafe {
+ let matrix: [f32; 16] = transformation.into();
+ gl.uniform_matrix_4_f32_slice(
+ Some(&self.transform_location),
+ false,
+ &matrix,
+ );
+
+ self.current_transform = transformation;
+ }
+ }
+
+ if scale != self.current_scale {
+ unsafe {
+ gl.uniform_1_f32(Some(&self.scale_location), scale);
+ }
+
+ self.current_scale = scale;
+ }
+
+ if target_height != self.current_target_height {
+ unsafe {
+ gl.uniform_1_f32(
+ Some(&self.screen_height_location),
+ target_height as f32,
+ );
+ }
+
+ self.current_target_height = target_height;
+ }
+
+ for instances in instances.chunks(MAX_INSTANCES) {
+ unsafe {
+ gl.buffer_sub_data_u8_slice(
+ glow::ARRAY_BUFFER,
+ 0,
+ bytemuck::cast_slice(&instances),
+ );
+
+ gl.draw_arrays_instanced(
+ glow::TRIANGLE_STRIP,
+ 0,
+ 4,
+ instances.len() as i32,
+ );
+ }
+ }
+
+ unsafe {
+ gl.bind_vertex_array(None);
+ gl.use_program(None);
+ gl.disable(glow::SCISSOR_TEST);
+ }
+ }
+}
+
+unsafe fn create_instance_buffer(
+ gl: &glow::Context,
+ size: usize,
+) -> (
+ <glow::Context as HasContext>::VertexArray,
+ <glow::Context as HasContext>::Buffer,
+) {
+ let vertex_array = gl.create_vertex_array().expect("Create vertex array");
+ let buffer = gl.create_buffer().expect("Create instance buffer");
+
+ gl.bind_vertex_array(Some(vertex_array));
+ gl.bind_buffer(glow::ARRAY_BUFFER, Some(buffer));
+ gl.buffer_data_size(
+ glow::ARRAY_BUFFER,
+ (size * std::mem::size_of::<layer::Quad>()) as i32,
+ glow::DYNAMIC_DRAW,
+ );
+
+ let stride = std::mem::size_of::<layer::Quad>() as i32;
+
+ gl.enable_vertex_attrib_array(0);
+ gl.vertex_attrib_pointer_f32(0, 2, glow::FLOAT, false, stride, 0);
+ gl.vertex_attrib_divisor(0, 1);
+
+ gl.enable_vertex_attrib_array(1);
+ gl.vertex_attrib_pointer_f32(1, 2, glow::FLOAT, false, stride, 4 * 2);
+ gl.vertex_attrib_divisor(1, 1);
+
+ gl.enable_vertex_attrib_array(2);
+ gl.vertex_attrib_pointer_f32(2, 4, glow::FLOAT, false, stride, 4 * (2 + 2));
+ gl.vertex_attrib_divisor(2, 1);
+
+ gl.enable_vertex_attrib_array(3);
+ gl.vertex_attrib_pointer_f32(
+ 3,
+ 4,
+ glow::FLOAT,
+ false,
+ stride,
+ 4 * (2 + 2 + 4),
+ );
+ gl.vertex_attrib_divisor(3, 1);
+
+ gl.enable_vertex_attrib_array(4);
+ gl.vertex_attrib_pointer_f32(
+ 4,
+ 1,
+ glow::FLOAT,
+ false,
+ stride,
+ 4 * (2 + 2 + 4 + 4),
+ );
+ gl.vertex_attrib_divisor(4, 1);
+
+ gl.enable_vertex_attrib_array(5);
+ gl.vertex_attrib_pointer_f32(
+ 5,
+ 1,
+ glow::FLOAT,
+ false,
+ stride,
+ 4 * (2 + 2 + 4 + 4 + 1),
+ );
+ gl.vertex_attrib_divisor(5, 1);
+
+ gl.bind_vertex_array(None);
+ gl.bind_buffer(glow::ARRAY_BUFFER, None);
+
+ (vertex_array, buffer)
+}
diff --git a/glow/src/shader/compatibility/quad.frag b/glow/src/shader/compatibility/quad.frag
new file mode 100644
index 00000000..c2634c65
--- /dev/null
+++ b/glow/src/shader/compatibility/quad.frag
@@ -0,0 +1,62 @@
+#version 100
+precision mediump float;
+
+uniform float u_ScreenHeight;
+
+varying vec4 v_Color;
+varying vec4 v_BorderColor;
+varying vec2 v_Pos;
+varying vec2 v_Scale;
+varying float v_BorderRadius;
+varying float v_BorderWidth;
+
+float _distance(in vec2 frag_coord, in vec2 position, in vec2 size, float radius)
+{
+ // TODO: Try SDF approach: https://www.shadertoy.com/view/wd3XRN
+ vec2 inner_size = size - vec2(radius, radius) * 2.0;
+ vec2 top_left = position + vec2(radius, radius);
+ vec2 bottom_right = top_left + inner_size;
+
+ vec2 top_left_distance = top_left - frag_coord;
+ vec2 bottom_right_distance = frag_coord - bottom_right;
+
+ vec2 distance = vec2(
+ max(max(top_left_distance.x, bottom_right_distance.x), 0.0),
+ max(max(top_left_distance.y, bottom_right_distance.y), 0.0)
+ );
+
+ return sqrt(distance.x * distance.x + distance.y * distance.y);
+}
+
+void main() {
+ vec2 fragCoord = vec2(gl_FragCoord.x, u_ScreenHeight - gl_FragCoord.y);
+
+ float internal_border = max(v_BorderRadius - v_BorderWidth, 0.0);
+
+ float internal_distance = _distance(
+ fragCoord,
+ v_Pos + vec2(v_BorderWidth),
+ v_Scale - vec2(v_BorderWidth * 2.0),
+ internal_border
+ );
+
+ float border_mix = smoothstep(
+ max(internal_border - 0.5, 0.0),
+ internal_border + 0.5,
+ internal_distance
+ );
+
+ vec4 mixed_color = mix(v_Color, v_BorderColor, border_mix);
+
+ float d = _distance(
+ fragCoord,
+ v_Pos,
+ v_Scale,
+ v_BorderRadius
+ );
+
+ float radius_alpha =
+ 1.0 - smoothstep(max(v_BorderRadius - 0.5, 0.0), v_BorderRadius + 0.5, d);
+
+ gl_FragColor = vec4(mixed_color.xyz, mixed_color.w * radius_alpha);
+}
diff --git a/glow/src/shader/compatibility/quad.vert b/glow/src/shader/compatibility/quad.vert
new file mode 100644
index 00000000..0d02e9d0
--- /dev/null
+++ b/glow/src/shader/compatibility/quad.vert
@@ -0,0 +1,46 @@
+#version 100
+
+uniform mat4 u_Transform;
+uniform float u_Scale;
+
+attribute vec2 i_Pos;
+attribute vec2 i_Scale;
+attribute vec4 i_Color;
+attribute vec4 i_BorderColor;
+attribute float i_BorderRadius;
+attribute float i_BorderWidth;
+attribute vec2 q_Pos;
+
+varying vec4 v_Color;
+varying vec4 v_BorderColor;
+varying vec2 v_Pos;
+varying vec2 v_Scale;
+varying float v_BorderRadius;
+varying float v_BorderWidth;
+
+
+void main() {
+ vec2 p_Pos = i_Pos * u_Scale;
+ vec2 p_Scale = i_Scale * u_Scale;
+
+ float i_BorderRadius = min(
+ i_BorderRadius,
+ min(i_Scale.x, i_Scale.y) / 2.0
+ );
+
+ mat4 i_Transform = mat4(
+ vec4(p_Scale.x + 1.0, 0.0, 0.0, 0.0),
+ vec4(0.0, p_Scale.y + 1.0, 0.0, 0.0),
+ vec4(0.0, 0.0, 1.0, 0.0),
+ vec4(p_Pos - vec2(0.5, 0.5), 0.0, 1.0)
+ );
+
+ v_Color = i_Color;
+ v_BorderColor = i_BorderColor;
+ v_Pos = p_Pos;
+ v_Scale = p_Scale;
+ v_BorderRadius = i_BorderRadius * u_Scale;
+ v_BorderWidth = i_BorderWidth * u_Scale;
+
+ gl_Position = u_Transform * i_Transform * vec4(q_Pos, 0.0, 1.0);
+}
diff --git a/glow/src/shader/compatibility/triangle.frag b/glow/src/shader/compatibility/triangle.frag
new file mode 100644
index 00000000..58fca553
--- /dev/null
+++ b/glow/src/shader/compatibility/triangle.frag
@@ -0,0 +1,8 @@
+#version 100
+precision mediump float;
+
+varying vec4 v_Color;
+
+void main() {
+ gl_FragColor = v_Color;
+}
diff --git a/glow/src/shader/compatibility/triangle.vert b/glow/src/shader/compatibility/triangle.vert
new file mode 100644
index 00000000..975c9781
--- /dev/null
+++ b/glow/src/shader/compatibility/triangle.vert
@@ -0,0 +1,13 @@
+#version 100
+
+uniform mat4 u_Transform;
+
+attribute vec2 i_Position;
+attribute vec4 i_Color;
+
+varying vec4 v_Color;
+
+void main() {
+ v_Color = i_Color;
+ gl_Position = u_Transform * vec4(i_Position, 0.0, 1.0);
+}
diff --git a/glow/src/shader/quad.frag b/glow/src/shader/core/quad.frag
index cea36bdc..18fd5baa 100644
--- a/glow/src/shader/quad.frag
+++ b/glow/src/shader/core/quad.frag
@@ -1,4 +1,4 @@
-#version 330
+#version 130
uniform float u_ScreenHeight;
diff --git a/glow/src/shader/quad.vert b/glow/src/shader/core/quad.vert
index 82417856..30f28d52 100644
--- a/glow/src/shader/quad.vert
+++ b/glow/src/shader/core/quad.vert
@@ -1,14 +1,14 @@
-#version 330
+#version 130
uniform mat4 u_Transform;
uniform float u_Scale;
-layout(location = 0) in vec2 i_Pos;
-layout(location = 1) in vec2 i_Scale;
-layout(location = 2) in vec4 i_Color;
-layout(location = 3) in vec4 i_BorderColor;
-layout(location = 4) in float i_BorderRadius;
-layout(location = 5) in float i_BorderWidth;
+in vec2 i_Pos;
+in vec2 i_Scale;
+in vec4 i_Color;
+in vec4 i_BorderColor;
+in float i_BorderRadius;
+in float i_BorderWidth;
out vec4 v_Color;
out vec4 v_BorderColor;
diff --git a/glow/src/shader/triangle.frag b/glow/src/shader/core/triangle.frag
index d186784a..39c2ff6f 100644
--- a/glow/src/shader/triangle.frag
+++ b/glow/src/shader/core/triangle.frag
@@ -1,4 +1,4 @@
-#version 330
+#version 130
in vec4 v_Color;
diff --git a/glow/src/shader/triangle.vert b/glow/src/shader/core/triangle.vert
index 5723436a..895652ea 100644
--- a/glow/src/shader/triangle.vert
+++ b/glow/src/shader/core/triangle.vert
@@ -1,9 +1,9 @@
-#version 330
+#version 130
uniform mat4 u_Transform;
-layout(location = 0) in vec2 i_Position;
-layout(location = 1) in vec4 i_Color;
+in vec2 i_Position;
+in vec4 i_Color;
out vec4 v_Color;
diff --git a/glow/src/triangle.rs b/glow/src/triangle.rs
index 9202bcb2..d0a05be6 100644
--- a/glow/src/triangle.rs
+++ b/glow/src/triangle.rs
@@ -26,10 +26,13 @@ impl Pipeline {
program::create(
gl,
&[
- (glow::VERTEX_SHADER, include_str!("shader/triangle.vert")),
+ (
+ glow::VERTEX_SHADER,
+ include_str!("shader/compatibility/triangle.vert"),
+ ),
(
glow::FRAGMENT_SHADER,
- include_str!("shader/triangle.frag"),
+ include_str!("shader/compatibility/triangle.frag"),
),
],
)