Skip to content

Commit 289d0e5

Browse files
kpreidWumpf
authored andcommitted
Allow the "gles" backend to (theoretically) compile on no_std targets.
This entirely consists of conditionally replacing `Mutex` with `RefCell`, then making sure that this doesn’t accidentally happen if we are also exposing `Send + Sync`.
1 parent 67f1554 commit 289d0e5

File tree

6 files changed

+62
-25
lines changed

6 files changed

+62
-25
lines changed

wgpu-hal/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ gles = [
104104
"naga/glsl-out",
105105
"dep:arrayvec",
106106
"dep:bytemuck",
107+
"dep:cfg-if",
107108
"dep:glow",
108109
"dep:glutin_wgl_sys",
109110
"dep:hashbrown",
@@ -217,6 +218,7 @@ rustc-hash = { workspace = true, optional = true }
217218
# Backend: GLES
218219
bytemuck = { workspace = true, optional = true }
219220
glow = { workspace = true, optional = true }
221+
cfg-if = { workspace = true, optional = true }
220222

221223
########################
222224
### Platform: Native ###

wgpu-hal/build.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,18 @@ fn main() {
99
Emscripten: { all(target_os = "emscripten", gles) },
1010
dx12: { all(target_os = "windows", feature = "dx12") },
1111
gles: { all(feature = "gles") },
12+
// Within the GL ES backend, use `std` and be Send + Sync only if we are using a target
13+
// that, among the ones where the GL ES backend is supported, has `std`.
14+
gles_with_std: { all(
15+
feature = "gles",
16+
any(
17+
not(target_arch = "wasm32"),
18+
// Accept wasm32-unknown-unknown, which uniquely has a stub `std`
19+
all(target_vendor = "unknown", target_os = "unknown"),
20+
// Accept wasm32-unknown-emscripten and similar, which has a real `std`
21+
target_os = "emscripten"
22+
)
23+
) },
1224
metal: { all(target_vendor = "apple", feature = "metal") },
1325
vulkan: { all(not(target_arch = "wasm32"), feature = "vulkan") },
1426
// ⚠️ Keep in sync with target.cfg() definition in Cargo.toml and cfg_alias in `wgpu` crate ⚠️

wgpu-hal/src/gles/device.rs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@ use alloc::{
22
borrow::ToOwned, format, string::String, string::ToString as _, sync::Arc, vec, vec::Vec,
33
};
44
use core::{cmp::max, convert::TryInto, num::NonZeroU32, ptr, sync::atomic::Ordering};
5-
use std::sync::Mutex;
65

76
use arrayvec::ArrayVec;
87
use glow::HasContext;
98
use naga::FastHashMap;
109

11-
use super::{conv, PrivateCapabilities};
10+
use super::{conv, lock, MaybeMutex, PrivateCapabilities};
1211
use crate::auxil::map_naga_stage;
1312
use crate::TlasInstance;
1413

@@ -526,8 +525,8 @@ impl crate::Device for super::Device {
526525
target,
527526
size: desc.size,
528527
map_flags: 0,
529-
data: Some(Arc::new(Mutex::new(vec![0; desc.size as usize]))),
530-
offset_of_current_mapping: Arc::new(Mutex::new(0)),
528+
data: Some(Arc::new(MaybeMutex::new(vec![0; desc.size as usize]))),
529+
offset_of_current_mapping: Arc::new(MaybeMutex::new(0)),
531530
});
532531
}
533532

@@ -614,7 +613,7 @@ impl crate::Device for super::Device {
614613
}
615614

616615
let data = if emulate_map && desc.usage.contains(wgt::BufferUses::MAP_READ) {
617-
Some(Arc::new(Mutex::new(vec![0; desc.size as usize])))
616+
Some(Arc::new(MaybeMutex::new(vec![0; desc.size as usize])))
618617
} else {
619618
None
620619
};
@@ -627,7 +626,7 @@ impl crate::Device for super::Device {
627626
size: desc.size,
628627
map_flags,
629628
data,
630-
offset_of_current_mapping: Arc::new(Mutex::new(0)),
629+
offset_of_current_mapping: Arc::new(MaybeMutex::new(0)),
631630
})
632631
}
633632

