parent
f845d59213
commit
26ae25c3d8
|
@ -26,10 +26,12 @@ struct World {
|
||||||
|
|
||||||
fn main() -> Result<(), Error> {
|
fn main() -> Result<(), Error> {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
let mut width = WIDTH;
|
||||||
|
let mut height = HEIGHT;
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
let mut input = WinitInputHelper::new();
|
let mut input = WinitInputHelper::new();
|
||||||
let window = {
|
let window = {
|
||||||
let size = LogicalSize::new(WIDTH as f64, HEIGHT as f64);
|
let size = LogicalSize::new(width as f64, height as f64);
|
||||||
WindowBuilder::new()
|
WindowBuilder::new()
|
||||||
.with_title("Hello Pixels + Dear ImGui")
|
.with_title("Hello Pixels + Dear ImGui")
|
||||||
.with_inner_size(size)
|
.with_inner_size(size)
|
||||||
|
@ -41,7 +43,7 @@ fn main() -> Result<(), Error> {
|
||||||
let mut pixels = {
|
let mut pixels = {
|
||||||
let window_size = window.inner_size();
|
let window_size = window.inner_size();
|
||||||
let surface_texture = SurfaceTexture::new(window_size.width, window_size.height, &window);
|
let surface_texture = SurfaceTexture::new(window_size.width, window_size.height, &window);
|
||||||
Pixels::new(WIDTH, HEIGHT, surface_texture)?
|
Pixels::new(width, height, surface_texture)?
|
||||||
};
|
};
|
||||||
let mut world = World::new();
|
let mut world = World::new();
|
||||||
|
|
||||||
|
@ -52,7 +54,7 @@ fn main() -> Result<(), Error> {
|
||||||
// Draw the current frame
|
// Draw the current frame
|
||||||
if let Event::RedrawRequested(_) = event {
|
if let Event::RedrawRequested(_) = event {
|
||||||
// Draw the world
|
// Draw the world
|
||||||
world.draw(pixels.get_frame());
|
world.draw(pixels.get_frame(), width);
|
||||||
|
|
||||||
// Prepare Dear ImGui
|
// Prepare Dear ImGui
|
||||||
gui.prepare(&window).expect("gui.prepare() failed");
|
gui.prepare(&window).expect("gui.prepare() failed");
|
||||||
|
@ -89,10 +91,13 @@ 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(size.width, size.height);
|
pixels.resize(size.width, size.height);
|
||||||
|
width = size.width;
|
||||||
|
height = size.height;
|
||||||
|
pixels.resize_buffer(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update internal state and request a redraw
|
// Update internal state and request a redraw
|
||||||
world.update();
|
world.update(width, height);
|
||||||
window.request_redraw();
|
window.request_redraw();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -110,12 +115,18 @@ impl World {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the `World` internal state; bounce the box around the screen.
|
/// Update the `World` internal state; bounce the box around the screen.
|
||||||
fn update(&mut self) {
|
fn update(&mut self, width: u32, height: u32) {
|
||||||
if self.box_x <= 0 || self.box_x + BOX_SIZE > WIDTH as i16 {
|
if self.box_x <= 0 {
|
||||||
self.velocity_x *= -1;
|
self.velocity_x = 1;
|
||||||
}
|
}
|
||||||
if self.box_y <= 0 || self.box_y + BOX_SIZE > HEIGHT as i16 {
|
if self.box_x + BOX_SIZE > width as i16 {
|
||||||
self.velocity_y *= -1;
|
self.velocity_x = -1;
|
||||||
|
}
|
||||||
|
if self.box_y <= 0 {
|
||||||
|
self.velocity_y = 1;
|
||||||
|
}
|
||||||
|
if self.box_y + BOX_SIZE > height as i16 {
|
||||||
|
self.velocity_y = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.box_x += self.velocity_x;
|
self.box_x += self.velocity_x;
|
||||||
|
@ -125,10 +136,10 @@ impl World {
|
||||||
/// Draw the `World` state to the frame buffer.
|
/// Draw the `World` state to the frame buffer.
|
||||||
///
|
///
|
||||||
/// Assumes the default texture format: `wgpu::TextureFormat::Rgba8UnormSrgb`
|
/// Assumes the default texture format: `wgpu::TextureFormat::Rgba8UnormSrgb`
|
||||||
fn draw(&self, frame: &mut [u8]) {
|
fn draw(&self, frame: &mut [u8], width: u32) {
|
||||||
for (i, pixel) in frame.chunks_exact_mut(4).enumerate() {
|
for (i, pixel) in frame.chunks_exact_mut(4).enumerate() {
|
||||||
let x = (i % WIDTH as usize) as i16;
|
let x = (i % width as usize) as i16;
|
||||||
let y = (i / WIDTH as usize) as i16;
|
let y = (i / width as usize) as i16;
|
||||||
|
|
||||||
let inside_the_box = x >= self.box_x
|
let inside_the_box = x >= self.box_x
|
||||||
&& x < self.box_x + BOX_SIZE
|
&& x < self.box_x + BOX_SIZE
|
||||||
|
|
157
src/builder.rs
157
src/builder.rs
|
@ -1,4 +1,5 @@
|
||||||
use crate::renderers::{ScalingMatrix, ScalingRenderer};
|
use crate::renderers::{ScalingMatrix, ScalingRenderer};
|
||||||
|
use crate::SurfaceSize;
|
||||||
use crate::{Error, Pixels, PixelsContext, SurfaceTexture};
|
use crate::{Error, Pixels, PixelsContext, SurfaceTexture};
|
||||||
use raw_window_handle::HasRawWindowHandle;
|
use raw_window_handle::HasRawWindowHandle;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
@ -184,66 +185,40 @@ impl<'req, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'win, W> {
|
||||||
));
|
));
|
||||||
let adapter = pollster::block_on(adapter).ok_or(Error::AdapterNotFound)?;
|
let adapter = pollster::block_on(adapter).ok_or(Error::AdapterNotFound)?;
|
||||||
|
|
||||||
let (device, queue) =
|
let (mut device, queue) =
|
||||||
pollster::block_on(adapter.request_device(&self.device_descriptor, None))
|
pollster::block_on(adapter.request_device(&self.device_descriptor, None))
|
||||||
.map_err(Error::DeviceNotFound)?;
|
.map_err(Error::DeviceNotFound)?;
|
||||||
|
|
||||||
// The rest of this is technically a fixed-function pipeline... For now!
|
|
||||||
|
|
||||||
// Create a texture
|
|
||||||
let width = self.width;
|
|
||||||
let height = self.height;
|
|
||||||
let texture_extent = wgpu::Extent3d {
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
depth: 1,
|
|
||||||
};
|
|
||||||
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
|
||||||
label: Some("pixels_source_texture"),
|
|
||||||
size: texture_extent,
|
|
||||||
mip_level_count: 1,
|
|
||||||
sample_count: 1,
|
|
||||||
dimension: wgpu::TextureDimension::D2,
|
|
||||||
format: self.texture_format,
|
|
||||||
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::COPY_DST,
|
|
||||||
});
|
|
||||||
let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
|
||||||
let texture_format_size = get_texture_format_size(self.texture_format);
|
|
||||||
|
|
||||||
// Create the pixel buffer
|
|
||||||
let capacity = ((width * height) as f32 * texture_format_size) as usize;
|
|
||||||
let mut pixels = Vec::with_capacity(capacity);
|
|
||||||
pixels.resize_with(capacity, Default::default);
|
|
||||||
|
|
||||||
let present_mode = self.present_mode;
|
let present_mode = self.present_mode;
|
||||||
|
|
||||||
// Create swap chain
|
// Create swap chain
|
||||||
let surface_size = self.surface_texture.size;
|
let surface_size = self.surface_texture.size;
|
||||||
let swap_chain = device.create_swap_chain(
|
let swap_chain = create_swap_chain(
|
||||||
|
&mut device,
|
||||||
&surface,
|
&surface,
|
||||||
&wgpu::SwapChainDescriptor {
|
|
||||||
usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
|
|
||||||
format: self.render_texture_format,
|
|
||||||
width: surface_size.width,
|
|
||||||
height: surface_size.height,
|
|
||||||
present_mode,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let scaling_matrix_inverse = ScalingMatrix::new(
|
|
||||||
(width as f32, height as f32),
|
|
||||||
(surface_size.width as f32, surface_size.height as f32),
|
|
||||||
)
|
|
||||||
.transform
|
|
||||||
.inversed();
|
|
||||||
|
|
||||||
let scaling_renderer = ScalingRenderer::new(
|
|
||||||
&device,
|
|
||||||
&texture_view,
|
|
||||||
&texture_extent,
|
|
||||||
self.render_texture_format,
|
self.render_texture_format,
|
||||||
|
&surface_size,
|
||||||
|
present_mode,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Create the backing texture
|
||||||
|
let (scaling_matrix_inverse, texture_extent, texture, scaling_renderer, pixels_buffer_size) =
|
||||||
|
create_backing_texture(
|
||||||
|
&device,
|
||||||
|
// Backing texture values
|
||||||
|
self.width,
|
||||||
|
self.height,
|
||||||
|
self.texture_format,
|
||||||
|
// Render texture values
|
||||||
|
&surface_size,
|
||||||
|
self.render_texture_format,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create the pixel buffer
|
||||||
|
let mut pixels = Vec::with_capacity(pixels_buffer_size);
|
||||||
|
pixels.resize_with(pixels_buffer_size, Default::default);
|
||||||
|
|
||||||
|
// Instantiate the Pixels struct
|
||||||
let context = PixelsContext {
|
let context = PixelsContext {
|
||||||
device,
|
device,
|
||||||
queue,
|
queue,
|
||||||
|
@ -251,7 +226,8 @@ impl<'req, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'win, W> {
|
||||||
swap_chain,
|
swap_chain,
|
||||||
texture,
|
texture,
|
||||||
texture_extent,
|
texture_extent,
|
||||||
texture_format_size,
|
texture_format: self.texture_format,
|
||||||
|
texture_format_size: get_texture_format_size(self.texture_format),
|
||||||
scaling_renderer,
|
scaling_renderer,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -266,7 +242,86 @@ impl<'req, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'win, W> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_texture_format_size(texture_format: wgpu::TextureFormat) -> f32 {
|
pub(crate) fn create_swap_chain(
|
||||||
|
device: &mut wgpu::Device,
|
||||||
|
surface: &wgpu::Surface,
|
||||||
|
format: wgpu::TextureFormat,
|
||||||
|
surface_size: &SurfaceSize,
|
||||||
|
// width: u32,
|
||||||
|
// height: u32,
|
||||||
|
present_mode: wgpu::PresentMode,
|
||||||
|
) -> wgpu::SwapChain {
|
||||||
|
device.create_swap_chain(
|
||||||
|
&surface,
|
||||||
|
&wgpu::SwapChainDescriptor {
|
||||||
|
usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
|
||||||
|
format,
|
||||||
|
width: surface_size.width,
|
||||||
|
height: surface_size.height,
|
||||||
|
present_mode,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn create_backing_texture(
|
||||||
|
device: &wgpu::Device,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
backing_texture_format: wgpu::TextureFormat,
|
||||||
|
surface_size: &SurfaceSize,
|
||||||
|
render_texture_format: wgpu::TextureFormat,
|
||||||
|
) -> (
|
||||||
|
ultraviolet::Mat4,
|
||||||
|
wgpu::Extent3d,
|
||||||
|
wgpu::Texture,
|
||||||
|
ScalingRenderer,
|
||||||
|
usize,
|
||||||
|
) {
|
||||||
|
let scaling_matrix_inverse = ScalingMatrix::new(
|
||||||
|
(width as f32, height as f32),
|
||||||
|
(surface_size.width as f32, surface_size.height as f32),
|
||||||
|
)
|
||||||
|
.transform
|
||||||
|
.inversed();
|
||||||
|
|
||||||
|
let texture_extent = wgpu::Extent3d {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
depth: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||||
|
label: Some("pixels_source_texture"),
|
||||||
|
size: texture_extent,
|
||||||
|
mip_level_count: 1,
|
||||||
|
sample_count: 1,
|
||||||
|
dimension: wgpu::TextureDimension::D2,
|
||||||
|
format: backing_texture_format,
|
||||||
|
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::COPY_DST,
|
||||||
|
});
|
||||||
|
let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
|
|
||||||
|
let scaling_renderer = ScalingRenderer::new(
|
||||||
|
device,
|
||||||
|
&texture_view,
|
||||||
|
&texture_extent,
|
||||||
|
render_texture_format,
|
||||||
|
);
|
||||||
|
|
||||||
|
let texture_format_size = get_texture_format_size(backing_texture_format);
|
||||||
|
let pixels_buffer_size = ((width * height) as f32 * texture_format_size) as usize;
|
||||||
|
|
||||||
|
(
|
||||||
|
scaling_matrix_inverse,
|
||||||
|
texture_extent,
|
||||||
|
texture,
|
||||||
|
scaling_renderer,
|
||||||
|
pixels_buffer_size,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
const fn get_texture_format_size(texture_format: wgpu::TextureFormat) -> f32 {
|
||||||
match texture_format {
|
match texture_format {
|
||||||
// 8-bit formats
|
// 8-bit formats
|
||||||
wgpu::TextureFormat::R8Unorm
|
wgpu::TextureFormat::R8Unorm
|
||||||
|
|
57
src/lib.rs
57
src/lib.rs
|
@ -74,6 +74,7 @@ pub struct PixelsContext {
|
||||||
|
|
||||||
/// Provides access to the texture size.
|
/// Provides access to the texture size.
|
||||||
pub texture_extent: wgpu::Extent3d,
|
pub texture_extent: wgpu::Extent3d,
|
||||||
|
pub texture_format: wgpu::TextureFormat,
|
||||||
|
|
||||||
/// Defines the "data rate" for the raw texture data. This is effectively the "bytes per pixel"
|
/// Defines the "data rate" for the raw texture data. This is effectively the "bytes per pixel"
|
||||||
/// count.
|
/// count.
|
||||||
|
@ -182,6 +183,31 @@ impl Pixels {
|
||||||
PixelsBuilder::new(width, height, surface_texture).build()
|
PixelsBuilder::new(width, height, surface_texture).build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resize the pixel buffer, this doesn't resize the surface upon which the pixel buffer is rendered.
|
||||||
|
pub fn resize_buffer(&mut self, width: u32, height: u32) {
|
||||||
|
// Recreate the backing texture
|
||||||
|
let (scaling_matrix_inverse, texture_extent, texture, scaling_renderer, pixels_buffer_size) =
|
||||||
|
builder::create_backing_texture(
|
||||||
|
&self.context.device,
|
||||||
|
// Backing texture values
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
self.context.texture_format,
|
||||||
|
// Render texture values
|
||||||
|
&self.surface_size,
|
||||||
|
self.render_texture_format,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.scaling_matrix_inverse = scaling_matrix_inverse;
|
||||||
|
self.context.texture_extent = texture_extent;
|
||||||
|
self.context.texture = texture;
|
||||||
|
self.context.scaling_renderer = scaling_renderer;
|
||||||
|
|
||||||
|
// Resize the pixel buffer
|
||||||
|
self.pixels
|
||||||
|
.resize_with(pixels_buffer_size, Default::default);
|
||||||
|
}
|
||||||
|
|
||||||
/// Resize the surface upon which the pixel buffer is rendered.
|
/// Resize the surface upon which the pixel buffer is rendered.
|
||||||
///
|
///
|
||||||
/// This does not resize the pixel buffer. The pixel buffer will be fit onto the surface as
|
/// This does not resize the pixel buffer. The pixel buffer will be fit onto the surface as
|
||||||
|
@ -206,16 +232,7 @@ impl Pixels {
|
||||||
.inversed();
|
.inversed();
|
||||||
|
|
||||||
// Recreate the swap chain
|
// Recreate the swap chain
|
||||||
self.context.swap_chain = self.context.device.create_swap_chain(
|
self.recreate_swap_chain();
|
||||||
&self.context.surface,
|
|
||||||
&wgpu::SwapChainDescriptor {
|
|
||||||
usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
|
|
||||||
format: self.render_texture_format,
|
|
||||||
width: self.surface_size.width,
|
|
||||||
height: self.surface_size.height,
|
|
||||||
present_mode: self.present_mode,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// Update state for all render passes
|
// Update state for all render passes
|
||||||
self.context
|
self.context
|
||||||
|
@ -300,6 +317,15 @@ impl Pixels {
|
||||||
.context
|
.context
|
||||||
.swap_chain
|
.swap_chain
|
||||||
.get_current_frame()
|
.get_current_frame()
|
||||||
|
.or_else(|err| match err {
|
||||||
|
wgpu::SwapChainError::Outdated => {
|
||||||
|
// Recreate the swap chain to mitigate race condition on drawing surface resize.
|
||||||
|
// See https://github.com/parasyte/pixels/issues/121
|
||||||
|
self.recreate_swap_chain();
|
||||||
|
self.context.swap_chain.get_current_frame()
|
||||||
|
}
|
||||||
|
err => Err(err),
|
||||||
|
})
|
||||||
.map_err(Error::Swapchain)?;
|
.map_err(Error::Swapchain)?;
|
||||||
let mut encoder =
|
let mut encoder =
|
||||||
self.context
|
self.context
|
||||||
|
@ -333,6 +359,17 @@ impl Pixels {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Re-create the swap chain with its own values
|
||||||
|
pub(crate) fn recreate_swap_chain(&mut self) {
|
||||||
|
self.context.swap_chain = builder::create_swap_chain(
|
||||||
|
&mut self.context.device,
|
||||||
|
&self.context.surface,
|
||||||
|
self.render_texture_format,
|
||||||
|
&self.surface_size,
|
||||||
|
self.present_mode,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a mutable byte slice for the pixel buffer. The buffer is _not_ cleared for you; it will
|
/// Get a mutable byte slice for the pixel buffer. The buffer is _not_ cleared for you; it will
|
||||||
/// retain the previous frame's contents until you clear it yourself.
|
/// retain the previous frame's contents until you clear it yourself.
|
||||||
pub fn get_frame(&mut self) -> &mut [u8] {
|
pub fn get_frame(&mut self) -> &mut [u8] {
|
||||||
|
|
Loading…
Reference in a new issue