diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 34700b6..bca0b7c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: rust: - stable - beta - - 1.61.0 + - 1.65.0 steps: - name: Checkout sources uses: actions/checkout@v3 @@ -73,7 +73,7 @@ jobs: rust: - stable - beta - - 1.61.0 + - 1.65.0 steps: - name: Checkout sources uses: actions/checkout@v3 diff --git a/Cargo.toml b/Cargo.toml index 0a2d7de..e23ee19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,10 +21,13 @@ include = [ [dependencies] bytemuck = "1.12" -raw-window-handle = "0.4" +raw-window-handle = "0.5" thiserror = "1.0" ultraviolet = "0.9" -wgpu = "0.13" +wgpu = "0.14" + +[target.'cfg(target_arch = "wasm32")'.dependencies] +wgpu = { version = "0.14", features = ["webgl"] } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] pollster = "0.2" diff --git a/MSRV.md b/MSRV.md index ec75ad3..d2124e9 100644 --- a/MSRV.md +++ b/MSRV.md @@ -2,7 +2,7 @@ | `pixels` version | `rustc` version | |------------------|-----------------| -| `0.11.0` | `1.61.0` | +| `0.11.0` | `1.65.0` | | `0.10.0` | `1.61.0` | | `0.9.0` | `1.57.0` | | `0.8.0` | `1.52.0` | diff --git a/README.md b/README.md index 9c8d30c..4da4c04 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,6 @@ The Minimum Supported Rust Version for `pixels` will always be made available in - [Dear ImGui example with `winit`](./examples/imgui-winit) - [Egui example with `winit`](./examples/minimal-egui) - [Minimal example for WebGL2](./examples/minimal-web) -- [Minimal example with SDL2](./examples/minimal-sdl2) - [Minimal example with `winit`](./examples/minimal-winit) - [Minimal example with `tao`](./examples/minimal-tao) - [Minimal example with `fltk`](./examples/minimal-fltk) diff --git a/examples/conway/src/main.rs b/examples/conway/src/main.rs index 24d4686..af717e2 100644 --- a/examples/conway/src/main.rs +++ b/examples/conway/src/main.rs @@ -196,7 +196,7 @@ impl Cell { fn cool_off(&mut self, decay: f32) { if !self.alive { - let heat = (self.heat as f32 * decay).min(255.0).max(0.0); + let heat = (self.heat as f32 * decay).clamp(0.0, 255.0); assert!(heat.is_finite()); self.heat = heat as u8; } @@ -313,8 +313,8 @@ impl ConwayGrid { // probably should do sutherland-hodgeman if this were more serious. // instead just clamp the start pos, and draw until moving towards the // end pos takes us out of bounds. - let x0 = x0.max(0).min(self.width as isize); - let y0 = y0.max(0).min(self.height as isize); + let x0 = x0.clamp(0, self.width as isize); + let y0 = y0.clamp(0, self.height as isize); for (x, y) in line_drawing::Bresenham::new((x0, y0), (x1, y1)) { if let Some(i) = self.grid_idx(x, y) { self.cells[i].set_alive(alive); diff --git a/examples/imgui-winit/Cargo.toml b/examples/imgui-winit/Cargo.toml index b858ac5..9d6b731 100644 --- a/examples/imgui-winit/Cargo.toml +++ b/examples/imgui-winit/Cargo.toml @@ -11,10 +11,10 @@ default = ["optimize"] [dependencies] env_logger = "0.9" -imgui = "0.8" -imgui-wgpu = "0.20" -imgui-winit-support = { version = "0.8", default-features = false, features = ["winit-26"] } +imgui = "0.9" +imgui-wgpu = "0.21" +imgui-winit-support = "0.9" log = "0.4" pixels = { path = "../.." } -winit = "0.26" -winit_input_helper = "0.12" +winit = "0.27" +winit_input_helper = "0.13" diff --git a/examples/imgui-winit/src/gui.rs b/examples/imgui-winit/src/gui.rs index 0b854ef..969d49d 100644 --- a/examples/imgui-winit/src/gui.rs +++ b/examples/imgui-winit/src/gui.rs @@ -87,14 +87,14 @@ impl Gui { let mouse_cursor = ui.mouse_cursor(); if self.last_cursor != mouse_cursor { self.last_cursor = mouse_cursor; - self.platform.prepare_render(&ui, window); + self.platform.prepare_render(ui, window); } // Draw windows and GUI elements here let mut about_open = false; ui.main_menu_bar(|| { ui.menu("Help", || { - about_open = imgui::MenuItem::new("About...").build(&ui); + about_open = ui.menu_item("About..."); }); }); if about_open { @@ -119,8 +119,12 @@ impl Gui { depth_stencil_attachment: None, }); - self.renderer - .render(ui.render(), &context.queue, &context.device, &mut rpass) + self.renderer.render( + self.imgui.render(), + &context.queue, + &context.device, + &mut rpass, + ) } /// Handle any outstanding events. diff --git a/examples/invaders/simple-invaders/src/loader.rs b/examples/invaders/simple-invaders/src/loader.rs index bf5033b..afc1be6 100644 --- a/examples/invaders/simple-invaders/src/loader.rs +++ b/examples/invaders/simple-invaders/src/loader.rs @@ -67,7 +67,7 @@ fn load_pcx(pcx: &[u8]) -> CachedSprite { let mut buffer = Vec::new(); buffer.resize_with(width * height, Default::default); for y in 0..height { - let a = y as usize * width; + let a = y * width; let b = a + width; reader.next_row_paletted(&mut buffer[a..b]).unwrap(); } diff --git a/examples/minimal-egui/Cargo.toml b/examples/minimal-egui/Cargo.toml index 168d644..99b102f 100644 --- a/examples/minimal-egui/Cargo.toml +++ b/examples/minimal-egui/Cargo.toml @@ -10,9 +10,9 @@ optimize = ["log/release_max_level_warn"] default = ["optimize"] [dependencies] -egui = "0.19" -egui-wgpu = "0.19" -egui-winit = { version = "0.19", default-features = false, features = ["links"] } +egui = "0.20" +egui-wgpu = "0.20" +egui-winit = { version = "0.20", default-features = false, features = ["links"] } env_logger = "0.9" log = "0.4" pixels = { path = "../.." } diff --git a/examples/minimal-egui/src/gui.rs b/examples/minimal-egui/src/gui.rs index 373bfb9..1f2a287 100644 --- a/examples/minimal-egui/src/gui.rs +++ b/examples/minimal-egui/src/gui.rs @@ -1,5 +1,5 @@ use egui::{ClippedPrimitive, Context, TexturesDelta}; -use egui_wgpu::renderer::{RenderPass, ScreenDescriptor}; +use egui_wgpu::renderer::{Renderer, ScreenDescriptor}; use pixels::{wgpu, PixelsContext}; use winit::event_loop::EventLoopWindowTarget; use winit::window::Window; @@ -10,7 +10,7 @@ pub(crate) struct Framework { egui_ctx: Context, egui_state: egui_winit::State, screen_descriptor: ScreenDescriptor, - rpass: RenderPass, + renderer: Renderer, paint_jobs: Vec, textures: TexturesDelta, @@ -43,7 +43,7 @@ impl Framework { size_in_pixels: [width, height], pixels_per_point: scale_factor, }; - let rpass = RenderPass::new(pixels.device(), pixels.render_texture_format(), 1); + let renderer = Renderer::new(pixels.device(), pixels.render_texture_format(), None, 1); let textures = TexturesDelta::default(); let gui = Gui::new(); @@ -51,7 +51,7 @@ impl Framework { egui_ctx, egui_state, screen_descriptor, - rpass, + renderer, paint_jobs: Vec::new(), textures, gui, @@ -60,7 +60,7 @@ impl Framework { /// Handle input events from the window manager. pub(crate) fn handle_event(&mut self, event: &winit::event::WindowEvent) { - self.egui_state.on_event(&self.egui_ctx, event); + let _ = self.egui_state.on_event(&self.egui_ctx, event); } /// Resize egui. @@ -99,29 +99,40 @@ impl Framework { ) { // Upload all resources to the GPU. for (id, image_delta) in &self.textures.set { - self.rpass + self.renderer .update_texture(&context.device, &context.queue, *id, image_delta); } - self.rpass.update_buffers( + self.renderer.update_buffers( &context.device, &context.queue, + encoder, &self.paint_jobs, &self.screen_descriptor, ); - // Record all render passes. - self.rpass.execute( - encoder, - render_target, - &self.paint_jobs, - &self.screen_descriptor, - None, - ); + // Render egui with WGPU + { + let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("egui"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: render_target, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color::BLACK), + store: true, + }, + })], + depth_stencil_attachment: None, + }); + + self.renderer + .render(&mut rpass, &self.paint_jobs, &self.screen_descriptor); + } // Cleanup let textures = std::mem::take(&mut self.textures); for id in &textures.free { - self.rpass.free_texture(id); + self.renderer.free_texture(id); } } } diff --git a/examples/minimal-fltk/Cargo.toml b/examples/minimal-fltk/Cargo.toml index 05ac517..d97b27d 100644 --- a/examples/minimal-fltk/Cargo.toml +++ b/examples/minimal-fltk/Cargo.toml @@ -10,7 +10,7 @@ optimize = ["log/release_max_level_warn"] default = ["optimize"] [dependencies] -fltk = { version = "=1.3.13", features = ["raw-window-handle", "no-images", "no-pango"] } +fltk = { version = "1.3.17", features = ["rwh05", "no-images", "no-pango"] } env_logger = "0.9" log = "0.4" pixels = { path = "../.." } diff --git a/examples/minimal-sdl2/Cargo.toml b/examples/minimal-sdl2/Cargo.toml deleted file mode 100644 index be041c6..0000000 --- a/examples/minimal-sdl2/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "minimal-sdl2" -version = "0.1.0" -authors = ["Jay Oster "] -edition = "2021" -publish = false - -[features] -optimize = ["log/release_max_level_warn"] -default = ["optimize"] - -[dependencies] -env_logger = "0.9" -fermium = { version = "20022.0.0", features = ["raw-window-handle"] } -log = "0.4" -pixels = { path = "../.." } -thiserror = "1.0" -zstring = "0.1" diff --git a/examples/minimal-sdl2/README.md b/examples/minimal-sdl2/README.md deleted file mode 100644 index 683fc31..0000000 --- a/examples/minimal-sdl2/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# Hello Pixels - -![Hello Pixels](../../img/minimal-sdl2.png) - -Minimal example with SDL2 using `beryllium`. - -## Running - -```bash -cargo run --release --package minimal-sdl2 -``` - -## About - -This example demonstrates the absolute minimum for creating an SDL2 window and pixel buffer. It animates a purple box moving on a blue background, just for _something_ interesting to display. diff --git a/examples/minimal-sdl2/src/main.rs b/examples/minimal-sdl2/src/main.rs deleted file mode 100644 index e201c3a..0000000 --- a/examples/minimal-sdl2/src/main.rs +++ /dev/null @@ -1,105 +0,0 @@ -#![deny(clippy::all)] -#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] - -use crate::sdl::{Event, Sdl}; -use pixels::{Pixels, SurfaceTexture}; -use zstring::zstr; - -mod sdl; - -const WIDTH: u32 = 320; -const HEIGHT: u32 = 240; -const BOX_SIZE: i16 = 64; - -/// Representation of the application state. In this example, a box will bounce around the screen. -struct World { - box_x: i16, - box_y: i16, - velocity_x: i16, - velocity_y: i16, -} - -fn main() -> Result<(), Box> { - env_logger::init(); - - let sdl = Sdl::new(zstr!("Hello Pixels"), WIDTH, HEIGHT)?; - - let mut pixels = { - let (width, height) = sdl.drawable_size(); - let surface_texture = SurfaceTexture::new(width, height, &sdl); - Pixels::new(WIDTH, HEIGHT, surface_texture)? - }; - let mut world = World::new(); - - 'game_loop: loop { - while let Some(event) = sdl.poll_event() { - match event { - // Close events - Event::Quit { .. } => break 'game_loop, - Event::Keyboard(key) if key == fermium::keycode::SDLK_ESCAPE => break 'game_loop, - - // Resize the window - Event::WindowResized { width, height, .. } => pixels.resize_surface(width, height), - - _ => (), - } - } - - // Update internal state - world.update(); - - // Draw the current frame - world.draw(pixels.get_frame_mut()); - pixels.render()?; - } - - Ok(()) -} - -impl World { - /// Create a new `World` instance that can draw a moving box. - fn new() -> Self { - Self { - box_x: 24, - box_y: 16, - velocity_x: 1, - velocity_y: 1, - } - } - - /// Update the `World` internal state; bounce the box around the screen. - fn update(&mut self) { - if self.box_x <= 0 || self.box_x + BOX_SIZE > WIDTH as i16 { - self.velocity_x *= -1; - } - if self.box_y <= 0 || self.box_y + BOX_SIZE > HEIGHT as i16 { - self.velocity_y *= -1; - } - - self.box_x += self.velocity_x; - self.box_y += self.velocity_y; - } - - /// Draw the `World` state to the frame buffer. - /// - /// Assumes the default texture format: `wgpu::TextureFormat::Rgba8UnormSrgb` - fn draw(&self, frame: &mut [u8]) { - for (i, pixel) in frame.chunks_exact_mut(4).enumerate() { - let x = (i % WIDTH as usize) as i16; - let y = (i / WIDTH as usize) as i16; - - let inside_the_box = x >= self.box_x - && x < self.box_x + BOX_SIZE - && y >= self.box_y - && y < self.box_y + BOX_SIZE; - - let rgba = if inside_the_box { - [0x5e, 0x48, 0xe8, 0xff] - } else { - [0x48, 0xb2, 0xe8, 0xff] - }; - - pixel.copy_from_slice(&rgba); - } - } -} diff --git a/examples/minimal-sdl2/src/sdl.rs b/examples/minimal-sdl2/src/sdl.rs deleted file mode 100644 index 216dea8..0000000 --- a/examples/minimal-sdl2/src/sdl.rs +++ /dev/null @@ -1,132 +0,0 @@ -//! This module implements the bare minimum of a high-level abstraction for SDL2 over fermium. -//! -//! We used to use beryllium, but that crate has lagged behind fermium in maintenance releases. - -use ::pixels::raw_window_handle::{HasRawWindowHandle, RawWindowHandle}; -use fermium::prelude::*; -use thiserror::Error; -use zstring::ZStr; - -pub struct Sdl { - sdl_win: *mut SDL_Window, - _winfo: SDL_SysWMinfo, - rwh: RawWindowHandle, -} - -#[derive(Debug, Error)] -pub enum SdlError { - #[error("SDL init failed")] - Init, - - #[error("Invalid pixel buffer size")] - Size, - - #[error("Create SDL window failed")] - Window, - - #[error("Create SDL WM Info failed")] - WMinfo, - - #[error("Create Window Handle failed")] - WindowHandle, -} - -#[derive(Debug)] -pub enum Event { - Quit, - Keyboard(SDL_Keycode), - WindowResized { width: u32, height: u32 }, -} - -impl Sdl { - pub fn new(title: ZStr, width: u32, height: u32) -> Result { - // SAFETY: Ensure SDL is initialized and we get a non-null Window pointer. - unsafe { - if SDL_Init(SDL_INIT_EVERYTHING) != 0 { - return Err(SdlError::Init); - } - - let window_type = if cfg!(target_os = "macos") { - SDL_WINDOW_METAL - } else { - SDL_WINDOW_VULKAN - }; - - let sdl_win = SDL_CreateWindow( - title.as_ptr() as *const i8, - SDL_WINDOWPOS_CENTERED, - SDL_WINDOWPOS_CENTERED, - width.try_into().map_err(|_| SdlError::Size)?, - height.try_into().map_err(|_| SdlError::Size)?, - (window_type | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE).0, - ); - if sdl_win.is_null() { - return Err(SdlError::Window); - } - - let mut winfo = SDL_SysWMinfo::default(); - if SDL_GetWindowWMInfo(sdl_win, &mut winfo) == SDL_FALSE { - return Err(SdlError::WMinfo); - } - - let rwh = winfo.try_into().ok_or(SdlError::WindowHandle)?; - - Ok(Self { - sdl_win, - _winfo: winfo, - rwh, - }) - } - } - - // XXX: Fermium doesn't support `SDL_Metal_GetDrawableSize` - #[cfg(not(target_os = "macos"))] - pub fn drawable_size(&self) -> (u32, u32) { - // SAFETY: We have a valid Vulkan window. - unsafe { - let mut width = 0; - let mut height = 0; - SDL_Vulkan_GetDrawableSize(self.sdl_win, &mut width, &mut height); - - (width.try_into().unwrap(), height.try_into().unwrap()) - } - } - - #[must_use] - pub fn poll_event(&self) -> Option { - let mut e = SDL_Event::default(); - if unsafe { SDL_PollEvent(&mut e) } == 0 { - None - } else { - Event::try_from(e).ok() - } - } -} - -unsafe impl HasRawWindowHandle for Sdl { - fn raw_window_handle(&self) -> RawWindowHandle { - self.rwh - } -} - -impl TryFrom for Event { - type Error = (); - - fn try_from(event: SDL_Event) -> Result { - // SAFETY: Only access union fields in when the combinations are known to be valid. - unsafe { - Ok(match event.type_ { - SDL_QUIT => Self::Quit, - SDL_KEYDOWN | SDL_KEYUP => Self::Keyboard(event.key.keysym.sym), - SDL_WINDOWEVENT => match event.window.event { - SDL_WINDOWEVENT_RESIZED => Self::WindowResized { - width: event.window.data1 as _, - height: event.window.data2 as _, - }, - _ => return Err(()), - }, - _ => return Err(()), - }) - } - } -} diff --git a/examples/minimal-tao/Cargo.toml b/examples/minimal-tao/Cargo.toml index 6a7f3a7..279e91a 100644 --- a/examples/minimal-tao/Cargo.toml +++ b/examples/minimal-tao/Cargo.toml @@ -13,4 +13,4 @@ default = ["optimize"] env_logger = "0.9" log = "0.4" pixels = { path = "../.." } -tao = "0.12" +tao = "0.15" diff --git a/examples/minimal-web/Cargo.toml b/examples/minimal-web/Cargo.toml index fb19b09..2e40bec 100644 --- a/examples/minimal-web/Cargo.toml +++ b/examples/minimal-web/Cargo.toml @@ -20,8 +20,7 @@ console_error_panic_hook = "0.1" console_log = "0.2" wasm-bindgen = "0.2" wasm-bindgen-futures = "0.4" -web-sys = "0.3" -wgpu = { version = "0.13", features = ["webgl"] } +web-sys = { version = "0.3", features = ["GpuTextureFormat"] } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] env_logger = "0.9" diff --git a/internals/pixels-mocks/Cargo.toml b/internals/pixels-mocks/Cargo.toml index 04e6c28..208c7fe 100644 --- a/internals/pixels-mocks/Cargo.toml +++ b/internals/pixels-mocks/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" publish = false [dependencies] -raw-window-handle = "0.4" +raw-window-handle = "0.5" diff --git a/internals/pixels-mocks/src/lib.rs b/internals/pixels-mocks/src/lib.rs index 1d2c727..6c17f12 100644 --- a/internals/pixels-mocks/src/lib.rs +++ b/internals/pixels-mocks/src/lib.rs @@ -5,7 +5,9 @@ pub struct Rwh; unsafe impl raw_window_handle::HasRawWindowHandle for Rwh { fn raw_window_handle(&self) -> raw_window_handle::RawWindowHandle { #[cfg(target_os = "macos")] - return raw_window_handle::RawWindowHandle::AppKit(raw_window_handle::AppKitHandle::empty()); + return raw_window_handle::RawWindowHandle::AppKit( + raw_window_handle::AppKitWindowHandle::empty(), + ); #[cfg(any( target_os = "linux", target_os = "dragonfly", @@ -14,11 +16,42 @@ unsafe impl raw_window_handle::HasRawWindowHandle for Rwh { target_os = "openbsd", ))] return raw_window_handle::RawWindowHandle::Wayland( - raw_window_handle::WaylandHandle::empty(), + raw_window_handle::WaylandWindowHandle::empty(), ); #[cfg(target_os = "windows")] - return raw_window_handle::RawWindowHandle::Win32(raw_window_handle::Win32Handle::empty()); + return raw_window_handle::RawWindowHandle::Win32( + raw_window_handle::Win32WindowHandle::empty(), + ); #[cfg(target_os = "ios")] - return raw_window_handle::RawWindowHandle::UiKit(raw_window_handle::UiKitHandle::empty()); + return raw_window_handle::RawWindowHandle::UiKit( + raw_window_handle::UiKitWindowHandle::empty(), + ); + } +} + +unsafe impl raw_window_handle::HasRawDisplayHandle for Rwh { + fn raw_display_handle(&self) -> raw_window_handle::RawDisplayHandle { + #[cfg(target_os = "macos")] + return raw_window_handle::RawDisplayHandle::AppKit( + raw_window_handle::AppKitDisplayHandle::empty(), + ); + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd", + ))] + return raw_window_handle::RawDisplayHandle::Wayland( + raw_window_handle::WaylandDisplayHandle::empty(), + ); + #[cfg(target_os = "windows")] + return raw_window_handle::RawDisplayHandle::Windows( + raw_window_handle::WindowsDisplayHandle::empty(), + ); + #[cfg(target_os = "ios")] + return raw_window_handle::RawDisplayHandle::UiKit( + raw_window_handle::UiKitDisplayHandle::empty(), + ); } } diff --git a/src/builder.rs b/src/builder.rs index 1bfa340..0dd392d 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1,10 +1,10 @@ use crate::renderers::{ScalingMatrix, ScalingRenderer}; use crate::SurfaceSize; use crate::{Error, Pixels, PixelsContext, SurfaceTexture}; -use raw_window_handle::HasRawWindowHandle; +use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle}; /// A builder to help create customized pixel buffers. -pub struct PixelsBuilder<'req, 'dev, 'win, W: HasRawWindowHandle> { +pub struct PixelsBuilder<'req, 'dev, 'win, W: HasRawWindowHandle + HasRawDisplayHandle> { request_adapter_options: Option>, device_descriptor: Option>, backend: wgpu::Backends, @@ -20,7 +20,9 @@ pub struct PixelsBuilder<'req, 'dev, 'win, W: HasRawWindowHandle> { blend_state: wgpu::BlendState, } -impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W> { +impl<'req, 'dev, 'win, W: HasRawWindowHandle + HasRawDisplayHandle> + PixelsBuilder<'req, 'dev, 'win, W> +{ /// Create a builder that can be finalized into a [`Pixels`] pixel buffer. /// /// # Examples @@ -325,6 +327,8 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W> let mut pixels = Vec::with_capacity(pixels_buffer_size); pixels.resize_with(pixels_buffer_size, Default::default); + let alpha_mode = surface.get_supported_alpha_modes(&adapter)[0]; + // Instantiate the Pixels struct let context = PixelsContext { device, @@ -346,6 +350,7 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W> blend_state, pixels, scaling_matrix_inverse, + alpha_mode, }; pixels.reconfigure_surface(); @@ -488,7 +493,8 @@ const fn get_texture_format_size(texture_format: wgpu::TextureFormat) -> f32 { | Rg8Snorm | Rg8Uint | Rg8Sint - | Rgb9e5Ufloat => 2.0, // 16.0 / 8.0 + | Rgb9e5Ufloat + | Depth16Unorm => 2.0, // 16.0 / 8.0 // 32-bit formats, 8 bits per component R32Uint @@ -510,8 +516,7 @@ const fn get_texture_format_size(texture_format: wgpu::TextureFormat) -> f32 { | Rg11b10Float | Depth32Float | Depth24Plus - | Depth24PlusStencil8 - | Depth24UnormStencil8 => 4.0, // 32.0 / 8.0 + | Depth24PlusStencil8 => 4.0, // 32.0 / 8.0 // 64-bit formats, 8 bits per component Rg32Uint diff --git a/src/lib.rs b/src/lib.rs index f8232ff..03ff580 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,7 +34,7 @@ pub use crate::builder::PixelsBuilder; pub use crate::renderers::ScalingRenderer; pub use raw_window_handle; -use raw_window_handle::HasRawWindowHandle; +use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle}; use std::num::NonZeroU32; use thiserror::Error; pub use wgpu; @@ -44,7 +44,7 @@ mod renderers; /// A logical texture for a window surface. #[derive(Debug)] -pub struct SurfaceTexture<'win, W: HasRawWindowHandle> { +pub struct SurfaceTexture<'win, W: HasRawWindowHandle + HasRawDisplayHandle> { window: &'win W, size: SurfaceSize, } @@ -99,6 +99,7 @@ pub struct Pixels { render_texture_format: wgpu::TextureFormat, surface_texture_format: wgpu::TextureFormat, blend_state: wgpu::BlendState, + alpha_mode: wgpu::CompositeAlphaMode, // Pixel buffer pixels: Vec, @@ -127,7 +128,7 @@ pub enum Error { type DynError = Box; -impl<'win, W: HasRawWindowHandle> SurfaceTexture<'win, W> { +impl<'win, W: HasRawWindowHandle + HasRawDisplayHandle> SurfaceTexture<'win, W> { /// Create a logical texture for a window surface. /// /// It is recommended (but not required) that the `width` and `height` are equivalent to the @@ -193,7 +194,7 @@ impl Pixels { /// /// Panics when `width` or `height` are 0. #[cfg(not(target_arch = "wasm32"))] - pub fn new( + pub fn new( width: u32, height: u32, surface_texture: SurfaceTexture<'_, W>, @@ -224,7 +225,7 @@ impl Pixels { /// # Panics /// /// Panics when `width` or `height` are 0. - pub async fn new_async( + pub async fn new_async( width: u32, height: u32, surface_texture: SurfaceTexture<'_, W>, @@ -487,6 +488,7 @@ impl Pixels { width: self.surface_size.width, height: self.surface_size.height, present_mode: self.present_mode, + alpha_mode: self.alpha_mode, }, ); } @@ -588,11 +590,9 @@ impl Pixels { pub fn clamp_pixel_pos(&self, pos: (isize, isize)) -> (usize, usize) { ( pos.0 - .max(0) - .min(self.context.texture_extent.width as isize - 1) as usize, + .clamp(0, self.context.texture_extent.width as isize - 1) as usize, pos.1 - .max(0) - .min(self.context.texture_extent.height as isize - 1) as usize, + .clamp(0, self.context.texture_extent.height as isize - 1) as usize, ) } diff --git a/src/renderers.rs b/src/renderers.rs index 73c6e0a..33e34be 100644 --- a/src/renderers.rs +++ b/src/renderers.rs @@ -232,8 +232,7 @@ impl ScalingMatrix { // Get smallest scale size let scale = (screen_width / texture_width) - .min(screen_height / texture_height) - .max(1.0) + .clamp(1.0, screen_height / texture_height) .floor(); let scaled_width = texture_width * scale;