diff options
author | 2020-05-22 01:14:31 +0200 | |
---|---|---|
committer | 2020-05-22 01:16:12 +0200 | |
commit | c5545c7a7306b5312007ffa74a014db4992ff5f4 (patch) | |
tree | 93f7277e22e376bb50ef39db3aed72408d2ba814 /glow | |
parent | bbfb1c040c92e36b3d23a2167ad3432c819b9668 (diff) | |
download | iced-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.rs | 236 |
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); + } + } +} |