mirror of
https://github.com/storytold/designcraft.git
synced 2026-11-11 21:02:45 +00:00
Merge pull request #2037 from r31lin/fix/gpu-largest-buffer
Ask the graphics device for the adapter's largest buffer
This commit is contained in:
2 files changed
+40
-12
No files matched your search
@@ -6,6 +6,11 @@
|
||||
//! (9048×5757 between 250 % and 100 % monitors), then failed `Surface::configure`, and wgpu's
|
||||
//! default error handler panics: the app closed with the documents in it. DirectX 12, Vulkan and
|
||||
//! Metal hardware offer 16384.
|
||||
//!
|
||||
//! The same goes for buffers: egui-wgpu doubles its vertex buffer when a frame outgrows it, and
|
||||
//! wgpu's default largest buffer is 256 MiB. A frame of a 160-page catalogue with 137 MB of vertices
|
||||
//! asked for a 275 MB buffer, and egui-wgpu panicked when the device refused it. DirectX 12 and
|
||||
//! Vulkan hardware offer far more.
|
||||
|
||||
use eframe::{
|
||||
NativeOptions,
|
||||
@@ -14,21 +19,23 @@ use eframe::{
|
||||
};
|
||||
use std::sync::{Arc, Mutex, PoisonError};
|
||||
|
||||
/// `required` with the largest texture side the adapter's `supported` limits offer. Taking the
|
||||
/// adapter's own value also never asks a smaller (downlevel) adapter for more than it has.
|
||||
pub fn surface_texture_limits(mut required: Limits, supported: &Limits) -> Limits {
|
||||
/// `required` with the largest texture side and buffer the adapter's `supported` limits offer.
|
||||
/// Taking the adapter's own values also never asks a smaller (downlevel) adapter for more than it
|
||||
/// has.
|
||||
pub fn adapter_size_limits(mut required: Limits, supported: &Limits) -> Limits {
|
||||
required.max_texture_dimension_2d = supported.max_texture_dimension_2d;
|
||||
required.max_buffer_size = supported.max_buffer_size;
|
||||
required
|
||||
}
|
||||
|
||||
/// Makes the device eframe creates ask for the adapter's largest texture side
|
||||
/// ([`surface_texture_limits`]), keeping eframe's other device requirements.
|
||||
pub fn request_adapter_texture_size(options: &mut NativeOptions) {
|
||||
/// Makes the device eframe creates ask for the adapter's largest texture side and buffer
|
||||
/// ([`adapter_size_limits`]), keeping eframe's other device requirements.
|
||||
pub fn request_adapter_sizes(options: &mut NativeOptions) {
|
||||
if let WgpuSetup::CreateNew(create) = &mut options.wgpu_options.wgpu_setup {
|
||||
let device_descriptor = Arc::clone(&create.device_descriptor);
|
||||
create.device_descriptor = Arc::new(move |adapter| {
|
||||
let mut descriptor = device_descriptor(adapter);
|
||||
descriptor.required_limits = surface_texture_limits(descriptor.required_limits, &adapter.limits());
|
||||
descriptor.required_limits = adapter_size_limits(descriptor.required_limits, &adapter.limits());
|
||||
descriptor
|
||||
});
|
||||
}
|
||||
@@ -62,7 +69,7 @@ mod tests {
|
||||
let eframe_request = Limits { max_texture_dimension_2d: 8192, ..base.clone() };
|
||||
for side in [4096, 8192, 16384, 32768] {
|
||||
let supported = Limits { max_texture_dimension_2d: side, ..base.clone() };
|
||||
let limits = surface_texture_limits(eframe_request.clone(), &supported);
|
||||
let limits = adapter_size_limits(eframe_request.clone(), &supported);
|
||||
assert_eq!(limits.max_texture_dimension_2d, side);
|
||||
// The drag's 9048×5757 surface fits from 16384 up.
|
||||
assert_eq!(side >= 16384, 9048 <= limits.max_texture_dimension_2d);
|
||||
@@ -73,12 +80,27 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn largest_buffer_is_the_adapters_own() {
|
||||
// egui-wgpu grew its vertex buffer to 275 MB for 137 MB of vertices: more than wgpu's
|
||||
// default 256 MiB, within what DirectX 12 hardware offers. A downlevel adapter offering
|
||||
// less is asked for no more.
|
||||
let eframe_request = Limits::default();
|
||||
for size in [128 << 20, 256 << 20, 2 << 30] {
|
||||
let supported = Limits { max_buffer_size: size, ..Limits::default() };
|
||||
let limits = adapter_size_limits(eframe_request.clone(), &supported);
|
||||
assert_eq!(limits.max_buffer_size, size);
|
||||
assert_eq!(size >= 2 << 30, limits.max_buffer_size >= 275_114_400);
|
||||
assert!(limits.check_limits(&supported));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn native_options_keep_creating_their_own_device() {
|
||||
// The wrapper only replaces the device descriptor: eframe still creates the instance,
|
||||
// adapter and device, and main.rs can still choose the backends.
|
||||
let mut options = NativeOptions::default();
|
||||
request_adapter_texture_size(&mut options);
|
||||
request_adapter_sizes(&mut options);
|
||||
assert!(matches!(options.wgpu_options.wgpu_setup, WgpuSetup::CreateNew(_)));
|
||||
}
|
||||
}
|
||||
@@ -319,9 +319,9 @@ fn main() -> std::process::ExitCode {
|
||||
if let Some(icon) = app_icon() {
|
||||
options.viewport = options.viewport.with_icon(icon);
|
||||
}
|
||||
// The adapter's largest texture side instead of eframe's 8192, so a window across several
|
||||
// monitors keeps its surface (see `gpu_limits`).
|
||||
gpu_limits::request_adapter_texture_size(&mut options);
|
||||
// The adapter's largest texture side and buffer instead of eframe's 8192 and wgpu's 256 MiB, so a
|
||||
// window across several monitors keeps its surface and a large frame its vertex buffer (see `gpu_limits`).
|
||||
gpu_limits::request_adapter_sizes(&mut options);
|
||||
// The graphics backend, decided before the window exists: a driver that faults takes the
|
||||
// process down before any Rust code can catch it (see `gpu::backend`).
|
||||
let fallback = gpu::backend::Fallback::begin(
|
||||
@@ -400,6 +400,12 @@ fn main() -> std::process::ExitCode {
|
||||
info.driver,
|
||||
info.driver_info
|
||||
);
|
||||
let limits = rs.device.limits();
|
||||
log::info!(
|
||||
"graphics: largest texture side {}, largest buffer {} MiB",
|
||||
limits.max_texture_dimension_2d,
|
||||
limits.max_buffer_size >> 20
|
||||
);
|
||||
created.started_with(info.backend);
|
||||
created.created(&cc.egui_ctx);
|
||||
if !skip.is_empty() {
|
||||
|
||||
Reference in new issue
Block a user