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:
parent
ce549a79b6
commit
288da3675f
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
10
src/lib.rs
10
src/lib.rs
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue