summaryrefslogtreecommitdiffstats
path: root/glow
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2020-05-22 01:14:31 +0200
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2020-05-22 01:16:12 +0200
commitc5545c7a7306b5312007ffa74a014db4992ff5f4 (patch)
tree93f7277e22e376bb50ef39db3aed72408d2ba814 /glow
parentbbfb1c040c92e36b3d23a2167ad3432c819b9668 (diff)
downloadiced-c5545c7a7306b5312007ffa74a014db4992ff5f4.tar.gz
iced-c5545c7a7306b5312007ffa74a014db4992ff5f4.tar.bz2
iced-c5545c7a7306b5312007ffa74a014db4992ff5f4.zip
Implement MSAA for triangle meshes in `iced_glow`
Diffstat (limited to 'glow')
-rw-r--r--glow/src/triangle.rs236
1 files changed, 195 insertions, 41 deletions
diff --git a/glow/src/triangle.rs b/glow/src/triangle.rs
index 489ceaff..f350db98 100644
--- a/glow/src/triangle.rs
+++ b/glow/src/triangle.rs
@@ -4,6 +4,7 @@ use crate::settings;
use crate::Transformation;
use glow::HasContext;
use iced_graphics::layer;
+use iced_graphics::Size;
use std::marker::PhantomData;
pub use iced_graphics::triangle::{Mesh2D, Vertex2D};
@@ -18,6 +19,7 @@ pub(crate) struct Pipeline {
vertices: Buffer<Vertex2D>,
indices: Buffer<u32>,
current_transform: Transformation,
+ antialias: Antialias,
}
impl Pipeline {
@@ -97,6 +99,7 @@ impl Pipeline {
vertices,
indices,
current_transform: Transformation::identity(),
+ antialias: Antialias::new(antialiasing),
}
}
@@ -157,49 +160,57 @@ impl Pipeline {
}
}
- // 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 {
- let matrix: [f32; 16] = transform.into();
- gl.uniform_matrix_4_f32_slice(Some(&0), false, &matrix);
-
- self.current_transform = transform;
+ let Self {
+ antialias,
+ current_transform,
+ ..
+ } = self;
+
+ // Then we draw each mesh using offsets with antialiasing
+ antialias.perform(gl, Size::new(target_width, target_height), |gl| {
+ 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 *current_transform != transform {
+ let matrix: [f32; 16] = transform.into();
+ gl.uniform_matrix_4_f32_slice(Some(&0), false, &matrix);
+
+ *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();
}
-
- 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);
@@ -279,3 +290,146 @@ impl<T> Buffer<T> {
}
}
}
+
+#[derive(Debug)]
+pub struct Antialias {
+ renderbuffer: Option<Renderbuffer>,
+ sample_count: u32,
+}
+
+impl Antialias {
+ fn new(antialiasing: Option<settings::Antialiasing>) -> Self {
+ Antialias {
+ renderbuffer: None,
+ sample_count: antialiasing
+ .map(settings::Antialiasing::sample_count)
+ .unwrap_or(1),
+ }
+ }
+
+ fn perform(
+ &mut self,
+ gl: &glow::Context,
+ size: Size<u32>,
+ f: impl FnOnce(&glow::Context),
+ ) {
+ if self.sample_count == 1 {
+ return f(gl);
+ }
+
+ let target = glow::DRAW_FRAMEBUFFER;
+
+ let renderbuffer = if let Some(renderbuffer) = self.renderbuffer.take()
+ {
+ if size == renderbuffer.size {
+ renderbuffer
+ } else {
+ renderbuffer.destroy(gl);
+
+ Renderbuffer::new(gl, target, self.sample_count, size)
+ }
+ } else {
+ Renderbuffer::new(gl, target, self.sample_count, size)
+ };
+
+ renderbuffer.bind(gl, target);
+
+ unsafe {
+ gl.clear_color(0.0, 0.0, 0.0, 0.0);
+ gl.clear(glow::COLOR_BUFFER_BIT);
+ }
+
+ f(gl);
+
+ unsafe {
+ gl.bind_framebuffer(target, None);
+ gl.clear_color(1.0, 1.0, 1.0, 1.0);
+ }
+
+ renderbuffer.blit(gl);
+
+ self.renderbuffer = Some(renderbuffer);
+ }
+}
+
+#[derive(Debug)]
+pub struct Renderbuffer {
+ raw: <glow::Context as HasContext>::Renderbuffer,
+ framebuffer: <glow::Context as HasContext>::Framebuffer,
+ size: Size<u32>,
+}
+
+impl Renderbuffer {
+ fn new(
+ gl: &glow::Context,
+ target: u32,
+ sample_count: u32,
+ size: Size<u32>,
+ ) -> Self {
+ let framebuffer = unsafe {
+ gl.create_framebuffer().expect("Create MSAA framebuffer")
+ };
+
+ let raw = unsafe {
+ gl.create_renderbuffer().expect("Create MSAA renderbuffer")
+ };
+
+ unsafe {
+ gl.bind_renderbuffer(glow::RENDERBUFFER, Some(raw));
+ gl.renderbuffer_storage_multisample(
+ glow::RENDERBUFFER,
+ sample_count as i32,
+ glow::SRGB8_ALPHA8,
+ size.width as i32,
+ size.height as i32,
+ );
+
+ gl.bind_framebuffer(target, Some(framebuffer));
+ gl.framebuffer_renderbuffer(
+ target,
+ glow::COLOR_ATTACHMENT0,
+ glow::RENDERBUFFER,
+ Some(raw),
+ );
+ gl.bind_framebuffer(target, None);
+ }
+
+ Self {
+ raw,
+ framebuffer,
+ size,
+ }
+ }
+
+ fn bind(&self, gl: &glow::Context, target: u32) {
+ unsafe {
+ gl.bind_framebuffer(target, Some(self.framebuffer));
+ }
+ }
+
+ fn blit(&self, gl: &glow::Context) {
+ unsafe {
+ self.bind(gl, glow::READ_FRAMEBUFFER);
+
+ gl.blit_framebuffer(
+ 0,
+ 0,
+ self.size.width as i32,
+ self.size.height as i32,
+ 0,
+ 0,
+ self.size.width as i32,
+ self.size.height as i32,
+ glow::COLOR_BUFFER_BIT,
+ glow::NEAREST,
+ );
+ }
+ }
+
+ fn destroy(self, gl: &glow::Context) {
+ unsafe {
+ gl.delete_renderbuffer(self.raw);
+ gl.delete_framebuffer(self.framebuffer);
+ }
+ }
+}