mirror of
https://github.com/EmbarkStudios/rust-gpu.git
synced 2025-02-16 08:54:56 +00:00
Update wgpu (and ash, to avoid duplicate deps).
This commit is contained in:
parent
b67ad40fef
commit
a9472a0743
852
Cargo.lock
generated
852
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -14,17 +14,14 @@ use-installed-tools = ["spirv-builder/use-installed-tools"]
|
||||
use-compiled-tools = ["spirv-builder/use-compiled-tools"]
|
||||
|
||||
[dependencies]
|
||||
ash = "0.35"
|
||||
ash-window = "0.9"
|
||||
winit = "0.26"
|
||||
ash = "0.37"
|
||||
ash-window = "0.12"
|
||||
raw-window-handle = "0.5.1"
|
||||
winit = "0.28.3"
|
||||
structopt = "0.3.20"
|
||||
cfg-if = "1.0.0"
|
||||
shared = { path = "../../shaders/shared" }
|
||||
spirv-builder = { workspace = true, default-features = false }
|
||||
|
||||
# TODO: Remove this once no longer needed, only needed to make cargo-deny happy for some reason.
|
||||
# https://rustsec.org/advisories/RUSTSEC-2021-0119
|
||||
nix = "0.20.2"
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
ash-molten = { version = "0.12.0", features = ["pre-built"] }
|
||||
ash-molten = { version = "0.13.1", features = ["pre-built"] }
|
||||
|
@ -76,6 +76,7 @@ use ash::{
|
||||
vk,
|
||||
};
|
||||
|
||||
use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
|
||||
use winit::{
|
||||
event::{Event, VirtualKeyCode, WindowEvent},
|
||||
event_loop::{ControlFlow, EventLoop},
|
||||
@ -271,11 +272,10 @@ impl RenderBase {
|
||||
.map(|raw_name| raw_name.as_ptr())
|
||||
.collect();
|
||||
|
||||
let mut extension_names_raw = ash_window::enumerate_required_extensions(&window)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|ext| ext.as_ptr())
|
||||
.collect::<Vec<_>>();
|
||||
let mut extension_names_raw =
|
||||
ash_window::enumerate_required_extensions(window.raw_display_handle())
|
||||
.unwrap()
|
||||
.to_vec();
|
||||
if options.debug_layer {
|
||||
extension_names_raw.push(ext::DebugUtils::name().as_ptr());
|
||||
}
|
||||
@ -299,8 +299,16 @@ impl RenderBase {
|
||||
}
|
||||
};
|
||||
|
||||
let surface =
|
||||
unsafe { ash_window::create_surface(&entry, &instance, &window, None).unwrap() };
|
||||
let surface = unsafe {
|
||||
ash_window::create_surface(
|
||||
&entry,
|
||||
&instance,
|
||||
window.raw_display_handle(),
|
||||
window.raw_window_handle(),
|
||||
None,
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
let (debug_utils_loader, debug_call_back) = if options.debug_layer {
|
||||
let debug_utils_loader = ext::DebugUtils::new(&entry, &instance);
|
||||
|
@ -22,7 +22,7 @@ shared = { path = "../../shaders/shared" }
|
||||
futures = { version = "0.3", default-features = false, features = ["std", "executor"] }
|
||||
# Vulkan SDK or MoltenVK needs to be installed for `vulkan-portability` to work on macOS
|
||||
wgpu = { git = "https://github.com/gfx-rs/wgpu", features = ["spirv", "vulkan-portability"] }
|
||||
winit = { version = "0.26" }
|
||||
winit = "0.28.3"
|
||||
structopt = "0.3"
|
||||
strum = { version = "0.23.0", default_features = false, features = ["std", "derive"] }
|
||||
bytemuck = "1.6.3"
|
||||
@ -31,13 +31,13 @@ bytemuck = "1.6.3"
|
||||
spirv-builder = { workspace = true, features = ["watch"] }
|
||||
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
ndk-glue = "0.4"
|
||||
ndk-glue = "0.7.0"
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
env_logger = "0.9.0"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
web-sys = "=0.3.55"
|
||||
web-sys = "0.3.60"
|
||||
console_error_panic_hook = "0.1.6"
|
||||
console_log = "0.2.0"
|
||||
wasm-bindgen-futures = "0.4.18"
|
||||
|
@ -1,7 +1,6 @@
|
||||
use wgpu::util::DeviceExt;
|
||||
|
||||
use super::Options;
|
||||
use futures::future::join;
|
||||
use std::{convert::TryInto, future::Future, time::Duration};
|
||||
|
||||
fn block_on<T>(future: impl Future<Output = T>) -> T {
|
||||
@ -24,13 +23,12 @@ pub async fn start_internal(
|
||||
_options: &Options,
|
||||
shader_binary: wgpu::ShaderModuleDescriptor<'static>,
|
||||
) {
|
||||
let instance = wgpu::Instance::new(wgpu::Backends::PRIMARY);
|
||||
let adapter = instance
|
||||
.request_adapter(&wgpu::RequestAdapterOptions {
|
||||
power_preference: wgpu::PowerPreference::default(),
|
||||
force_fallback_adapter: false,
|
||||
compatible_surface: None,
|
||||
})
|
||||
let backends = wgpu::util::backend_bits_from_env().unwrap_or(wgpu::Backends::PRIMARY);
|
||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||
backends,
|
||||
dx12_shader_compiler: wgpu::util::dx12_shader_compiler_from_env().unwrap_or_default(),
|
||||
});
|
||||
let adapter = wgpu::util::initialize_adapter_from_env_or_default(&instance, backends, None)
|
||||
.await
|
||||
.expect("Failed to find an appropriate adapter");
|
||||
|
||||
@ -51,7 +49,7 @@ pub async fn start_internal(
|
||||
let timestamp_period = queue.get_timestamp_period();
|
||||
|
||||
// Load the shaders from disk
|
||||
let module = device.create_shader_module(&shader_binary);
|
||||
let module = device.create_shader_module(shader_binary);
|
||||
|
||||
let top = 2u32.pow(20);
|
||||
let src_range = 1..top;
|
||||
@ -135,7 +133,7 @@ pub async fn start_internal(
|
||||
cpass.set_bind_group(0, &bind_group, &[]);
|
||||
cpass.set_pipeline(&compute_pipeline);
|
||||
cpass.write_timestamp(&queries, 0);
|
||||
cpass.dispatch(src_range.len() as u32 / 64, 1, 1);
|
||||
cpass.dispatch_workgroups(src_range.len() as u32 / 64, 1, 1);
|
||||
cpass.write_timestamp(&queries, 1);
|
||||
}
|
||||
|
||||
@ -151,41 +149,41 @@ pub async fn start_internal(
|
||||
queue.submit(Some(encoder.finish()));
|
||||
let buffer_slice = readback_buffer.slice(..);
|
||||
let timestamp_slice = timestamp_buffer.slice(..);
|
||||
let timestamp_future = timestamp_slice.map_async(wgpu::MapMode::Read);
|
||||
let buffer_future = buffer_slice.map_async(wgpu::MapMode::Read);
|
||||
timestamp_slice.map_async(wgpu::MapMode::Read, |r| r.unwrap());
|
||||
buffer_slice.map_async(wgpu::MapMode::Read, |r| r.unwrap());
|
||||
// NOTE(eddyb) `poll` should return only after the above callbacks fire
|
||||
// (see also https://github.com/gfx-rs/wgpu/pull/2698 for more details).
|
||||
device.poll(wgpu::Maintain::Wait);
|
||||
|
||||
if let (Ok(()), Ok(())) = join(buffer_future, timestamp_future).await {
|
||||
let data = buffer_slice.get_mapped_range();
|
||||
let timing_data = timestamp_slice.get_mapped_range();
|
||||
let result = data
|
||||
.chunks_exact(4)
|
||||
.map(|b| u32::from_ne_bytes(b.try_into().unwrap()))
|
||||
.collect::<Vec<_>>();
|
||||
let timings = timing_data
|
||||
.chunks_exact(8)
|
||||
.map(|b| u64::from_ne_bytes(b.try_into().unwrap()))
|
||||
.collect::<Vec<_>>();
|
||||
drop(data);
|
||||
readback_buffer.unmap();
|
||||
drop(timing_data);
|
||||
timestamp_buffer.unmap();
|
||||
let mut max = 0;
|
||||
for (src, out) in src_range.zip(result.iter().copied()) {
|
||||
if out == u32::MAX {
|
||||
println!("{src}: overflowed");
|
||||
break;
|
||||
} else if out > max {
|
||||
max = out;
|
||||
// Should produce <https://oeis.org/A006877>
|
||||
println!("{src}: {out}");
|
||||
}
|
||||
let data = buffer_slice.get_mapped_range();
|
||||
let timing_data = timestamp_slice.get_mapped_range();
|
||||
let result = data
|
||||
.chunks_exact(4)
|
||||
.map(|b| u32::from_ne_bytes(b.try_into().unwrap()))
|
||||
.collect::<Vec<_>>();
|
||||
let timings = timing_data
|
||||
.chunks_exact(8)
|
||||
.map(|b| u64::from_ne_bytes(b.try_into().unwrap()))
|
||||
.collect::<Vec<_>>();
|
||||
drop(data);
|
||||
readback_buffer.unmap();
|
||||
drop(timing_data);
|
||||
timestamp_buffer.unmap();
|
||||
let mut max = 0;
|
||||
for (src, out) in src_range.zip(result.iter().copied()) {
|
||||
if out == u32::MAX {
|
||||
println!("{src}: overflowed");
|
||||
break;
|
||||
} else if out > max {
|
||||
max = out;
|
||||
// Should produce <https://oeis.org/A006877>
|
||||
println!("{src}: {out}");
|
||||
}
|
||||
println!(
|
||||
"Took: {:?}",
|
||||
Duration::from_nanos(
|
||||
((timings[1] - timings[0]) as f64 * f64::from(timestamp_period)) as u64
|
||||
)
|
||||
);
|
||||
}
|
||||
println!(
|
||||
"Took: {:?}",
|
||||
Duration::from_nanos(
|
||||
((timings[1] - timings[0]) as f64 * f64::from(timestamp_period)) as u64
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use super::Options;
|
||||
use shared::ShaderConstants;
|
||||
use winit::{
|
||||
event::{ElementState, Event, KeyboardInput, MouseButton, VirtualKeyCode, WindowEvent},
|
||||
event_loop::{ControlFlow, EventLoop},
|
||||
event_loop::{ControlFlow, EventLoop, EventLoopBuilder},
|
||||
window::Window,
|
||||
};
|
||||
|
||||
@ -37,25 +37,37 @@ async fn run(
|
||||
window: Window,
|
||||
shader_binary: wgpu::ShaderModuleDescriptor<'static>,
|
||||
) {
|
||||
let instance = wgpu::Instance::new(wgpu::Backends::VULKAN | wgpu::Backends::METAL);
|
||||
let backends = wgpu::util::backend_bits_from_env()
|
||||
.unwrap_or(wgpu::Backends::VULKAN | wgpu::Backends::METAL);
|
||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||
backends,
|
||||
dx12_shader_compiler: wgpu::util::dx12_shader_compiler_from_env().unwrap_or_default(),
|
||||
});
|
||||
|
||||
// Wait for Resumed event on Android; the surface is only needed early to
|
||||
// find an adapter that can render to this surface.
|
||||
let mut surface = if cfg!(target_os = "android") {
|
||||
None
|
||||
// HACK(eddyb) marker error type for lazily-created surfaces (e.g. on Android).
|
||||
struct SurfaceCreationPending {
|
||||
preferred_format: wgpu::TextureFormat,
|
||||
}
|
||||
|
||||
// Wait for Resumed event on Android; the surface is only otherwise needed
|
||||
// early to find an adapter that can render to this surface.
|
||||
let initial_surface = if cfg!(target_os = "android") {
|
||||
Err(SurfaceCreationPending {
|
||||
preferred_format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
||||
})
|
||||
} else {
|
||||
Some(unsafe { instance.create_surface(&window) })
|
||||
Ok(unsafe { instance.create_surface(&window) }
|
||||
.expect("Failed to create surface from window"))
|
||||
};
|
||||
|
||||
let adapter = instance
|
||||
.request_adapter(&wgpu::RequestAdapterOptions {
|
||||
power_preference: wgpu::PowerPreference::default(),
|
||||
force_fallback_adapter: false,
|
||||
// Request an adapter which can render to our surface
|
||||
compatible_surface: surface.as_ref(),
|
||||
})
|
||||
.await
|
||||
.expect("Failed to find an appropriate adapter");
|
||||
let adapter = wgpu::util::initialize_adapter_from_env_or_default(
|
||||
&instance,
|
||||
backends,
|
||||
// Request an adapter which can render to our surface
|
||||
initial_surface.as_ref().ok(),
|
||||
)
|
||||
.await
|
||||
.expect("Failed to find an appropriate adapter");
|
||||
|
||||
let features = wgpu::Features::PUSH_CONSTANTS;
|
||||
let limits = wgpu::Limits {
|
||||
@ -76,6 +88,30 @@ async fn run(
|
||||
.await
|
||||
.expect("Failed to create device");
|
||||
|
||||
let auto_configure_surface =
|
||||
|adapter: &_, device: &_, surface: wgpu::Surface, size: winit::dpi::PhysicalSize<_>| {
|
||||
let mut surface_config = surface
|
||||
.get_default_config(adapter, size.width, size.height)
|
||||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Missing formats/present modes in surface capabilities: {:#?}",
|
||||
surface.get_capabilities(adapter)
|
||||
)
|
||||
});
|
||||
|
||||
// FIXME(eddyb) should this be toggled by a CLI arg?
|
||||
// NOTE(eddyb) VSync was disabled in the past, but without VSync,
|
||||
// especially for simpler shaders, you can easily hit thousands
|
||||
// of frames per second, stressing GPUs for no reason.
|
||||
surface_config.present_mode = wgpu::PresentMode::AutoVsync;
|
||||
|
||||
surface.configure(device, &surface_config);
|
||||
|
||||
(surface, surface_config)
|
||||
};
|
||||
let mut surface_with_config = initial_surface
|
||||
.map(|surface| auto_configure_surface(&adapter, &device, surface, window.inner_size()));
|
||||
|
||||
// Load the shaders from disk
|
||||
|
||||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
@ -87,28 +123,15 @@ async fn run(
|
||||
}],
|
||||
});
|
||||
|
||||
let preferred_format = if let Some(surface) = &surface {
|
||||
surface.get_preferred_format(&adapter).unwrap()
|
||||
} else {
|
||||
// if Surface is none, we're guaranteed to be on android
|
||||
wgpu::TextureFormat::Rgba8UnormSrgb
|
||||
};
|
||||
|
||||
let mut render_pipeline =
|
||||
create_pipeline(&device, &pipeline_layout, preferred_format, shader_binary);
|
||||
|
||||
let size = window.inner_size();
|
||||
|
||||
let mut surface_config = wgpu::SurfaceConfiguration {
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||
format: preferred_format,
|
||||
width: size.width,
|
||||
height: size.height,
|
||||
present_mode: wgpu::PresentMode::Mailbox,
|
||||
};
|
||||
if let Some(surface) = &mut surface {
|
||||
surface.configure(&device, &surface_config);
|
||||
}
|
||||
let mut render_pipeline = create_pipeline(
|
||||
&device,
|
||||
&pipeline_layout,
|
||||
surface_with_config.as_ref().map_or_else(
|
||||
|pending| pending.preferred_format,
|
||||
|(_, surface_config)| surface_config.format,
|
||||
),
|
||||
shader_binary,
|
||||
);
|
||||
|
||||
let start = std::time::Instant::now();
|
||||
|
||||
@ -132,13 +155,21 @@ async fn run(
|
||||
window.request_redraw();
|
||||
}
|
||||
Event::Resumed => {
|
||||
let s = unsafe { instance.create_surface(&window) };
|
||||
surface_config.format = s.get_preferred_format(&adapter).unwrap();
|
||||
s.configure(&device, &surface_config);
|
||||
surface = Some(s);
|
||||
let new_surface = unsafe { instance.create_surface(&window) }
|
||||
.expect("Failed to create surface from window (after resume)");
|
||||
surface_with_config = Ok(auto_configure_surface(
|
||||
&adapter,
|
||||
&device,
|
||||
new_surface,
|
||||
window.inner_size(),
|
||||
));
|
||||
}
|
||||
Event::Suspended => {
|
||||
surface = None;
|
||||
if let Ok((_, surface_config)) = &surface_with_config {
|
||||
surface_with_config = Err(SurfaceCreationPending {
|
||||
preferred_format: surface_config.format,
|
||||
});
|
||||
}
|
||||
}
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::Resized(size),
|
||||
@ -146,22 +177,29 @@ async fn run(
|
||||
} => {
|
||||
if size.width != 0 && size.height != 0 {
|
||||
// Recreate the swap chain with the new size
|
||||
surface_config.width = size.width;
|
||||
surface_config.height = size.height;
|
||||
if let Some(surface) = &surface {
|
||||
surface.configure(&device, &surface_config);
|
||||
if let Ok((surface, surface_config)) = &mut surface_with_config {
|
||||
surface_config.width = size.width;
|
||||
surface_config.height = size.height;
|
||||
surface.configure(&device, surface_config);
|
||||
}
|
||||
}
|
||||
}
|
||||
Event::RedrawRequested(_) => {
|
||||
if let Some(surface) = &mut surface {
|
||||
// FIXME(eddyb) only the mouse shader *really* needs this, could
|
||||
// avoid doing wasteful rendering by special-casing each shader?
|
||||
// (with VSync enabled this can't be *too* bad, thankfully)
|
||||
// FIXME(eddyb) is this the best way to do continuous redraws in
|
||||
// `winit`? (or should we stop using `ControlFlow::Wait`? etc.)
|
||||
window.request_redraw();
|
||||
|
||||
if let Ok((surface, surface_config)) = &mut surface_with_config {
|
||||
let output = match surface.get_current_texture() {
|
||||
Ok(surface) => surface,
|
||||
Err(err) => {
|
||||
eprintln!("get_current_texture error: {err:?}");
|
||||
match err {
|
||||
wgpu::SurfaceError::Lost => {
|
||||
surface.configure(&device, &surface_config);
|
||||
surface.configure(&device, surface_config);
|
||||
}
|
||||
wgpu::SurfaceError::OutOfMemory => {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
@ -179,14 +217,14 @@ async fn run(
|
||||
{
|
||||
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: None,
|
||||
color_attachments: &[wgpu::RenderPassColorAttachment {
|
||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||
view: &output_view,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::GREEN),
|
||||
store: true,
|
||||
},
|
||||
}],
|
||||
})],
|
||||
depth_stencil_attachment: None,
|
||||
});
|
||||
|
||||
@ -270,8 +308,15 @@ async fn run(
|
||||
}
|
||||
}
|
||||
Event::UserEvent(new_module) => {
|
||||
*render_pipeline =
|
||||
create_pipeline(&device, &pipeline_layout, surface_config.format, new_module);
|
||||
*render_pipeline = create_pipeline(
|
||||
&device,
|
||||
&pipeline_layout,
|
||||
surface_with_config.as_ref().map_or_else(
|
||||
|pending| pending.preferred_format,
|
||||
|(_, surface_config)| surface_config.format,
|
||||
),
|
||||
new_module,
|
||||
);
|
||||
window.request_redraw();
|
||||
*control_flow = ControlFlow::Poll;
|
||||
}
|
||||
@ -286,7 +331,7 @@ fn create_pipeline(
|
||||
surface_format: wgpu::TextureFormat,
|
||||
shader_binary: wgpu::ShaderModuleDescriptor<'_>,
|
||||
) -> wgpu::RenderPipeline {
|
||||
let module = device.create_shader_module(&shader_binary);
|
||||
let module = device.create_shader_module(shader_binary);
|
||||
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: None,
|
||||
layout: Some(pipeline_layout),
|
||||
@ -313,11 +358,11 @@ fn create_pipeline(
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &module,
|
||||
entry_point: shaders::main_fs,
|
||||
targets: &[wgpu::ColorTargetState {
|
||||
targets: &[Some(wgpu::ColorTargetState {
|
||||
format: surface_format,
|
||||
blend: None,
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
}],
|
||||
})],
|
||||
}),
|
||||
multiview: None,
|
||||
})
|
||||
@ -326,7 +371,7 @@ fn create_pipeline(
|
||||
#[allow(clippy::match_wild_err_arm)]
|
||||
pub fn start(options: &Options) {
|
||||
// Build the shader before we pop open a window, since it might take a while.
|
||||
let event_loop = EventLoop::with_user_event();
|
||||
let event_loop = EventLoopBuilder::with_user_event().build();
|
||||
let proxy = event_loop.create_proxy();
|
||||
let initial_shader = maybe_watch(
|
||||
options.shader,
|
||||
|
Loading…
Reference in New Issue
Block a user