Use the swapchain-preferred texture format by default (#182)

- Fixes #140
- Adds a public method to get the current GPU framebuffer texture format (AKA the render texture format).
- This wasn't as difficult as it seemed; the extra API is used by the examples to get the right texture format instead of being hardcoded.
This commit is contained in:
Jay Oster 2021-07-17 08:21:49 -07:00 committed by GitHub
parent ce549a79b6
commit 288da3675f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 59 additions and 35 deletions

View file

@ -45,7 +45,7 @@ fn main() -> Result<(), Error> {
};
let mut world = World::new();
let mut time = 0.0;
let mut noise_renderer = NoiseRenderer::new(pixels.device(), WIDTH, HEIGHT);
let mut noise_renderer = NoiseRenderer::new(&pixels, WIDTH, HEIGHT);
event_loop.run(move |event, _, control_flow| {
// Draw the current frame
@ -82,7 +82,7 @@ fn main() -> Result<(), Error> {
// Resize the window
if let Some(size) = input.window_resized() {
pixels.resize_surface(size.width, size.height);
noise_renderer.resize(pixels.device(), size.width, size.height);
noise_renderer.resize(&pixels, size.width, size.height);
}
// Update internal state and request a redraw

View file

@ -11,13 +11,14 @@ pub(crate) struct NoiseRenderer {
}
impl NoiseRenderer {
pub(crate) fn new(device: &wgpu::Device, width: u32, height: u32) -> Self {
pub(crate) fn new(pixels: &pixels::Pixels, width: u32, height: u32) -> Self {
let device = pixels.device();
let shader = wgpu::include_wgsl!("../shaders/noise.wgsl");
let module = device.create_shader_module(&shader);
// Create a texture view that will be used as input
// This will be used as the render target for the default scaling renderer
let texture_view = create_texture_view(device, width, height);
let texture_view = create_texture_view(pixels, width, height);
// Create a texture sampler with nearest neighbor
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
@ -137,7 +138,7 @@ impl NoiseRenderer {
module: &module,
entry_point: "fs_main",
targets: &[wgpu::ColorTargetState {
format: wgpu::TextureFormat::Bgra8UnormSrgb,
format: pixels.render_texture_format(),
blend: Some(wgpu::BlendState {
color: wgpu::BlendComponent::REPLACE,
alpha: wgpu::BlendComponent::REPLACE,
@ -162,10 +163,10 @@ impl NoiseRenderer {
&self.texture_view
}
pub(crate) fn resize(&mut self, device: &wgpu::Device, width: u32, height: u32) {
self.texture_view = create_texture_view(device, width, height);
pub(crate) fn resize(&mut self, pixels: &pixels::Pixels, width: u32, height: u32) {
self.texture_view = create_texture_view(pixels, width, height);
self.bind_group = create_bind_group(
device,
pixels.device(),
&self.bind_group_layout,
&self.texture_view,
&self.sampler,
@ -203,7 +204,8 @@ impl NoiseRenderer {
}
}
fn create_texture_view(device: &wgpu::Device, width: u32, height: u32) -> wgpu::TextureView {
fn create_texture_view(pixels: &pixels::Pixels, width: u32, height: u32) -> wgpu::TextureView {
let device = pixels.device();
let texture_descriptor = wgpu::TextureDescriptor {
label: None,
size: pixels::wgpu::Extent3d {
@ -214,7 +216,7 @@ fn create_texture_view(device: &wgpu::Device, width: u32, height: u32) -> wgpu::
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Bgra8UnormSrgb,
format: pixels.render_texture_format(),
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::RENDER_ATTACHMENT,
};

View file

@ -19,7 +19,7 @@ pub(crate) struct Gui {
impl Gui {
/// Create egui.
pub(crate) fn new(width: u32, height: u32, scale_factor: f64, context: &PixelsContext) -> Self {
pub(crate) fn new(width: u32, height: u32, scale_factor: f64, pixels: &pixels::Pixels) -> Self {
let platform = Platform::new(PlatformDescriptor {
physical_width: width,
physical_height: height,
@ -32,7 +32,7 @@ impl Gui {
physical_height: height,
scale_factor: scale_factor as f32,
};
let rpass = RenderPass::new(&context.device, wgpu::TextureFormat::Bgra8UnormSrgb, 1);
let rpass = RenderPass::new(pixels.device(), pixels.render_texture_format(), 1);
Self {
start_time: Instant::now(),

View file

@ -43,12 +43,7 @@ fn main() -> Result<(), Error> {
let scale_factor = window.scale_factor();
let surface_texture = SurfaceTexture::new(window_size.width, window_size.height, &window);
let pixels = Pixels::new(WIDTH, HEIGHT, surface_texture)?;
let gui = Gui::new(
window_size.width,
window_size.height,
scale_factor,
pixels.context(),
);
let gui = Gui::new(window_size.width, window_size.height, scale_factor, &pixels);
(pixels, gui)
};

View file

@ -44,9 +44,8 @@ impl Gui {
// Create Dear ImGui WGPU renderer
let device = pixels.device();
let queue = pixels.queue();
let texture_format = wgpu::TextureFormat::Bgra8UnormSrgb;
let config = imgui_wgpu::RendererConfig {
texture_format,
texture_format: pixels.render_texture_format(),
..Default::default()
};
let renderer = imgui_wgpu::Renderer::new(&mut imgui, device, queue, config);

View file

@ -15,7 +15,7 @@ pub struct PixelsBuilder<'req, 'dev, 'win, W: HasRawWindowHandle> {
present_mode: wgpu::PresentMode,
surface_texture: SurfaceTexture<'win, W>,
texture_format: wgpu::TextureFormat,
render_texture_format: wgpu::TextureFormat,
render_texture_format: Option<wgpu::TextureFormat>,
}
impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W> {
@ -58,7 +58,7 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W>
present_mode: wgpu::PresentMode::Fifo,
surface_texture,
texture_format: wgpu::TextureFormat::Rgba8UnormSrgb,
render_texture_format: wgpu::TextureFormat::Bgra8UnormSrgb,
render_texture_format: None,
}
}
@ -82,8 +82,7 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W>
/// Set which backends wgpu will attempt to use.
///
/// The default value of this is [`wgpu::BackendBit::PRIMARY`], which enables
/// the well supported backends for wgpu.
/// The default value is `PRIMARY`, which enables the well supported backends for wgpu.
pub fn wgpu_backend(mut self, backend: wgpu::BackendBit) -> PixelsBuilder<'req, 'dev, 'win, W> {
self.backend = backend;
self
@ -144,9 +143,12 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W>
/// Set the texture format.
///
/// The default value is [`wgpu::TextureFormat::Rgba8UnormSrgb`], which is 4 unsigned bytes in
/// `RGBA` order using the SRGB color space. This is typically what you want when you are
/// working with color values from popular image editing tools or web apps.
/// The default value is `Rgba8UnormSrgb`, which is 4 unsigned bytes in `RGBA` order using the
/// sRGB color space. This is typically what you want when you are working with color values
/// from popular image editing tools or web apps.
///
/// This is the pixel format of the texture that most applications will interact with directly.
/// The format influences the structure of byte data that is returned by [`Pixels::get_frame`].
pub fn texture_format(
mut self,
texture_format: wgpu::TextureFormat,
@ -157,14 +159,27 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W>
/// Set the render texture format.
///
/// The default value is [`wgpu::TextureFormat::Bgra8UnormSrgb`], which is 4 unsigned bytes in
/// `BGRA` order using the SRGB color space. This format depends on the hardware/platform the
/// pixel buffer is rendered to/for.
/// The default value is chosen automatically by the swapchain (if it can) with a fallback to
/// `Bgra8UnormSrgb` (which is 4 unsigned bytes in `BGRA` order using the sRGB color space).
/// Setting this format correctly depends on the hardware/platform the pixel buffer is rendered
/// to. The chosen format can be retrieved later with [`Pixels::render_texture_format`].
///
/// This method controls the format of the swapchain frame buffer, which has strict texture
/// format requirements. Applications will never interact directly with the pixel data of this
/// texture, but a view is provided to the `render_function` closure by [`Pixels::render_with`].
/// The render texture can only be used as the final render target at the end of all
/// post-processing shaders.
///
/// The [`ScalingRenderer`] also uses this format for its own render target. This is because it
/// assumes the render target is always the swapchain current frame. This needs to be kept in
/// mind when writing custom shaders for post-processing effects. There is a full example of a
/// [custom-shader](https://github.com/parasyte/pixels/tree/master/examples/custom-shader)
/// available that demonstrates how to deal with this.
pub fn render_texture_format(
mut self,
texture_format: wgpu::TextureFormat,
) -> PixelsBuilder<'req, 'dev, 'win, W> {
self.render_texture_format = texture_format;
self.render_texture_format = Some(texture_format);
self
}
@ -196,13 +211,18 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W>
.map_err(Error::DeviceNotFound)?;
let present_mode = self.present_mode;
let render_texture_format = self.render_texture_format.unwrap_or_else(|| {
adapter
.get_swap_chain_preferred_format(&surface)
.unwrap_or(wgpu::TextureFormat::Bgra8UnormSrgb)
});
// Create swap chain
let surface_size = self.surface_texture.size;
let swap_chain = create_swap_chain(
&mut device,
&surface,
self.render_texture_format,
render_texture_format,
&surface_size,
present_mode,
);
@ -217,7 +237,7 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W>
self.texture_format,
// Render texture values
&surface_size,
self.render_texture_format,
render_texture_format,
);
// Create the pixel buffer
@ -241,9 +261,9 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W>
context,
surface_size,
present_mode,
render_texture_format,
pixels,
scaling_matrix_inverse,
render_texture_format: self.render_texture_format,
})
}
}

View file

@ -525,8 +525,16 @@ impl Pixels {
&self.context.texture
}
/// Provides access to the internal [`PixelsContext`]
/// Provides access to the internal [`PixelsContext`].
pub fn context(&self) -> &PixelsContext {
&self.context
}
/// Get the render texture format.
///
/// This texture format may be chosen automatically by the swapchain. See
/// [`PixelsBuilder::render_texture_format`] for more information.
pub fn render_texture_format(&self) -> wgpu::TextureFormat {
self.render_texture_format
}
}