Use built-in OpenGL multisampling in iced_glow

This commit is contained in:
Héctor Ramón Jiménez 2020-05-22 19:15:39 +02:00
parent 6f71a8e3d5
commit 1dd79c4697
6 changed files with 61 additions and 210 deletions

View File

@ -26,8 +26,7 @@ impl Backend {
pub fn new(gl: &glow::Context, settings: Settings) -> Self { pub fn new(gl: &glow::Context, settings: Settings) -> Self {
let text_pipeline = text::Pipeline::new(gl, settings.default_font); let text_pipeline = text::Pipeline::new(gl, settings.default_font);
let quad_pipeline = quad::Pipeline::new(gl); let quad_pipeline = quad::Pipeline::new(gl);
let triangle_pipeline = let triangle_pipeline = triangle::Pipeline::new(gl);
triangle::Pipeline::new(gl, settings.antialiasing);
Self { Self {
quad_pipeline, quad_pipeline,
@ -56,7 +55,6 @@ impl Backend {
scale_factor, scale_factor,
projection, projection,
&layer, &layer,
viewport_size.width,
viewport_size.height, viewport_size.height,
); );
} }
@ -70,7 +68,6 @@ impl Backend {
scale_factor: f32, scale_factor: f32,
transformation: Transformation, transformation: Transformation,
layer: &Layer<'_>, layer: &Layer<'_>,
target_width: u32,
target_height: u32, target_height: u32,
) { ) {
let mut bounds = (layer.bounds * scale_factor).round(); let mut bounds = (layer.bounds * scale_factor).round();
@ -93,7 +90,6 @@ impl Backend {
self.triangle_pipeline.draw( self.triangle_pipeline.draw(
gl, gl,
target_width,
target_height, target_height,
scaled, scaled,
scale_factor, scale_factor,

View File

@ -1,10 +1,8 @@
//! Draw meshes of triangles. //! Draw meshes of triangles.
use crate::program; use crate::program;
use crate::settings;
use crate::Transformation; use crate::Transformation;
use glow::HasContext; use glow::HasContext;
use iced_graphics::layer; use iced_graphics::layer;
use iced_graphics::Size;
use std::marker::PhantomData; use std::marker::PhantomData;
pub use iced_graphics::triangle::{Mesh2D, Vertex2D}; pub use iced_graphics::triangle::{Mesh2D, Vertex2D};
@ -20,14 +18,10 @@ pub(crate) struct Pipeline {
indices: Buffer<u32>, indices: Buffer<u32>,
transform_location: <glow::Context as HasContext>::UniformLocation, transform_location: <glow::Context as HasContext>::UniformLocation,
current_transform: Transformation, current_transform: Transformation,
antialias: Antialias,
} }
impl Pipeline { impl Pipeline {
pub fn new( pub fn new(gl: &glow::Context) -> Pipeline {
gl: &glow::Context,
antialiasing: Option<settings::Antialiasing>,
) -> Pipeline {
let program = unsafe { let program = unsafe {
program::create( program::create(
gl, gl,
@ -109,20 +103,19 @@ impl Pipeline {
indices, indices,
transform_location, transform_location,
current_transform: Transformation::identity(), current_transform: Transformation::identity(),
antialias: Antialias::new(antialiasing),
} }
} }
pub fn draw( pub fn draw(
&mut self, &mut self,
gl: &glow::Context, gl: &glow::Context,
target_width: u32,
target_height: u32, target_height: u32,
transformation: Transformation, transformation: Transformation,
scale_factor: f32, scale_factor: f32,
meshes: &[layer::Mesh<'_>], meshes: &[layer::Mesh<'_>],
) { ) {
unsafe { unsafe {
gl.enable(glow::MULTISAMPLE);
gl.enable(glow::SCISSOR_TEST); gl.enable(glow::SCISSOR_TEST);
gl.use_program(Some(self.program)); gl.use_program(Some(self.program));
gl.bind_vertex_array(Some(self.vertex_array)); gl.bind_vertex_array(Some(self.vertex_array));
@ -170,67 +163,59 @@ impl Pipeline {
} }
} }
let Self { // Then we draw each mesh using offsets
antialias, let mut last_vertex = 0;
current_transform, let mut last_index = 0;
transform_location,
..
} = self;
// Then we draw each mesh using offsets with antialiasing for layer::Mesh {
antialias.perform(gl, Size::new(target_width, target_height), |gl| { buffers,
let mut last_vertex = 0; origin,
let mut last_index = 0; clip_bounds,
} in meshes
{
let transform =
transformation * Transformation::translate(origin.x, origin.y);
for layer::Mesh { let clip_bounds = (*clip_bounds * scale_factor).round();
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 {
unsafe { let matrix: [f32; 16] = transform.into();
if *current_transform != transform { gl.uniform_matrix_4_f32_slice(
let matrix: [f32; 16] = transform.into(); Some(&self.transform_location),
gl.uniform_matrix_4_f32_slice( false,
Some(transform_location), &matrix,
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( self.current_transform = transform;
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 { unsafe {
gl.bind_vertex_array(None); gl.bind_vertex_array(None);
gl.use_program(None); gl.use_program(None);
gl.disable(glow::SCISSOR_TEST); gl.disable(glow::SCISSOR_TEST);
gl.disable(glow::MULTISAMPLE);
} }
} }
} }
@ -305,146 +290,3 @@ 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);
}
}
}

View File

@ -2,7 +2,7 @@ use crate::{Backend, Renderer, Settings, Viewport};
use core::ffi::c_void; use core::ffi::c_void;
use glow::HasContext; use glow::HasContext;
use iced_graphics::Size; use iced_graphics::{Antialiasing, Size};
use iced_native::mouse; use iced_native::mouse;
/// A window graphics backend for iced powered by `glow`. /// A window graphics backend for iced powered by `glow`.
@ -30,11 +30,21 @@ impl iced_graphics::window::GLCompositor for Compositor {
gl.enable(glow::BLEND); gl.enable(glow::BLEND);
gl.blend_func(glow::SRC_ALPHA, glow::ONE_MINUS_SRC_ALPHA); gl.blend_func(glow::SRC_ALPHA, glow::ONE_MINUS_SRC_ALPHA);
// Disable multisampling by default
gl.disable(glow::MULTISAMPLE);
let renderer = Renderer::new(Backend::new(&gl, settings)); let renderer = Renderer::new(Backend::new(&gl, settings));
(Self { gl }, renderer) (Self { gl }, renderer)
} }
fn sample_count(settings: &Settings) -> u32 {
settings
.antialiasing
.map(Antialiasing::sample_count)
.unwrap_or(0)
}
fn resize_viewport(&mut self, physical_size: Size<u32>) { fn resize_viewport(&mut self, physical_size: Size<u32>) {
unsafe { unsafe {
self.gl.viewport( self.gl.viewport(

View File

@ -51,6 +51,7 @@ pub fn run<A, E, C>(
let context = ContextBuilder::new() let context = ContextBuilder::new()
.with_vsync(true) .with_vsync(true)
.with_multisampling(C::sample_count(&compositor_settings) as u16)
.build_windowed(builder, &event_loop) .build_windowed(builder, &event_loop)
.expect("Open window"); .expect("Open window");

View File

@ -12,6 +12,8 @@ pub trait GLCompositor: Sized {
loader_function: impl FnMut(&str) -> *const c_void, loader_function: impl FnMut(&str) -> *const c_void,
) -> (Self, Self::Renderer); ) -> (Self, Self::Renderer);
fn sample_count(settings: &Self::Settings) -> u32;
fn resize_viewport(&mut self, physical_size: Size<u32>); fn resize_viewport(&mut self, physical_size: Size<u32>);
fn draw<T: AsRef<str>>( fn draw<T: AsRef<str>>(

View File

@ -170,9 +170,9 @@ impl Pipeline {
], ],
}], }],
}, },
sample_count: antialiasing sample_count: u32::from(
.map(|a| a.sample_count()) antialiasing.map(|a| a.sample_count()).unwrap_or(1),
.unwrap_or(1), ),
sample_mask: !0, sample_mask: !0,
alpha_to_coverage_enabled: false, alpha_to_coverage_enabled: false,
}); });