@@ -652,20 +651,20 @@ impl crate::Device for super::Device {
652651
let is_coherent = buffer.map_flags & glow::MAP_COHERENT_BIT != 0;
653652
let ptr = match buffer.raw {
654653
None => {
655-
let mut vec = buffer.data.as_ref().unwrap().lock().unwrap();
654+
let mut vec = lock(buffer.data.as_ref().unwrap());
656655
let slice = &mut vec.as_mut_slice()[range.start as usize..range.end as usize];
657656
slice.as_mut_ptr()
658657
}
659658
Some(raw) => {
660659
let gl = &self.shared.context.lock();
661660
unsafe { gl.bind_buffer(buffer.target, Some(raw)) };
662661
let ptr = if let Some(ref map_read_allocation) = buffer.data {
663-
let mut guard = map_read_allocation.lock().unwrap();
662+
let mut guard = lock(map_read_allocation);
664663
let slice = guard.as_mut_slice();
665664
unsafe { self.shared.get_buffer_sub_data(gl, buffer.target, 0, slice) };
666665
slice.as_mut_ptr()
667666
} else {
668-
*buffer.offset_of_current_mapping.lock().unwrap() = range.start;
667+
*lock(&buffer.offset_of_current_mapping) = range.start;
669668
unsafe {
670669
gl.map_buffer_range(
671670
buffer.target,
@@ -691,7 +690,7 @@ impl crate::Device for super::Device {
691690
unsafe { gl.bind_buffer(buffer.target, Some(raw)) };
692691
unsafe { gl.unmap_buffer(buffer.target) };
693692
unsafe { gl.bind_buffer(buffer.target, None) };
694-
*buffer.offset_of_current_mapping.lock().unwrap() = 0;
693+
*lock(&buffer.offset_of_current_mapping) = 0;
695694
}
696695
}
697696
}
@@ -704,8 +703,7 @@ impl crate::Device for super::Device {
704703
let gl = &self.shared.context.lock();
705704
unsafe { gl.bind_buffer(buffer.target, Some(raw)) };
706705
for range in ranges {
707-
let offset_of_current_mapping =
708-
*buffer.offset_of_current_mapping.lock().unwrap();
706+
let offset_of_current_mapping = *lock(&buffer.offset_of_current_mapping);
709707
unsafe {
710708
gl.flush_mapped_buffer_range(
711709
buffer.target,

wgpu-hal/src/gles/mod.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -346,8 +346,8 @@ pub struct Buffer {
346346
target: BindTarget,
347347
size: wgt::BufferAddress,
348348
map_flags: u32,
349-
data: Option<Arc<std::sync::Mutex<Vec<u8>>>>,
350-
offset_of_current_mapping: Arc<std::sync::Mutex<wgt::BufferAddress>>,
349+
data: Option<Arc<MaybeMutex<Vec<u8>>>>,
350+
offset_of_current_mapping: Arc<MaybeMutex<wgt::BufferAddress>>,
351351
}
352352

353353
#[cfg(send_sync)]
@@ -1093,3 +1093,26 @@ fn gl_debug_message_callback(source: u32, gltype: u32, id: u32, severity: u32, m
10931093
crate::VALIDATION_CANARY.add(message.to_string());
10941094
}
10951095
}
1096+
1097+
// If we are using `std`, then use `Mutex` to provide `Send` and `Sync`
1098+
cfg_if::cfg_if! {
1099+
if #[cfg(gles_with_std)] {
1100+
type MaybeMutex<T> = std::sync::Mutex<T>;
1101+
1102+
fn lock<T>(mutex: &MaybeMutex<T>) -> std::sync::MutexGuard<'_, T> {
1103+
mutex.lock().unwrap()
1104+
}
1105+
} else {
1106+
// It should be impossible for any build configuration to trigger this error
1107+
// It is intended only as a guard against changes elsewhere causing the use of
1108+
// `RefCell` here to become unsound.
1109+
#[cfg(all(send_sync, not(feature = "fragile-send-sync-non-atomic-wasm")))]
1110+
compile_error!("cannot provide non-fragile Send+Sync without std");
1111+
1112+
type MaybeMutex<T> = core::cell::RefCell<T>;
1113+
1114+
fn lock<T>(mutex: &MaybeMutex<T>) -> core::cell::RefMut<'_, T> {
1115+
mutex.borrow_mut()
1116+
}
1117+
}
1118+
}

wgpu-hal/src/gles/queue.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
use super::{conv::is_layered_target, Command as C, PrivateCapabilities};
21
use alloc::sync::Arc;
3-
use arrayvec::ArrayVec;
2+
use alloc::vec;
43
use core::{slice, sync::atomic::Ordering};
4+
5+
use arrayvec::ArrayVec;
56
use glow::HasContext;
67

8+
use super::{conv::is_layered_target, lock, Command as C, PrivateCapabilities};
9+
710
const DEBUG_ID: u32 = 0;
811

912
fn extract_marker<'a>(data: &'a [u8], range: &core::ops::Range<u32>) -> &'a str {
@@ -340,7 +343,7 @@ impl super::Queue {
340343
}
341344
}
342345
None => {
343-
dst.data.as_ref().unwrap().lock().unwrap().as_mut_slice()
346+
lock(dst.data.as_ref().unwrap()).as_mut_slice()
344347
[range.start as usize..range.end as usize]
345348
.fill(0);
346349
}
@@ -382,7 +385,7 @@ impl super::Queue {
382385
};
383386
}
384387
(Some(src), None) => {
385-
let mut data = dst.data.as_ref().unwrap().lock().unwrap();
388+
let mut data = lock(dst.data.as_ref().unwrap());
386389
let dst_data = &mut data.as_mut_slice()
387390
[copy.dst_offset as usize..copy.dst_offset as usize + size];
388391

@@ -397,7 +400,7 @@ impl super::Queue {
397400
};
398401
}
399402
(None, Some(dst)) => {
400-
let data = src.data.as_ref().unwrap().lock().unwrap();
403+
let data = lock(src.data.as_ref().unwrap());
401404
let src_data = &data.as_slice()
402405
[copy.src_offset as usize..copy.src_offset as usize + size];
403406
unsafe { gl.bind_buffer(copy_dst_target, Some(dst)) };
@@ -738,7 +741,7 @@ impl super::Queue {
738741
glow::PixelUnpackData::BufferOffset(copy.buffer_layout.offset as u32)
739742
}
740743
None => {
741-
buffer_data = src.data.as_ref().unwrap().lock().unwrap();
744+
buffer_data = lock(src.data.as_ref().unwrap());
742745
let src_data =
743746
&buffer_data.as_slice()[copy.buffer_layout.offset as usize..];
744747
glow::PixelUnpackData::Slice(Some(src_data))
@@ -802,7 +805,7 @@ impl super::Queue {
802805
)
803806
}
804807
None => {
805-
buffer_data = src.data.as_ref().unwrap().lock().unwrap();
808+
buffer_data = lock(src.data.as_ref().unwrap());
806809
let src_data = &buffer_data.as_slice()
807810
[(offset as usize)..(offset + bytes_in_upload) as usize];
808811
glow::CompressedPixelUnpackData::Slice(src_data)
@@ -883,7 +886,7 @@ impl super::Queue {
883886
glow::PixelPackData::BufferOffset(offset as u32)
884887
}
885888
None => {
886-
buffer_data = dst.data.as_ref().unwrap().lock().unwrap();
889+
buffer_data = lock(dst.data.as_ref().unwrap());
887890
let dst_data = &mut buffer_data.as_mut_slice()[offset as usize..];
888891
glow::PixelPackData::Slice(Some(dst_data))
889892
}
@@ -1054,7 +1057,7 @@ impl super::Queue {
10541057
};
10551058
}
10561059
None => {
1057-
let data = &mut dst.data.as_ref().unwrap().lock().unwrap();
1060+
let data = &mut lock(dst.data.as_ref().unwrap());
10581061
let len = query_data.len().min(data.len());
10591062
data[..len].copy_from_slice(&query_data[..len]);
10601063
}

wgpu-hal/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,7 @@
241241
extern crate alloc;
242242
extern crate wgpu_types as wgt;
243243
// Each of these backends needs `std` in some fashion; usually `std::thread` functions.
244-
// TODO(https://github.com/gfx-rs/wgpu/issues/6826): gles-WebGL backend should be made no-std
245-
#[cfg(any(dx12, gles, metal, vulkan))]
244+
#[cfg(any(dx12, gles_with_std, metal, vulkan))]
246245
#[macro_use]
247246
extern crate std;
248247

0 commit comments

Comments
 (0)