mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-02-16 17:02:32 +00:00
gles: fix crash when holding multiple devices on wayland/surfaceless. (#5351)
This commit is contained in:
parent
f78e2f7800
commit
8e15707631
@ -41,7 +41,7 @@ Bottom level categories:
|
|||||||
|
|
||||||
### Major Changes
|
### Major Changes
|
||||||
|
|
||||||
#### Vendored WebGPU Bindings from `web_sys`
|
#### Vendored WebGPU Bindings from `web_sys`
|
||||||
|
|
||||||
**`--cfg=web_sys_unstable_apis` is no longer needed in your `RUSTFLAGS` to compile for WebGPU!!!**
|
**`--cfg=web_sys_unstable_apis` is no longer needed in your `RUSTFLAGS` to compile for WebGPU!!!**
|
||||||
|
|
||||||
@ -165,6 +165,7 @@ By @cwfitzgerald in [#5325](https://github.com/gfx-rs/wgpu/pull/5325).
|
|||||||
|
|
||||||
- Fixes for being able to use an OpenGL 4.1 core context provided by macOS with wgpu. By @bes in [#5331](https://github.com/gfx-rs/wgpu/pull/5331).
|
- Fixes for being able to use an OpenGL 4.1 core context provided by macOS with wgpu. By @bes in [#5331](https://github.com/gfx-rs/wgpu/pull/5331).
|
||||||
- Don't create a program for shader-clearing if that workaround isn't required. By @Dinnerbone in [#5348](https://github.com/gfx-rs/wgpu/pull/5348).
|
- Don't create a program for shader-clearing if that workaround isn't required. By @Dinnerbone in [#5348](https://github.com/gfx-rs/wgpu/pull/5348).
|
||||||
|
- Fix crash when holding multiple devices on wayland/surfaceless. By @ashdnazg in [#5351](https://github.com/gfx-rs/wgpu/pull/5351).
|
||||||
|
|
||||||
#### Vulkan
|
#### Vulkan
|
||||||
|
|
||||||
|
@ -29,39 +29,69 @@ static CROSS_DEVICE_BIND_GROUP_USAGE: GpuTestConfiguration = GpuTestConfiguratio
|
|||||||
});
|
});
|
||||||
|
|
||||||
#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
|
#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
|
||||||
#[test]
|
#[gpu_test]
|
||||||
fn device_lifetime_check() {
|
static DEVICE_LIFETIME_CHECK: GpuTestConfiguration = GpuTestConfiguration::new()
|
||||||
use pollster::FutureExt as _;
|
.parameters(TestParameters::default())
|
||||||
|
.run_sync(|_| {
|
||||||
|
use pollster::FutureExt as _;
|
||||||
|
|
||||||
env_logger::init();
|
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
backends: wgpu::util::backend_bits_from_env().unwrap_or(wgpu::Backends::all()),
|
||||||
backends: wgpu::util::backend_bits_from_env().unwrap_or(wgpu::Backends::all()),
|
dx12_shader_compiler: wgpu::util::dx12_shader_compiler_from_env().unwrap_or_default(),
|
||||||
dx12_shader_compiler: wgpu::util::dx12_shader_compiler_from_env().unwrap_or_default(),
|
gles_minor_version: wgpu::util::gles_minor_version_from_env().unwrap_or_default(),
|
||||||
gles_minor_version: wgpu::util::gles_minor_version_from_env().unwrap_or_default(),
|
flags: wgpu::InstanceFlags::advanced_debugging().with_env(),
|
||||||
flags: wgpu::InstanceFlags::advanced_debugging().with_env(),
|
});
|
||||||
|
|
||||||
|
let adapter = wgpu::util::initialize_adapter_from_env_or_default(&instance, None)
|
||||||
|
.block_on()
|
||||||
|
.expect("failed to create adapter");
|
||||||
|
|
||||||
|
let (device, queue) = adapter
|
||||||
|
.request_device(&wgpu::DeviceDescriptor::default(), None)
|
||||||
|
.block_on()
|
||||||
|
.expect("failed to create device");
|
||||||
|
|
||||||
|
instance.poll_all(false);
|
||||||
|
|
||||||
|
let pre_report = instance.generate_report().unwrap();
|
||||||
|
|
||||||
|
drop(queue);
|
||||||
|
drop(device);
|
||||||
|
let post_report = instance.generate_report().unwrap();
|
||||||
|
assert_ne!(
|
||||||
|
pre_report, post_report,
|
||||||
|
"Queue and Device has not been dropped as expected"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
let adapter = wgpu::util::initialize_adapter_from_env_or_default(&instance, None)
|
#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
|
||||||
.block_on()
|
#[gpu_test]
|
||||||
.expect("failed to create adapter");
|
static MULTIPLE_DEVICES: GpuTestConfiguration = GpuTestConfiguration::new()
|
||||||
|
.parameters(TestParameters::default())
|
||||||
|
.run_sync(|_| {
|
||||||
|
use pollster::FutureExt as _;
|
||||||
|
|
||||||
let (device, queue) = adapter
|
fn create_device_and_queue() -> (wgpu::Device, wgpu::Queue) {
|
||||||
.request_device(&wgpu::DeviceDescriptor::default(), None)
|
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||||
.block_on()
|
backends: wgpu::util::backend_bits_from_env().unwrap_or(wgpu::Backends::all()),
|
||||||
.expect("failed to create device");
|
dx12_shader_compiler: wgpu::util::dx12_shader_compiler_from_env()
|
||||||
|
.unwrap_or_default(),
|
||||||
|
gles_minor_version: wgpu::util::gles_minor_version_from_env().unwrap_or_default(),
|
||||||
|
flags: wgpu::InstanceFlags::advanced_debugging().with_env(),
|
||||||
|
});
|
||||||
|
|
||||||
instance.poll_all(false);
|
let adapter = wgpu::util::initialize_adapter_from_env_or_default(&instance, None)
|
||||||
|
.block_on()
|
||||||
|
.expect("failed to create adapter");
|
||||||
|
|
||||||
let pre_report = instance.generate_report().unwrap().unwrap();
|
adapter
|
||||||
|
.request_device(&wgpu::DeviceDescriptor::default(), None)
|
||||||
|
.block_on()
|
||||||
|
.expect("failed to create device")
|
||||||
|
}
|
||||||
|
|
||||||
drop(queue);
|
let _ = vec![create_device_and_queue(), create_device_and_queue()];
|
||||||
drop(device);
|
});
|
||||||
let post_report = instance.generate_report().unwrap().unwrap();
|
|
||||||
assert_ne!(
|
|
||||||
pre_report, post_report,
|
|
||||||
"Queue and Device has not been dropped as expected"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
|
#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
|
||||||
#[gpu_test]
|
#[gpu_test]
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use glow::HasContext;
|
use glow::HasContext;
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
use parking_lot::{Mutex, MutexGuard, RwLock};
|
use parking_lot::{Mutex, MutexGuard, RwLock};
|
||||||
|
|
||||||
use std::{ffi, os::raw, ptr, rc::Rc, sync::Arc, time::Duration};
|
use std::{collections::HashMap, ffi, os::raw, ptr, rc::Rc, sync::Arc, time::Duration};
|
||||||
|
|
||||||
/// The amount of time to wait while trying to obtain a lock to the adapter context
|
/// The amount of time to wait while trying to obtain a lock to the adapter context
|
||||||
const CONTEXT_LOCK_TIMEOUT_SECS: u64 = 1;
|
const CONTEXT_LOCK_TIMEOUT_SECS: u64 = 1;
|
||||||
@ -432,6 +433,45 @@ struct Inner {
|
|||||||
srgb_kind: SrgbFrameBufferKind,
|
srgb_kind: SrgbFrameBufferKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Different calls to `eglGetPlatformDisplay` may return the same `Display`, making it a global
|
||||||
|
// state of all our `EglContext`s. This forces us to track the number of such context to prevent
|
||||||
|
// terminating the display if it's currently used by another `EglContext`.
|
||||||
|
static DISPLAYS_REFERENCE_COUNT: Lazy<Mutex<HashMap<usize, usize>>> = Lazy::new(Default::default);
|
||||||
|
|
||||||
|
fn initialize_display(
|
||||||
|
egl: &EglInstance,
|
||||||
|
display: khronos_egl::Display,
|
||||||
|
) -> Result<(i32, i32), khronos_egl::Error> {
|
||||||
|
let mut guard = DISPLAYS_REFERENCE_COUNT.lock();
|
||||||
|
*guard.entry(display.as_ptr() as usize).or_default() += 1;
|
||||||
|
|
||||||
|
// We don't need to check the reference count here since according to the `eglInitialize`
|
||||||
|
// documentation, initializing an already initialized EGL display connection has no effect
|
||||||
|
// besides returning the version numbers.
|
||||||
|
egl.initialize(display)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn terminate_display(
|
||||||
|
egl: &EglInstance,
|
||||||
|
display: khronos_egl::Display,
|
||||||
|
) -> Result<(), khronos_egl::Error> {
|
||||||
|
let key = &(display.as_ptr() as usize);
|
||||||
|
let mut guard = DISPLAYS_REFERENCE_COUNT.lock();
|
||||||
|
let count_ref = guard
|
||||||
|
.get_mut(key)
|
||||||
|
.expect("Attempted to decref a display before incref was called");
|
||||||
|
|
||||||
|
if *count_ref > 1 {
|
||||||
|
*count_ref -= 1;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
guard.remove(key);
|
||||||
|
|
||||||
|
egl.terminate(display)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Inner {
|
impl Inner {
|
||||||
fn create(
|
fn create(
|
||||||
flags: wgt::InstanceFlags,
|
flags: wgt::InstanceFlags,
|
||||||
@ -439,7 +479,7 @@ impl Inner {
|
|||||||
display: khronos_egl::Display,
|
display: khronos_egl::Display,
|
||||||
force_gles_minor_version: wgt::Gles3MinorVersion,
|
force_gles_minor_version: wgt::Gles3MinorVersion,
|
||||||
) -> Result<Self, crate::InstanceError> {
|
) -> Result<Self, crate::InstanceError> {
|
||||||
let version = egl.initialize(display).map_err(|e| {
|
let version = initialize_display(&egl, display).map_err(|e| {
|
||||||
crate::InstanceError::with_source(
|
crate::InstanceError::with_source(
|
||||||
String::from("failed to initialize EGL display connection"),
|
String::from("failed to initialize EGL display connection"),
|
||||||
e,
|
e,
|
||||||
@ -608,7 +648,8 @@ impl Drop for Inner {
|
|||||||
{
|
{
|
||||||
log::warn!("Error in destroy_context: {:?}", e);
|
log::warn!("Error in destroy_context: {:?}", e);
|
||||||
}
|
}
|
||||||
if let Err(e) = self.egl.instance.terminate(self.egl.display) {
|
|
||||||
|
if let Err(e) = terminate_display(&self.egl.instance, self.egl.display) {
|
||||||
log::warn!("Error in terminate: {:?}", e);
|
log::warn!("Error in terminate: {:?}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -778,7 +819,7 @@ impl crate::Instance<super::Api> for Instance {
|
|||||||
let display = unsafe {
|
let display = unsafe {
|
||||||
egl.get_platform_display(
|
egl.get_platform_display(
|
||||||
EGL_PLATFORM_SURFACELESS_MESA,
|
EGL_PLATFORM_SURFACELESS_MESA,
|
||||||
std::ptr::null_mut(),
|
khronos_egl::DEFAULT_DISPLAY,
|
||||||
&[khronos_egl::ATTRIB_NONE],
|
&[khronos_egl::ATTRIB_NONE],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user