Update wgpu to 0.13 (#300)
* Intial work towards wgpu 0.13 * Increase MSRV for egui * Add missing texture formats * Update fermium - Replaces beryllium with our own hand-rolled high-level abstraction layer for SDL2. * Update dependencies Co-authored-by: JMS55 <47158642+JMS55@users.noreply.github.com>
This commit is contained in:
parent
bcbe9d84cb
commit
051a523ee6
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
|
@ -13,7 +13,7 @@ jobs:
|
||||||
rust:
|
rust:
|
||||||
- stable
|
- stable
|
||||||
- beta
|
- beta
|
||||||
- 1.60.0
|
- 1.61.0
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
@ -73,7 +73,7 @@ jobs:
|
||||||
rust:
|
rust:
|
||||||
- stable
|
- stable
|
||||||
- beta
|
- beta
|
||||||
- 1.60.0
|
- 1.61.0
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
|
@ -20,11 +20,11 @@ include = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bytemuck = "1.7"
|
bytemuck = "1.12"
|
||||||
raw-window-handle = "0.4"
|
raw-window-handle = "0.4"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
ultraviolet = "0.9"
|
ultraviolet = "0.9"
|
||||||
wgpu = "0.12"
|
wgpu = "0.13"
|
||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
pollster = "0.2"
|
pollster = "0.2"
|
||||||
|
|
2
MSRV.md
2
MSRV.md
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
| `pixels` version | `rustc` version |
|
| `pixels` version | `rustc` version |
|
||||||
|------------------|-----------------|
|
|------------------|-----------------|
|
||||||
| `0.10.0` | `1.60.0` |
|
| `0.10.0` | `1.61.0` |
|
||||||
| `0.9.0` | `1.57.0` |
|
| `0.9.0` | `1.57.0` |
|
||||||
| `0.8.0` | `1.52.0` |
|
| `0.8.0` | `1.52.0` |
|
||||||
| `0.7.0` | `1.52.0` |
|
| `0.7.0` | `1.52.0` |
|
||||||
|
|
|
@ -10,7 +10,7 @@ optimize = ["log/release_max_level_warn"]
|
||||||
default = ["optimize"]
|
default = ["optimize"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
byteorder = "1.3"
|
byteorder = "1.4"
|
||||||
env_logger = "0.9"
|
env_logger = "0.9"
|
||||||
getrandom = "0.2"
|
getrandom = "0.2"
|
||||||
line_drawing = "1.0"
|
line_drawing = "1.0"
|
||||||
|
|
|
@ -10,7 +10,7 @@ optimize = ["log/release_max_level_warn"]
|
||||||
default = ["optimize"]
|
default = ["optimize"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bytemuck = "1.7"
|
bytemuck = "1.10"
|
||||||
env_logger = "0.9"
|
env_logger = "0.9"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pixels = { path = "../.." }
|
pixels = { path = "../.." }
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
// Vertex shader bindings
|
// Vertex shader bindings
|
||||||
|
|
||||||
struct VertexOutput {
|
struct VertexOutput {
|
||||||
[[location(0)]] tex_coord: vec2<f32>;
|
@location(0) tex_coord: vec2<f32>,
|
||||||
[[builtin(position)]] position: vec4<f32>;
|
@builtin(position) position: vec4<f32>,
|
||||||
};
|
}
|
||||||
|
|
||||||
[[stage(vertex)]]
|
@vertex
|
||||||
fn vs_main(
|
fn vs_main(
|
||||||
[[location(0)]] position: vec2<f32>,
|
@location(0) position: vec2<f32>,
|
||||||
) -> VertexOutput {
|
) -> VertexOutput {
|
||||||
var out: VertexOutput;
|
var out: VertexOutput;
|
||||||
out.tex_coord = fma(position, vec2<f32>(0.5, -0.5), vec2<f32>(0.5, 0.5));
|
out.tex_coord = fma(position, vec2<f32>(0.5, -0.5), vec2<f32>(0.5, 0.5));
|
||||||
|
@ -17,12 +17,12 @@ fn vs_main(
|
||||||
|
|
||||||
// Fragment shader bindings
|
// Fragment shader bindings
|
||||||
|
|
||||||
[[group(0), binding(0)]] var r_tex_color: texture_2d<f32>;
|
@group(0) @binding(0) var r_tex_color: texture_2d<f32>;
|
||||||
[[group(0), binding(1)]] var r_tex_sampler: sampler;
|
@group(0) @binding(1) var r_tex_sampler: sampler;
|
||||||
struct Locals {
|
struct Locals {
|
||||||
time: f32;
|
time: f32,
|
||||||
};
|
}
|
||||||
[[group(0), binding(2)]] var<uniform> r_locals: Locals;
|
@group(0) @binding(2) var<uniform> r_locals: Locals;
|
||||||
|
|
||||||
let tau: f32 = 6.283185307179586476925286766559;
|
let tau: f32 = 6.283185307179586476925286766559;
|
||||||
let bias: f32 = 0.2376; // Offset the circular time input so it is never 0
|
let bias: f32 = 0.2376; // Offset the circular time input so it is never 0
|
||||||
|
@ -40,8 +40,8 @@ fn random_vec2(st: vec2<f32>) -> f32 {
|
||||||
return random(dot(st, vec2<f32>(random_x, random_y)));
|
return random(dot(st, vec2<f32>(random_x, random_y)));
|
||||||
}
|
}
|
||||||
|
|
||||||
[[stage(fragment)]]
|
@fragment
|
||||||
fn fs_main([[location(0)]] tex_coord: vec2<f32>) -> [[location(0)]] vec4<f32> {
|
fn fs_main(@location(0) tex_coord: vec2<f32>) -> @location(0) vec4<f32> {
|
||||||
let sampled_color = textureSample(r_tex_color, r_tex_sampler, tex_coord);
|
let sampled_color = textureSample(r_tex_color, r_tex_sampler, tex_coord);
|
||||||
let noise_color = vec3<f32>(random_vec2(tex_coord.xy * vec2<f32>(r_locals.time % tau + bias)));
|
let noise_color = vec3<f32>(random_vec2(tex_coord.xy * vec2<f32>(r_locals.time % tau + bias)));
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ impl NoiseRenderer {
|
||||||
pub(crate) fn new(pixels: &pixels::Pixels, width: u32, height: u32) -> Self {
|
pub(crate) fn new(pixels: &pixels::Pixels, width: u32, height: u32) -> Self {
|
||||||
let device = pixels.device();
|
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
|
||||||
|
@ -127,14 +127,14 @@ impl NoiseRenderer {
|
||||||
fragment: Some(wgpu::FragmentState {
|
fragment: Some(wgpu::FragmentState {
|
||||||
module: &module,
|
module: &module,
|
||||||
entry_point: "fs_main",
|
entry_point: "fs_main",
|
||||||
targets: &[wgpu::ColorTargetState {
|
targets: &[Some(wgpu::ColorTargetState {
|
||||||
format: pixels.render_texture_format(),
|
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,
|
||||||
}),
|
}),
|
||||||
write_mask: wgpu::ColorWrites::ALL,
|
write_mask: wgpu::ColorWrites::ALL,
|
||||||
}],
|
})],
|
||||||
}),
|
}),
|
||||||
multiview: None,
|
multiview: None,
|
||||||
});
|
});
|
||||||
|
@ -181,14 +181,14 @@ impl NoiseRenderer {
|
||||||
) {
|
) {
|
||||||
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
label: Some("NoiseRenderer render pass"),
|
label: Some("NoiseRenderer render pass"),
|
||||||
color_attachments: &[wgpu::RenderPassColorAttachment {
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
view: render_target,
|
view: render_target,
|
||||||
resolve_target: None,
|
resolve_target: None,
|
||||||
ops: wgpu::Operations {
|
ops: wgpu::Operations {
|
||||||
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
|
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
|
||||||
store: true,
|
store: true,
|
||||||
},
|
},
|
||||||
}],
|
})],
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
});
|
});
|
||||||
rpass.set_pipeline(&self.render_pipeline);
|
rpass.set_pipeline(&self.render_pipeline);
|
||||||
|
|
|
@ -12,7 +12,7 @@ default = ["optimize"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
env_logger = "0.9"
|
env_logger = "0.9"
|
||||||
imgui = "0.8"
|
imgui = "0.8"
|
||||||
imgui-wgpu = "0.19"
|
imgui-wgpu = "0.20"
|
||||||
imgui-winit-support = { version = "0.8", default-features = false, features = ["winit-26"] }
|
imgui-winit-support = { version = "0.8", default-features = false, features = ["winit-26"] }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pixels = { path = "../.." }
|
pixels = { path = "../.." }
|
||||||
|
|
|
@ -108,14 +108,14 @@ impl Gui {
|
||||||
// Render Dear ImGui with WGPU
|
// Render Dear ImGui with WGPU
|
||||||
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
label: Some("imgui"),
|
label: Some("imgui"),
|
||||||
color_attachments: &[wgpu::RenderPassColorAttachment {
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
view: render_target,
|
view: render_target,
|
||||||
resolve_target: None,
|
resolve_target: None,
|
||||||
ops: wgpu::Operations {
|
ops: wgpu::Operations {
|
||||||
load: wgpu::LoadOp::Load,
|
load: wgpu::LoadOp::Load,
|
||||||
store: true,
|
store: true,
|
||||||
},
|
},
|
||||||
}],
|
})],
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,9 @@ optimize = ["log/release_max_level_warn"]
|
||||||
default = ["optimize"]
|
default = ["optimize"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
egui = "0.18"
|
egui = { git = "https://github.com/emilk/egui.git", rev = "38a67f86467f16084443258ae5e7761429c00db2" }
|
||||||
egui-wgpu = "0.18"
|
egui-wgpu = { git = "https://github.com/emilk/egui.git", rev = "38a67f86467f16084443258ae5e7761429c00db2" }
|
||||||
egui-winit = { version = "0.18", default-features = false, features = ["links"] }
|
egui-winit = { git = "https://github.com/emilk/egui.git", rev = "38a67f86467f16084443258ae5e7761429c00db2", default-features = false, features = ["links"] }
|
||||||
env_logger = "0.9"
|
env_logger = "0.9"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pixels = { path = "../.." }
|
pixels = { path = "../.." }
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use egui::{ClippedPrimitive, Context, TexturesDelta};
|
use egui::{ClippedPrimitive, Context, TexturesDelta};
|
||||||
use egui_wgpu::renderer::{RenderPass, ScreenDescriptor};
|
use egui_wgpu::renderer::{RenderPass, ScreenDescriptor};
|
||||||
use pixels::{wgpu, PixelsContext};
|
use pixels::{wgpu, PixelsContext};
|
||||||
|
use winit::event_loop::EventLoopWindowTarget;
|
||||||
use winit::window::Window;
|
use winit::window::Window;
|
||||||
|
|
||||||
/// Manages all state required for rendering egui over `Pixels`.
|
/// Manages all state required for rendering egui over `Pixels`.
|
||||||
|
@ -25,11 +26,19 @@ struct Gui {
|
||||||
|
|
||||||
impl Framework {
|
impl Framework {
|
||||||
/// Create egui.
|
/// Create egui.
|
||||||
pub(crate) fn new(width: u32, height: u32, scale_factor: f32, pixels: &pixels::Pixels) -> Self {
|
pub(crate) fn new<T>(
|
||||||
|
event_loop: &EventLoopWindowTarget<T>,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
scale_factor: f32,
|
||||||
|
pixels: &pixels::Pixels,
|
||||||
|
) -> Self {
|
||||||
let max_texture_size = pixels.device().limits().max_texture_dimension_2d as usize;
|
let max_texture_size = pixels.device().limits().max_texture_dimension_2d as usize;
|
||||||
|
|
||||||
let egui_ctx = Context::default();
|
let egui_ctx = Context::default();
|
||||||
let egui_state = egui_winit::State::from_pixels_per_point(max_texture_size, scale_factor);
|
let mut egui_state = egui_winit::State::new(event_loop);
|
||||||
|
egui_state.set_max_texture_side(max_texture_size);
|
||||||
|
egui_state.set_pixels_per_point(scale_factor);
|
||||||
let screen_descriptor = ScreenDescriptor {
|
let screen_descriptor = ScreenDescriptor {
|
||||||
size_in_pixels: [width, height],
|
size_in_pixels: [width, height],
|
||||||
pixels_per_point: scale_factor,
|
pixels_per_point: scale_factor,
|
||||||
|
|
|
@ -43,8 +43,13 @@ fn main() -> Result<(), Error> {
|
||||||
let scale_factor = window.scale_factor() as f32;
|
let scale_factor = window.scale_factor() as f32;
|
||||||
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 framework =
|
let framework = Framework::new(
|
||||||
Framework::new(window_size.width, window_size.height, scale_factor, &pixels);
|
&event_loop,
|
||||||
|
window_size.width,
|
||||||
|
window_size.height,
|
||||||
|
scale_factor,
|
||||||
|
&pixels,
|
||||||
|
);
|
||||||
|
|
||||||
(pixels, framework)
|
(pixels, framework)
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,7 +10,7 @@ optimize = ["log/release_max_level_warn"]
|
||||||
default = ["optimize"]
|
default = ["optimize"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
fltk = { version = "1.2", features = ["raw-window-handle", "no-images", "no-pango"] }
|
fltk = { version = "1.3", features = ["raw-window-handle", "no-images", "no-pango"] }
|
||||||
env_logger = "0.9"
|
env_logger = "0.9"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pixels = { path = "../.." }
|
pixels = { path = "../.." }
|
||||||
|
|
|
@ -10,9 +10,9 @@ optimize = ["log/release_max_level_warn"]
|
||||||
default = ["optimize"]
|
default = ["optimize"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
beryllium = { version = "0.7", features = ["use-raw-window-handle"] }
|
|
||||||
env_logger = "0.9"
|
env_logger = "0.9"
|
||||||
fermium = { version = "20016.1.1", default-features = false }
|
fermium = { version = "20022.0.0", features = ["raw-window-handle"] }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pixels = { path = "../.." }
|
pixels = { path = "../.." }
|
||||||
|
thiserror = "1.0"
|
||||||
zstring = "0.1"
|
zstring = "0.1"
|
||||||
|
|
|
@ -1,16 +1,12 @@
|
||||||
#![deny(clippy::all)]
|
#![deny(clippy::all)]
|
||||||
#![forbid(unsafe_code)]
|
|
||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||||
|
|
||||||
use beryllium::{
|
use crate::sdl::{Event, Sdl};
|
||||||
event::Event,
|
|
||||||
init::{InitFlags, Sdl},
|
|
||||||
window::WindowFlags,
|
|
||||||
};
|
|
||||||
use fermium::keycode;
|
|
||||||
use pixels::{Pixels, SurfaceTexture};
|
use pixels::{Pixels, SurfaceTexture};
|
||||||
use zstring::zstr;
|
use zstring::zstr;
|
||||||
|
|
||||||
|
mod sdl;
|
||||||
|
|
||||||
const WIDTH: u32 = 320;
|
const WIDTH: u32 = 320;
|
||||||
const HEIGHT: u32 = 240;
|
const HEIGHT: u32 = 240;
|
||||||
const BOX_SIZE: i16 = 64;
|
const BOX_SIZE: i16 = 64;
|
||||||
|
@ -25,18 +21,12 @@ struct World {
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
let sdl = Sdl::init(InitFlags::EVERYTHING)?;
|
|
||||||
let window = sdl.create_vk_window(
|
let sdl = Sdl::new(zstr!("Hello Pixels"), WIDTH, HEIGHT)?;
|
||||||
zstr!("Hello Pixels"),
|
|
||||||
None,
|
|
||||||
(WIDTH as i32, HEIGHT as i32),
|
|
||||||
WindowFlags::ALLOW_HIGHDPI,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let mut pixels = {
|
let mut pixels = {
|
||||||
// TODO: Beryllium does not expose the SDL2 `GetDrawableSize` APIs, so choosing the correct
|
let (width, height) = sdl.drawable_size();
|
||||||
// surface texture size is not possible.
|
let surface_texture = SurfaceTexture::new(width, height, &sdl);
|
||||||
let surface_texture = SurfaceTexture::new(WIDTH, HEIGHT, &*window);
|
|
||||||
Pixels::new(WIDTH, HEIGHT, surface_texture)?
|
Pixels::new(WIDTH, HEIGHT, surface_texture)?
|
||||||
};
|
};
|
||||||
let mut world = World::new();
|
let mut world = World::new();
|
||||||
|
@ -46,9 +36,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
match event {
|
match event {
|
||||||
// Close events
|
// Close events
|
||||||
Event::Quit { .. } => break 'game_loop,
|
Event::Quit { .. } => break 'game_loop,
|
||||||
Event::Keyboard { keycode: key, .. } if key == keycode::SDLK_ESCAPE => {
|
Event::Keyboard(key) if key == fermium::keycode::SDLK_ESCAPE => break 'game_loop,
|
||||||
break 'game_loop
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resize the window
|
// Resize the window
|
||||||
Event::WindowResized { width, height, .. } => pixels.resize_surface(width, height),
|
Event::WindowResized { width, height, .. } => pixels.resize_surface(width, height),
|
||||||
|
|
132
examples/minimal-sdl2/src/sdl.rs
Normal file
132
examples/minimal-sdl2/src/sdl.rs
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
//! 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<Self, SdlError> {
|
||||||
|
// 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<Event> {
|
||||||
|
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<SDL_Event> for Event {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(event: SDL_Event) -> Result<Self, Self::Error> {
|
||||||
|
// 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(()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,14 +13,14 @@ default = ["optimize"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pixels = { path = "../.." }
|
pixels = { path = "../.." }
|
||||||
wgpu = "0.12"
|
wgpu = "0.13"
|
||||||
winit = "0.26"
|
winit = "0.26"
|
||||||
winit_input_helper = "0.12"
|
winit_input_helper = "0.12"
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
console_error_panic_hook = "0.1"
|
console_error_panic_hook = "0.1"
|
||||||
console_log = "0.2"
|
console_log = "0.2"
|
||||||
wasm-bindgen = "0.2.78"
|
wasm-bindgen = "0.2"
|
||||||
wasm-bindgen-futures = "0.4"
|
wasm-bindgen-futures = "0.4"
|
||||||
web-sys = "0.3"
|
web-sys = "0.3"
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
// Vertex shader bindings
|
// Vertex shader bindings
|
||||||
|
|
||||||
struct VertexOutput {
|
struct VertexOutput {
|
||||||
[[location(0)]] tex_coord: vec2<f32>;
|
@location(0) tex_coord: vec2<f32>,
|
||||||
[[builtin(position)]] position: vec4<f32>;
|
@builtin(position) position: vec4<f32>,
|
||||||
};
|
}
|
||||||
|
|
||||||
struct Locals {
|
struct Locals {
|
||||||
transform: mat4x4<f32>;
|
transform: mat4x4<f32>,
|
||||||
};
|
}
|
||||||
[[group(0), binding(2)]] var<uniform> r_locals: Locals;
|
@group(0) @binding(2) var<uniform> r_locals: Locals;
|
||||||
|
|
||||||
[[stage(vertex)]]
|
@vertex
|
||||||
fn vs_main(
|
fn vs_main(
|
||||||
[[location(0)]] position: vec2<f32>,
|
@location(0) position: vec2<f32>,
|
||||||
) -> VertexOutput {
|
) -> VertexOutput {
|
||||||
var out: VertexOutput;
|
var out: VertexOutput;
|
||||||
out.tex_coord = fma(position, vec2<f32>(0.5, -0.5), vec2<f32>(0.5, 0.5));
|
out.tex_coord = fma(position, vec2<f32>(0.5, -0.5), vec2<f32>(0.5, 0.5));
|
||||||
|
@ -22,10 +22,10 @@ fn vs_main(
|
||||||
|
|
||||||
// Fragment shader bindings
|
// Fragment shader bindings
|
||||||
|
|
||||||
[[group(0), binding(0)]] var r_tex_color: texture_2d<f32>;
|
@group(0) @binding(0) var r_tex_color: texture_2d<f32>;
|
||||||
[[group(0), binding(1)]] var r_tex_sampler: sampler;
|
@group(0) @binding(1) var r_tex_sampler: sampler;
|
||||||
|
|
||||||
[[stage(fragment)]]
|
@fragment
|
||||||
fn fs_main([[location(0)]] tex_coord: vec2<f32>) -> [[location(0)]] vec4<f32> {
|
fn fs_main(@location(0) tex_coord: vec2<f32>) -> @location(0) vec4<f32> {
|
||||||
return textureSample(r_tex_color, r_tex_sampler, tex_coord);
|
return textureSample(r_tex_color, r_tex_sampler, tex_coord);
|
||||||
}
|
}
|
||||||
|
|
|
@ -296,9 +296,10 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W>
|
||||||
|
|
||||||
let present_mode = self.present_mode;
|
let present_mode = self.present_mode;
|
||||||
let surface_texture_format = self.surface_texture_format.unwrap_or_else(|| {
|
let surface_texture_format = self.surface_texture_format.unwrap_or_else(|| {
|
||||||
surface
|
*surface
|
||||||
.get_preferred_format(&adapter)
|
.get_supported_formats(&adapter)
|
||||||
.unwrap_or(wgpu::TextureFormat::Bgra8UnormSrgb)
|
.first()
|
||||||
|
.unwrap_or(&wgpu::TextureFormat::Bgra8UnormSrgb)
|
||||||
});
|
});
|
||||||
let render_texture_format = self.render_texture_format.unwrap_or(surface_texture_format);
|
let render_texture_format = self.render_texture_format.unwrap_or(surface_texture_format);
|
||||||
|
|
||||||
|
@ -457,11 +458,20 @@ pub(crate) fn create_backing_texture(
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
#[inline]
|
#[inline]
|
||||||
const fn get_texture_format_size(texture_format: wgpu::TextureFormat) -> f32 {
|
const fn get_texture_format_size(texture_format: wgpu::TextureFormat) -> f32 {
|
||||||
use wgpu::TextureFormat::*;
|
use wgpu::{AstcBlock::*, TextureFormat::*};
|
||||||
|
|
||||||
// TODO: Use constant arithmetic when supported.
|
// TODO: Use constant arithmetic when supported.
|
||||||
// See: https://github.com/rust-lang/rust/issues/57241
|
// See: https://github.com/rust-lang/rust/issues/57241
|
||||||
match texture_format {
|
match texture_format {
|
||||||
|
// Note that these sizes are typically estimates. For instance, GPU vendors decide whether
|
||||||
|
// their implementation uses 5 or 8 bytes per texel for formats like `Depth32PlusStencil8`.
|
||||||
|
// In cases where it is unclear, we choose to overestimate.
|
||||||
|
//
|
||||||
|
// See:
|
||||||
|
// - https://gpuweb.github.io/gpuweb/#plain-color-formats
|
||||||
|
// - https://gpuweb.github.io/gpuweb/#depth-formats
|
||||||
|
// - https://gpuweb.github.io/gpuweb/#packed-formats
|
||||||
|
|
||||||
// 8-bit formats, 8 bits per component
|
// 8-bit formats, 8 bits per component
|
||||||
R8Unorm
|
R8Unorm
|
||||||
| R8Snorm
|
| R8Snorm
|
||||||
|
@ -500,7 +510,8 @@ const fn get_texture_format_size(texture_format: wgpu::TextureFormat) -> f32 {
|
||||||
| Rg11b10Float
|
| Rg11b10Float
|
||||||
| Depth32Float
|
| Depth32Float
|
||||||
| Depth24Plus
|
| Depth24Plus
|
||||||
| Depth24PlusStencil8 => 4.0, // 32.0 / 8.0
|
| Depth24PlusStencil8
|
||||||
|
| Depth24UnormStencil8 => 4.0, // 32.0 / 8.0
|
||||||
|
|
||||||
// 64-bit formats, 8 bits per component
|
// 64-bit formats, 8 bits per component
|
||||||
Rg32Uint
|
Rg32Uint
|
||||||
|
@ -510,7 +521,8 @@ const fn get_texture_format_size(texture_format: wgpu::TextureFormat) -> f32 {
|
||||||
| Rgba16Sint
|
| Rgba16Sint
|
||||||
| Rgba16Float
|
| Rgba16Float
|
||||||
| Rgba16Unorm
|
| Rgba16Unorm
|
||||||
| Rgba16Snorm => 8.0, // 64.0 / 8.0
|
| Rgba16Snorm
|
||||||
|
| Depth32FloatStencil8 => 8.0, // 64.0 / 8.0
|
||||||
|
|
||||||
// 128-bit formats, 8 bits per component
|
// 128-bit formats, 8 bits per component
|
||||||
Rgba32Uint
|
Rgba32Uint
|
||||||
|
@ -546,59 +558,45 @@ const fn get_texture_format_size(texture_format: wgpu::TextureFormat) -> f32 {
|
||||||
| EacRg11Snorm
|
| EacRg11Snorm
|
||||||
| Etc2Rgba8Unorm
|
| Etc2Rgba8Unorm
|
||||||
| Etc2Rgba8UnormSrgb
|
| Etc2Rgba8UnormSrgb
|
||||||
| Astc4x4RgbaUnorm
|
| Astc { block: B4x4, channel: _ } => 1.0, // 4.0 * 4.0 / 16.0
|
||||||
| Astc4x4RgbaUnormSrgb => 1.0, // 4.0 * 4.0 / 16.0
|
|
||||||
|
|
||||||
// 5x4 blocks, 16 bytes per block
|
// 5x4 blocks, 16 bytes per block
|
||||||
Astc5x4RgbaUnorm
|
Astc { block: B5x4, channel: _ } => 1.25, // 5.0 * 4.0 / 16.0
|
||||||
| Astc5x4RgbaUnormSrgb => 1.25, // 5.0 * 4.0 / 16.0
|
|
||||||
|
|
||||||
// 5x5 blocks, 16 bytes per block
|
// 5x5 blocks, 16 bytes per block
|
||||||
Astc5x5RgbaUnorm
|
Astc { block: B5x5, channel: _ } => 1.5625, // 5.0 * 5.0 / 16.0
|
||||||
| Astc5x5RgbaUnormSrgb => 1.5625, // 5.0 * 5.0 / 16.0
|
|
||||||
|
|
||||||
// 6x5 blocks, 16 bytes per block
|
// 6x5 blocks, 16 bytes per block
|
||||||
Astc6x5RgbaUnorm
|
Astc { block: B6x5, channel: _ } => 1.875, // 6.0 * 5.0 / 16.0
|
||||||
| Astc6x5RgbaUnormSrgb => 1.875, // 6.0 * 5.0 / 16.0
|
|
||||||
|
|
||||||
// 6x6 blocks, 16 bytes per block
|
// 6x6 blocks, 16 bytes per block
|
||||||
Astc6x6RgbaUnorm
|
Astc { block: B6x6, channel: _ } => 2.25, // 6.0 * 6.0 / 16.0
|
||||||
| Astc6x6RgbaUnormSrgb => 2.25, // 6.0 * 6.0 / 16.0
|
|
||||||
|
|
||||||
// 8x5 blocks, 16 bytes per block
|
// 8x5 blocks, 16 bytes per block
|
||||||
Astc8x5RgbaUnorm
|
Astc { block: B8x5, channel: _ } => 2.5, // 8.0 * 5.0 / 16.0
|
||||||
| Astc8x5RgbaUnormSrgb => 2.5, // 8.0 * 5.0 / 16.0
|
|
||||||
|
|
||||||
// 8x6 blocks, 16 bytes per block
|
// 8x6 blocks, 16 bytes per block
|
||||||
Astc8x6RgbaUnorm
|
Astc { block: B8x6, channel: _ } => 3.0, // 8.0 * 6.0 / 16.0
|
||||||
| Astc8x6RgbaUnormSrgb => 3.0, // 8.0 * 6.0 / 16.0
|
|
||||||
|
|
||||||
// 8x8 blocks, 16 bytes per block
|
// 8x8 blocks, 16 bytes per block
|
||||||
Astc8x8RgbaUnorm
|
Astc { block: B8x8, channel: _ } => 4.0, // 8.0 * 8.0 / 16.0
|
||||||
| Astc8x8RgbaUnormSrgb => 4.0, // 8.0 * 8.0 / 16.0
|
|
||||||
|
|
||||||
// 10x5 blocks, 16 bytes per block
|
// 10x5 blocks, 16 bytes per block
|
||||||
Astc10x5RgbaUnorm
|
Astc { block: B10x5, channel: _ } => 3.125, // 10.0 * 5.0 / 16.0
|
||||||
| Astc10x5RgbaUnormSrgb => 3.125, // 10.0 * 5.0 / 16.0
|
|
||||||
|
|
||||||
// 10x6 blocks, 16 bytes per block
|
// 10x6 blocks, 16 bytes per block
|
||||||
Astc10x6RgbaUnorm
|
Astc { block: B10x6, channel: _ } => 3.75, // 10.0 * 6.0 / 16.0
|
||||||
| Astc10x6RgbaUnormSrgb => 3.75, // 10.0 * 6.0 / 16.0
|
|
||||||
|
|
||||||
// 10x8 blocks, 16 bytes per block
|
// 10x8 blocks, 16 bytes per block
|
||||||
Astc10x8RgbaUnorm
|
Astc { block: B10x8, channel: _ } => 5.0, // 10.0 * 8.0 / 16.0
|
||||||
| Astc10x8RgbaUnormSrgb => 5.0, // 10.0 * 8.0 / 16.0
|
|
||||||
|
|
||||||
// 10x10 blocks, 16 bytes per block
|
// 10x10 blocks, 16 bytes per block
|
||||||
Astc10x10RgbaUnorm
|
Astc { block: B10x10, channel: _ } => 6.25, // 10.0 * 10.0 / 16.0
|
||||||
| Astc10x10RgbaUnormSrgb => 6.25, // 10.0 * 10.0 / 16.0
|
|
||||||
|
|
||||||
// 12x10 blocks, 16 bytes per block
|
// 12x10 blocks, 16 bytes per block
|
||||||
Astc12x10RgbaUnorm
|
Astc { block: B12x10, channel: _ } => 7.5, // 12.0 * 10.0 / 16.0
|
||||||
| Astc12x10RgbaUnormSrgb => 7.5, // 12.0 * 10.0 / 16.0
|
|
||||||
|
|
||||||
// 12x12 blocks, 16 bytes per block
|
// 12x12 blocks, 16 bytes per block
|
||||||
Astc12x12RgbaUnorm
|
Astc { block: B12x12, channel: _ } => 9.0, // 12.0 * 12.0 / 16.0
|
||||||
| Astc12x12RgbaUnormSrgb => 9.0, // 12.0 * 12.0 / 16.0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ impl ScalingRenderer {
|
||||||
blend_state: wgpu::BlendState,
|
blend_state: wgpu::BlendState,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let shader = wgpu::include_wgsl!("../shaders/scale.wgsl");
|
let shader = wgpu::include_wgsl!("../shaders/scale.wgsl");
|
||||||
let module = device.create_shader_module(&shader);
|
let module = device.create_shader_module(shader);
|
||||||
|
|
||||||
// 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 {
|
||||||
|
@ -151,11 +151,11 @@ impl ScalingRenderer {
|
||||||
fragment: Some(wgpu::FragmentState {
|
fragment: Some(wgpu::FragmentState {
|
||||||
module: &module,
|
module: &module,
|
||||||
entry_point: "fs_main",
|
entry_point: "fs_main",
|
||||||
targets: &[wgpu::ColorTargetState {
|
targets: &[Some(wgpu::ColorTargetState {
|
||||||
format: render_texture_format,
|
format: render_texture_format,
|
||||||
blend: Some(blend_state),
|
blend: Some(blend_state),
|
||||||
write_mask: wgpu::ColorWrites::ALL,
|
write_mask: wgpu::ColorWrites::ALL,
|
||||||
}],
|
})],
|
||||||
}),
|
}),
|
||||||
multiview: None,
|
multiview: None,
|
||||||
});
|
});
|
||||||
|
@ -179,14 +179,14 @@ impl ScalingRenderer {
|
||||||
pub fn render(&self, encoder: &mut wgpu::CommandEncoder, render_target: &wgpu::TextureView) {
|
pub fn render(&self, encoder: &mut wgpu::CommandEncoder, render_target: &wgpu::TextureView) {
|
||||||
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
label: Some("pixels_scaling_renderer_render_pass"),
|
label: Some("pixels_scaling_renderer_render_pass"),
|
||||||
color_attachments: &[wgpu::RenderPassColorAttachment {
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
view: render_target,
|
view: render_target,
|
||||||
resolve_target: None,
|
resolve_target: None,
|
||||||
ops: wgpu::Operations {
|
ops: wgpu::Operations {
|
||||||
load: wgpu::LoadOp::Clear(self.clear_color),
|
load: wgpu::LoadOp::Clear(self.clear_color),
|
||||||
store: true,
|
store: true,
|
||||||
},
|
},
|
||||||
}],
|
})],
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
});
|
});
|
||||||
rpass.set_pipeline(&self.render_pipeline);
|
rpass.set_pipeline(&self.render_pipeline);
|
||||||
|
|
Loading…
Reference in a new issue