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 world = World::new();
|
||||||
let mut time = 0.0;
|
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| {
|
event_loop.run(move |event, _, control_flow| {
|
||||||
// Draw the current frame
|
// Draw the current frame
|
||||||
|
@ -82,7 +82,7 @@ fn main() -> Result<(), Error> {
|
||||||
// Resize the window
|
// Resize the window
|
||||||
if let Some(size) = input.window_resized() {
|
if let Some(size) = input.window_resized() {
|
||||||
pixels.resize_surface(size.width, size.height);
|
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
|
// Update internal state and request a redraw
|
||||||
|
|
|
@ -11,13 +11,14 @@ pub(crate) struct NoiseRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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 shader = wgpu::include_wgsl!("../shaders/noise.wgsl");
|
||||||
let module = device.create_shader_module(&shader);
|
let module = device.create_shader_module(&shader);
|
||||||
|
|
||||||
// Create a texture view that will be used as input
|
// Create a texture view that will be used as input
|
||||||
// This will be used as the render target for the default scaling renderer
|
// 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
|
// Create a texture sampler with nearest neighbor
|
||||||
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
|
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
|
||||||
|
@ -137,7 +138,7 @@ impl NoiseRenderer {
|
||||||
module: &module,
|
module: &module,
|
||||||
entry_point: "fs_main",
|
entry_point: "fs_main",
|
||||||
targets: &[wgpu::ColorTargetState {
|
targets: &[wgpu::ColorTargetState {
|
||||||
format: wgpu::TextureFormat::Bgra8UnormSrgb,
|
format: pixels.render_texture_format(),
|
||||||
blend: Some(wgpu::BlendState {
|
blend: Some(wgpu::BlendState {
|
||||||
color: wgpu::BlendComponent::REPLACE,
|
color: wgpu::BlendComponent::REPLACE,
|
||||||
alpha: wgpu::BlendComponent::REPLACE,
|
alpha: wgpu::BlendComponent::REPLACE,
|
||||||
|
@ -162,10 +163,10 @@ impl NoiseRenderer {
|
||||||
&self.texture_view
|
&self.texture_view
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn resize(&mut self, device: &wgpu::Device, width: u32, height: u32) {
|
pub(crate) fn resize(&mut self, pixels: &pixels::Pixels, width: u32, height: u32) {
|
||||||
self.texture_view = create_texture_view(device, width, height);
|
self.texture_view = create_texture_view(pixels, width, height);
|
||||||
self.bind_group = create_bind_group(
|
self.bind_group = create_bind_group(
|
||||||
device,
|
pixels.device(),
|
||||||
&self.bind_group_layout,
|
&self.bind_group_layout,
|
||||||
&self.texture_view,
|
&self.texture_view,
|
||||||
&self.sampler,
|
&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 {
|
let texture_descriptor = wgpu::TextureDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
size: pixels::wgpu::Extent3d {
|
size: pixels::wgpu::Extent3d {
|
||||||
|
@ -214,7 +216,7 @@ fn create_texture_view(device: &wgpu::Device, width: u32, height: u32) -> wgpu::
|
||||||
mip_level_count: 1,
|
mip_level_count: 1,
|
||||||
sample_count: 1,
|
sample_count: 1,
|
||||||
dimension: wgpu::TextureDimension::D2,
|
dimension: wgpu::TextureDimension::D2,
|
||||||
format: wgpu::TextureFormat::Bgra8UnormSrgb,
|
format: pixels.render_texture_format(),
|
||||||
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::RENDER_ATTACHMENT,
|
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::RENDER_ATTACHMENT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ pub(crate) struct Gui {
|
||||||
|
|
||||||
impl Gui {
|
impl Gui {
|
||||||
/// Create egui.
|
/// 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 {
|
let platform = Platform::new(PlatformDescriptor {
|
||||||
physical_width: width,
|
physical_width: width,
|
||||||
physical_height: height,
|
physical_height: height,
|
||||||
|
@ -32,7 +32,7 @@ impl Gui {
|
||||||
physical_height: height,
|
physical_height: height,
|
||||||
scale_factor: scale_factor as f32,
|
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 {
|
Self {
|
||||||
start_time: Instant::now(),
|
start_time: Instant::now(),
|
||||||
|
|
|
@ -43,12 +43,7 @@ fn main() -> Result<(), Error> {
|
||||||
let scale_factor = window.scale_factor();
|
let scale_factor = window.scale_factor();
|
||||||
let surface_texture = SurfaceTexture::new(window_size.width, window_size.height, &window);
|
let surface_texture = SurfaceTexture::new(window_size.width, window_size.height, &window);
|
||||||
let pixels = Pixels::new(WIDTH, HEIGHT, surface_texture)?;
|
let pixels = Pixels::new(WIDTH, HEIGHT, surface_texture)?;
|
||||||
let gui = Gui::new(
|
let gui = Gui::new(window_size.width, window_size.height, scale_factor, &pixels);
|
||||||
window_size.width,
|
|
||||||
window_size.height,
|
|
||||||
scale_factor,
|
|
||||||
pixels.context(),
|
|
||||||
);
|
|
||||||
|
|
||||||
(pixels, gui)
|
(pixels, gui)
|
||||||
};
|
};
|
||||||
|
|
|
@ -44,9 +44,8 @@ impl Gui {
|
||||||
// Create Dear ImGui WGPU renderer
|
// Create Dear ImGui WGPU renderer
|
||||||
let device = pixels.device();
|
let device = pixels.device();
|
||||||
let queue = pixels.queue();
|
let queue = pixels.queue();
|
||||||
let texture_format = wgpu::TextureFormat::Bgra8UnormSrgb;
|
|
||||||
let config = imgui_wgpu::RendererConfig {
|
let config = imgui_wgpu::RendererConfig {
|
||||||
texture_format,
|
texture_format: pixels.render_texture_format(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let renderer = imgui_wgpu::Renderer::new(&mut imgui, device, queue, config);
|
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,
|
present_mode: wgpu::PresentMode,
|
||||||
surface_texture: SurfaceTexture<'win, W>,
|
surface_texture: SurfaceTexture<'win, W>,
|
||||||
texture_format: wgpu::TextureFormat,
|
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> {
|
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,
|
present_mode: wgpu::PresentMode::Fifo,
|
||||||
surface_texture,
|
surface_texture,
|
||||||
texture_format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
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.
|
/// Set which backends wgpu will attempt to use.
|
||||||
///
|
///
|
||||||
/// The default value of this is [`wgpu::BackendBit::PRIMARY`], which enables
|
/// The default value is `PRIMARY`, which enables the well supported backends for wgpu.
|
||||||
/// the well supported backends for wgpu.
|
|
||||||
pub fn wgpu_backend(mut self, backend: wgpu::BackendBit) -> PixelsBuilder<'req, 'dev, 'win, W> {
|
pub fn wgpu_backend(mut self, backend: wgpu::BackendBit) -> PixelsBuilder<'req, 'dev, 'win, W> {
|
||||||
self.backend = backend;
|
self.backend = backend;
|
||||||
self
|
self
|
||||||
|
@ -144,9 +143,12 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W>
|
||||||
|
|
||||||
/// Set the texture format.
|
/// Set the texture format.
|
||||||
///
|
///
|
||||||
/// The default value is [`wgpu::TextureFormat::Rgba8UnormSrgb`], which is 4 unsigned bytes in
|
/// The default value is `Rgba8UnormSrgb`, which is 4 unsigned bytes in `RGBA` order using the
|
||||||
/// `RGBA` order using the SRGB color space. This is typically what you want when you are
|
/// sRGB color space. This is typically what you want when you are working with color values
|
||||||
/// working with color values from popular image editing tools or web apps.
|
/// 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(
|
pub fn texture_format(
|
||||||
mut self,
|
mut self,
|
||||||
texture_format: wgpu::TextureFormat,
|
texture_format: wgpu::TextureFormat,
|
||||||
|
@ -157,14 +159,27 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W>
|
||||||
|
|
||||||
/// Set the render texture format.
|
/// Set the render texture format.
|
||||||
///
|
///
|
||||||
/// The default value is [`wgpu::TextureFormat::Bgra8UnormSrgb`], which is 4 unsigned bytes in
|
/// The default value is chosen automatically by the swapchain (if it can) with a fallback to
|
||||||
/// `BGRA` order using the SRGB color space. This format depends on the hardware/platform the
|
/// `Bgra8UnormSrgb` (which is 4 unsigned bytes in `BGRA` order using the sRGB color space).
|
||||||
/// pixel buffer is rendered to/for.
|
/// 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(
|
pub fn render_texture_format(
|
||||||
mut self,
|
mut self,
|
||||||
texture_format: wgpu::TextureFormat,
|
texture_format: wgpu::TextureFormat,
|
||||||
) -> PixelsBuilder<'req, 'dev, 'win, W> {
|
) -> PixelsBuilder<'req, 'dev, 'win, W> {
|
||||||
self.render_texture_format = texture_format;
|
self.render_texture_format = Some(texture_format);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,13 +211,18 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W>
|
||||||
.map_err(Error::DeviceNotFound)?;
|
.map_err(Error::DeviceNotFound)?;
|
||||||
|
|
||||||
let present_mode = self.present_mode;
|
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
|
// Create swap chain
|
||||||
let surface_size = self.surface_texture.size;
|
let surface_size = self.surface_texture.size;
|
||||||
let swap_chain = create_swap_chain(
|
let swap_chain = create_swap_chain(
|
||||||
&mut device,
|
&mut device,
|
||||||
&surface,
|
&surface,
|
||||||
self.render_texture_format,
|
render_texture_format,
|
||||||
&surface_size,
|
&surface_size,
|
||||||
present_mode,
|
present_mode,
|
||||||
);
|
);
|
||||||
|
@ -217,7 +237,7 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W>
|
||||||
self.texture_format,
|
self.texture_format,
|
||||||
// Render texture values
|
// Render texture values
|
||||||
&surface_size,
|
&surface_size,
|
||||||
self.render_texture_format,
|
render_texture_format,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create the pixel buffer
|
// Create the pixel buffer
|
||||||
|
@ -241,9 +261,9 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W>
|
||||||
context,
|
context,
|
||||||
surface_size,
|
surface_size,
|
||||||
present_mode,
|
present_mode,
|
||||||
|
render_texture_format,
|
||||||
pixels,
|
pixels,
|
||||||
scaling_matrix_inverse,
|
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
|
&self.context.texture
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provides access to the internal [`PixelsContext`]
|
/// Provides access to the internal [`PixelsContext`].
|
||||||
pub fn context(&self) -> &PixelsContext {
|
pub fn context(&self) -> &PixelsContext {
|
||||||
&self.context
|
&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