Implement MSAA for triangle meshes in iced_glow
This commit is contained in:
parent
bbfb1c040c
commit
c5545c7a73
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user