-
Notifications
You must be signed in to change notification settings - Fork 38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Maybe sharper egui soon #216
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,19 +26,20 @@ use std::{ | |
#[derive(Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)] | ||
struct Uniforms { | ||
screen_size: [f32; 2], | ||
padding: [f32; 2], | ||
dithering: u32, | ||
padding: u32, | ||
} | ||
|
||
#[derive(blade_macros::ShaderData)] | ||
struct Globals { | ||
r_uniforms: Uniforms, | ||
r_sampler: blade_graphics::Sampler, | ||
} | ||
|
||
#[derive(blade_macros::ShaderData)] | ||
struct Locals { | ||
r_vertex_data: blade_graphics::BufferPiece, | ||
r_texture: blade_graphics::TextureView, | ||
r_sampler: blade_graphics::Sampler, | ||
} | ||
|
||
#[derive(Debug, PartialEq)] | ||
|
@@ -58,10 +59,16 @@ impl ScreenDescriptor { | |
struct GuiTexture { | ||
allocation: blade_graphics::Texture, | ||
view: blade_graphics::TextureView, | ||
sampler: blade_graphics::Sampler, | ||
} | ||
|
||
impl GuiTexture { | ||
fn create(context: &blade_graphics::Context, name: &str, size: blade_graphics::Extent) -> Self { | ||
fn create( | ||
context: &blade_graphics::Context, | ||
name: &str, | ||
size: blade_graphics::Extent, | ||
options: egui::TextureOptions, | ||
) -> Self { | ||
let format = blade_graphics::TextureFormat::Rgba8UnormSrgb; | ||
let allocation = context.create_texture(blade_graphics::TextureDesc { | ||
name, | ||
|
@@ -81,12 +88,62 @@ impl GuiTexture { | |
subresources: &blade_graphics::TextureSubresources::default(), | ||
}, | ||
); | ||
Self { allocation, view } | ||
|
||
let sampler = context.create_sampler(blade_graphics::SamplerDesc { | ||
name, | ||
address_modes: { | ||
let mode = match options.wrap_mode { | ||
egui::TextureWrapMode::ClampToEdge => blade_graphics::AddressMode::ClampToEdge, | ||
egui::TextureWrapMode::Repeat => blade_graphics::AddressMode::Repeat, | ||
egui::TextureWrapMode::MirroredRepeat => { | ||
blade_graphics::AddressMode::MirrorRepeat | ||
} | ||
}; | ||
[mode; 3] | ||
}, | ||
mag_filter: match options.magnification { | ||
egui::TextureFilter::Nearest => blade_graphics::FilterMode::Nearest, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should have helper function to do this mapping, since we are doing it 3 times here |
||
egui::TextureFilter::Linear => blade_graphics::FilterMode::Linear, | ||
}, | ||
min_filter: match options.minification { | ||
egui::TextureFilter::Nearest => blade_graphics::FilterMode::Nearest, | ||
egui::TextureFilter::Linear => blade_graphics::FilterMode::Linear, | ||
}, | ||
mipmap_filter: match options.mipmap_mode { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this would look like |
||
Some(it) => match it { | ||
egui::TextureFilter::Nearest => blade_graphics::FilterMode::Nearest, | ||
egui::TextureFilter::Linear => blade_graphics::FilterMode::Linear, | ||
}, | ||
None => blade_graphics::FilterMode::Linear, | ||
}, | ||
..Default::default() | ||
}); | ||
|
||
Self { | ||
allocation, | ||
view, | ||
sampler, | ||
} | ||
} | ||
|
||
fn delete(self, context: &blade_graphics::Context) { | ||
context.destroy_texture(self.allocation); | ||
context.destroy_texture_view(self.view); | ||
context.destroy_sampler(self.sampler); | ||
} | ||
} | ||
|
||
#[derive(Clone, Copy)] | ||
pub struct GuiPainterOptions { | ||
/// Controls whether to apply dithering to minimize banding artifacts, same as egui-wgpu | ||
/// | ||
/// Defaults to true. | ||
pub dithering: bool, | ||
} | ||
|
||
impl Default for GuiPainterOptions { | ||
fn default() -> Self { | ||
Self { dithering: true } | ||
} | ||
} | ||
|
||
|
@@ -103,7 +160,7 @@ pub struct GuiPainter { | |
//TODO: this could also look better | ||
textures_dropped: Vec<GuiTexture>, | ||
textures_to_delete: Vec<(GuiTexture, blade_graphics::SyncPoint)>, | ||
sampler: blade_graphics::Sampler, | ||
options: GuiPainterOptions, | ||
} | ||
|
||
impl GuiPainter { | ||
|
@@ -120,15 +177,18 @@ impl GuiPainter { | |
for (gui_texture, _) in self.textures_to_delete.drain(..) { | ||
gui_texture.delete(context); | ||
} | ||
context.destroy_sampler(self.sampler); | ||
} | ||
|
||
/// Create a new painter with a given GPU context. | ||
/// | ||
/// It supports renderpasses with only a color attachment, | ||
/// and this attachment format must be The `output_format`. | ||
#[profiling::function] | ||
pub fn new(info: blade_graphics::SurfaceInfo, context: &blade_graphics::Context) -> Self { | ||
pub fn new( | ||
info: blade_graphics::SurfaceInfo, | ||
context: &blade_graphics::Context, | ||
options: GuiPainterOptions, | ||
) -> Self { | ||
let shader = context.create_shader(blade_graphics::ShaderDesc { | ||
source: SHADER_SOURCE, | ||
}); | ||
|
@@ -144,7 +204,11 @@ impl GuiPainter { | |
..Default::default() | ||
}, | ||
depth_stencil: None, //TODO? | ||
fragment: shader.at("fs_main"), | ||
fragment: if info.format.is_srgb() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks highly suspicious to me. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is what egui-wgpu did so I just replicated all of it to see if it would help. Egui examples use a non-srg render target whereas blade always uses one There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minimizing changes is a good experiment for sure. Shipping it the way egui_wgpu did seems very concerning to me. I'll try to find some associated discussion there. |
||
shader.at("fs_main_linear_framebuffer") | ||
} else { | ||
shader.at("fs_main_gamma_framebuffer") | ||
}, | ||
color_targets: &[blade_graphics::ColorTargetState { | ||
format: info.format, | ||
blend: Some(blade_graphics::BlendState::ALPHA_BLENDING), | ||
|
@@ -158,21 +222,13 @@ impl GuiPainter { | |
alignment: 4, | ||
}); | ||
|
||
let sampler = context.create_sampler(blade_graphics::SamplerDesc { | ||
name: "gui", | ||
address_modes: [blade_graphics::AddressMode::ClampToEdge; 3], | ||
mag_filter: blade_graphics::FilterMode::Linear, | ||
min_filter: blade_graphics::FilterMode::Linear, | ||
..Default::default() | ||
}); | ||
|
||
Self { | ||
pipeline, | ||
belt, | ||
textures: Default::default(), | ||
textures_dropped: Vec::new(), | ||
textures_to_delete: Vec::new(), | ||
sampler, | ||
options, | ||
} | ||
} | ||
|
||
|
@@ -239,15 +295,16 @@ impl GuiPainter { | |
let texture = match self.textures.entry(texture_id) { | ||
Entry::Occupied(mut o) => { | ||
if image_delta.pos.is_none() { | ||
let texture = GuiTexture::create(context, &label, extent); | ||
let texture = | ||
GuiTexture::create(context, &label, extent, image_delta.options); | ||
command_encoder.init_texture(texture.allocation); | ||
let old = o.insert(texture); | ||
self.textures_dropped.push(old); | ||
} | ||
o.into_mut() | ||
} | ||
Entry::Vacant(v) => { | ||
let texture = GuiTexture::create(context, &label, extent); | ||
let texture = GuiTexture::create(context, &label, extent, image_delta.options); | ||
command_encoder.init_texture(texture.allocation); | ||
v.insert(texture) | ||
} | ||
|
@@ -296,9 +353,9 @@ impl GuiPainter { | |
&Globals { | ||
r_uniforms: Uniforms { | ||
screen_size: [logical_size.0, logical_size.1], | ||
padding: [0.0; 2], | ||
dithering: if self.options.dithering { 1 } else { 0 }, | ||
padding: 0, | ||
}, | ||
r_sampler: self.sampler, | ||
}, | ||
); | ||
|
||
|
@@ -340,6 +397,7 @@ impl GuiPainter { | |
&Locals { | ||
r_vertex_data: vertex_buf, | ||
r_texture: texture.view, | ||
r_sampler: texture.sampler, | ||
}, | ||
); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we really need a separate entry point? it's largely doing the same thing, we might as well just have an if/else at the end based on a runtime flag
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Runtime flag can do it. Just replicated egui-wgpu for the quick draft.
It would be nice to find the underlying cause so the shader potentially can be simple again..