Implement MSAA for triangle meshes in iced_glow

This commit is contained in:
Héctor Ramón Jiménez 2020-05-22 01:14:31 +02:00
parent bbfb1c040c
commit c5545c7a73

View File

@ -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;
let Self {
antialias,
current_transform,
..
} = self;
for layer::Mesh {
buffers,
origin,
clip_bounds,
} in meshes
{
let transform =
transformation * Transformation::translate(origin.x, origin.y);
// 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;
let clip_bounds = (*clip_bounds * scale_factor).round();
for layer::Mesh {
buffers,
origin,
clip_bounds,
} in meshes
{
let transform = transformation
* Transformation::translate(origin.x, origin.y);
unsafe {
if self.current_transform != transform {
let matrix: [f32; 16] = transform.into();
gl.uniform_matrix_4_f32_slice(Some(&0), false, &matrix);
let clip_bounds = (*clip_bounds * scale_factor).round();
self.current_transform = transform;
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);
}
}
}