mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
Use bytemuck instead of slice::from_raw_parts for transmutes (#7376)
This commit is contained in:
parent
c6286791fe
commit
4687973c9a
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -4884,6 +4884,7 @@ name = "wgpu-types"
|
||||
version = "24.0.0"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"bytemuck",
|
||||
"js-sys",
|
||||
"log",
|
||||
"serde",
|
||||
|
||||
@ -91,7 +91,6 @@ bit-set = { version = "0.8", default-features = false }
|
||||
bit-vec = { version = "0.8", default-features = false }
|
||||
bitflags = "2.9"
|
||||
bytemuck = { version = "1.22", features = [
|
||||
"derive",
|
||||
"extern_crate_alloc",
|
||||
"min_const_generics",
|
||||
] }
|
||||
|
||||
@ -21,12 +21,12 @@ struct Globals {
|
||||
}
|
||||
|
||||
#[repr(C, align(256))]
|
||||
#[derive(Clone, Copy, Zeroable)]
|
||||
#[derive(Clone, Copy, Pod, Zeroable)]
|
||||
struct Bunny {
|
||||
position: [f32; 2],
|
||||
velocity: [f32; 2],
|
||||
color: u32,
|
||||
_pad: u32,
|
||||
_pad: [u32; (256 - 20) / 4],
|
||||
}
|
||||
|
||||
impl Bunny {
|
||||
@ -81,7 +81,7 @@ impl Example {
|
||||
position: [0.0, 0.5 * (self.extent[1] as f32)],
|
||||
velocity: [speed, 0.0],
|
||||
color,
|
||||
_pad: 0,
|
||||
_pad: Zeroable::zeroed(),
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -98,12 +98,7 @@ impl Example {
|
||||
}
|
||||
|
||||
let uniform_alignment = device.limits().min_uniform_buffer_offset_alignment;
|
||||
queue.write_buffer(&self.local_buffer, 0, unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
self.bunnies.as_ptr() as *const u8,
|
||||
self.bunnies.len() * uniform_alignment as usize,
|
||||
)
|
||||
});
|
||||
queue.write_buffer(&self.local_buffer, 0, bytemuck::cast_slice(&self.bunnies));
|
||||
|
||||
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
|
||||
{
|
||||
|
||||
@ -76,7 +76,14 @@ observe_locks = ["std", "dep:ron", "serde/serde_derive"]
|
||||
serde = ["dep:serde", "wgpu-types/serde", "arrayvec/serde", "hashbrown/serde"]
|
||||
|
||||
## Enable API tracing.
|
||||
trace = ["serde", "std", "dep:ron", "naga/serialize", "wgpu-types/trace"]
|
||||
trace = [
|
||||
"serde",
|
||||
"std",
|
||||
"dep:ron",
|
||||
"naga/serialize",
|
||||
"wgpu-types/trace",
|
||||
"dep:bytemuck",
|
||||
]
|
||||
|
||||
## Enable API replaying
|
||||
replay = ["serde", "naga/deserialize"]
|
||||
|
||||
@ -964,9 +964,7 @@ impl Global {
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
if let Some(ref mut trace) = *device.trace.lock() {
|
||||
let data = trace.make_binary("spv", unsafe {
|
||||
core::slice::from_raw_parts(source.as_ptr().cast::<u8>(), source.len() * 4)
|
||||
});
|
||||
let data = trace.make_binary("spv", bytemuck::cast_slice(&source));
|
||||
trace.add(trace::Action::CreateShaderModule {
|
||||
id: fid.id(),
|
||||
desc: desc.clone(),
|
||||
|
||||
@ -88,6 +88,7 @@ vulkan = [
|
||||
"dep:android_system_properties",
|
||||
"dep:arrayvec",
|
||||
"dep:ash",
|
||||
"dep:bytemuck",
|
||||
"dep:gpu-alloc",
|
||||
"dep:gpu-descriptor",
|
||||
"dep:hashbrown",
|
||||
@ -127,6 +128,7 @@ dx12 = [
|
||||
"naga/hlsl-out",
|
||||
"dep:arrayvec",
|
||||
"dep:bit-set",
|
||||
"dep:bytemuck",
|
||||
"dep:hashbrown",
|
||||
"dep:libloading",
|
||||
"dep:log",
|
||||
@ -208,6 +210,7 @@ thiserror.workspace = true
|
||||
|
||||
# Target agnostic dependencies used only in backends.
|
||||
arrayvec = { workspace = true, optional = true }
|
||||
bytemuck = { workspace = true, optional = true, features = ["derive"] }
|
||||
hashbrown = { workspace = true, optional = true }
|
||||
log = { workspace = true, optional = true }
|
||||
once_cell = { workspace = true, optional = true }
|
||||
@ -216,7 +219,6 @@ profiling = { workspace = true, optional = true, default-features = false }
|
||||
rustc-hash = { workspace = true, optional = true }
|
||||
|
||||
# Backend: GLES
|
||||
bytemuck = { workspace = true, optional = true }
|
||||
glow = { workspace = true, optional = true }
|
||||
cfg-if = { workspace = true, optional = true }
|
||||
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
slice,
|
||||
string::{String, ToString as _},
|
||||
};
|
||||
|
||||
@ -48,18 +47,12 @@ unsafe extern "system" fn output_debug_string_handler(
|
||||
return Debug::EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
let message = match record.ExceptionCode {
|
||||
Foundation::DBG_PRINTEXCEPTION_C => String::from_utf8_lossy(unsafe {
|
||||
slice::from_raw_parts(
|
||||
record.ExceptionInformation[1] as *const u8,
|
||||
record.ExceptionInformation[0],
|
||||
)
|
||||
}),
|
||||
Foundation::DBG_PRINTEXCEPTION_WIDE_C => Cow::Owned(String::from_utf16_lossy(unsafe {
|
||||
slice::from_raw_parts(
|
||||
record.ExceptionInformation[1] as *const u16,
|
||||
record.ExceptionInformation[0],
|
||||
)
|
||||
})),
|
||||
Foundation::DBG_PRINTEXCEPTION_C => {
|
||||
String::from_utf8_lossy(bytemuck::cast_slice(&record.ExceptionInformation))
|
||||
}
|
||||
Foundation::DBG_PRINTEXCEPTION_WIDE_C => Cow::Owned(String::from_utf16_lossy(
|
||||
bytemuck::cast_slice(&record.ExceptionInformation),
|
||||
)),
|
||||
_ => return Debug::EXCEPTION_CONTINUE_SEARCH,
|
||||
};
|
||||
|
||||
|
||||
@ -2,13 +2,14 @@ use std::{
|
||||
borrow::Cow,
|
||||
ffi, mem,
|
||||
num::NonZeroU32,
|
||||
ptr, slice,
|
||||
ptr,
|
||||
string::{String, ToString as _},
|
||||
sync::Arc,
|
||||
time::{Duration, Instant},
|
||||
vec::Vec,
|
||||
};
|
||||
|
||||
use bytemuck::TransparentWrapper;
|
||||
use parking_lot::Mutex;
|
||||
use windows::{
|
||||
core::Interface as _,
|
||||
@ -2362,13 +2363,9 @@ impl crate::Device for super::Device {
|
||||
_bitfield2: 0,
|
||||
AccelerationStructure: instance.blas_address,
|
||||
};
|
||||
let temp: *const _ = &temp;
|
||||
unsafe {
|
||||
slice::from_raw_parts(
|
||||
temp.cast::<u8>(),
|
||||
size_of::<Direct3D12::D3D12_RAYTRACING_INSTANCE_DESC>(),
|
||||
)
|
||||
.to_vec()
|
||||
}
|
||||
|
||||
wgt::bytemuck_wrapper!(unsafe struct Desc(Direct3D12::D3D12_RAYTRACING_INSTANCE_DESC));
|
||||
|
||||
bytemuck::bytes_of(&Desc::wrap(temp)).to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use alloc::string::String;
|
||||
use core::{mem, ops::Range, slice};
|
||||
use core::{mem, ops::Range};
|
||||
|
||||
use arrayvec::ArrayVec;
|
||||
|
||||
@ -84,7 +84,7 @@ impl super::CommandBuffer {
|
||||
}
|
||||
|
||||
fn add_push_constant_data(&mut self, data: &[u32]) -> Range<u32> {
|
||||
let data_raw = unsafe { slice::from_raw_parts(data.as_ptr().cast(), size_of_val(data)) };
|
||||
let data_raw = bytemuck::cast_slice(data);
|
||||
let start = self.data_bytes.len();
|
||||
assert!(start < u32::MAX as usize);
|
||||
self.data_bytes.extend_from_slice(data_raw);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec;
|
||||
use core::{slice, sync::atomic::Ordering};
|
||||
use core::sync::atomic::Ordering;
|
||||
|
||||
use arrayvec::ArrayVec;
|
||||
use glow::HasContext;
|
||||
@ -1039,12 +1039,7 @@ impl super::Queue {
|
||||
};
|
||||
temp_query_results.push(result);
|
||||
}
|
||||
let query_data = unsafe {
|
||||
slice::from_raw_parts(
|
||||
temp_query_results.as_ptr().cast::<u8>(),
|
||||
temp_query_results.len() * size_of::<u64>(),
|
||||
)
|
||||
};
|
||||
let query_data = bytemuck::cast_slice(&temp_query_results);
|
||||
match dst.raw {
|
||||
Some(buffer) => {
|
||||
unsafe { gl.bind_buffer(dst_target, Some(buffer)) };
|
||||
|
||||
@ -3,7 +3,7 @@ use super::conv;
|
||||
use arrayvec::ArrayVec;
|
||||
use ash::vk;
|
||||
|
||||
use std::{mem, ops::Range, slice};
|
||||
use std::{mem, ops::Range};
|
||||
|
||||
const ALLOCATION_GRANULARITY: u32 = 16;
|
||||
const DST_IMAGE_LAYOUT: vk::ImageLayout = vk::ImageLayout::TRANSFER_DST_OPTIMAL;
|
||||
@ -900,7 +900,7 @@ impl crate::CommandEncoder for super::CommandEncoder {
|
||||
layout.raw,
|
||||
conv::map_shader_stage(stages),
|
||||
offset_bytes,
|
||||
slice::from_raw_parts(data.as_ptr().cast(), data.len() * 4),
|
||||
bytemuck::cast_slice(data),
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ use std::{
|
||||
ffi::{CStr, CString},
|
||||
mem::{self, MaybeUninit},
|
||||
num::NonZeroU32,
|
||||
ptr, slice,
|
||||
ptr,
|
||||
sync::Arc,
|
||||
vec::Vec,
|
||||
};
|
||||
@ -2867,10 +2867,7 @@ impl crate::Device for super::Device {
|
||||
shader_binding_table_record_offset_and_flags: 0,
|
||||
acceleration_structure_reference: instance.blas_address,
|
||||
};
|
||||
let temp: *const _ = &temp;
|
||||
unsafe {
|
||||
slice::from_raw_parts::<u8>(temp.cast::<u8>(), size_of::<RawTlasInstance>()).to_vec()
|
||||
}
|
||||
bytemuck::bytes_of(&temp).to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -47,6 +47,7 @@ use std::{
|
||||
|
||||
use arrayvec::ArrayVec;
|
||||
use ash::{ext, khr, vk};
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use hashbrown::HashSet;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
|
||||
@ -1489,7 +1490,7 @@ fn get_lost_err() -> crate::DeviceError {
|
||||
crate::DeviceError::Lost
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Copy, Pod, Zeroable)]
|
||||
#[repr(C)]
|
||||
struct RawTlasInstance {
|
||||
transform: [f32; 12],
|
||||
|
||||
@ -48,6 +48,7 @@ trace = ["std"]
|
||||
|
||||
[dependencies]
|
||||
bitflags = { workspace = true, features = ["serde"] }
|
||||
bytemuck = { workspace = true, features = ["derive"] }
|
||||
log.workspace = true
|
||||
thiserror = { workspace = true, optional = true }
|
||||
serde = { workspace = true, default-features = false, features = [
|
||||
|
||||
25
wgpu-types/src/cast_utils.rs
Normal file
25
wgpu-types/src/cast_utils.rs
Normal file
@ -0,0 +1,25 @@
|
||||
/// Wrapper to unsafely define a wrapper type that can be used with `bytemuck`'s traits.
|
||||
///
|
||||
/// This is very useful as it allows us to use bytemuck on foreign types. Despite the
|
||||
/// unsafe assertion, it means that bytemuck is handling all the actual casting,
|
||||
/// so we can't screw up size or alignment handling.
|
||||
///
|
||||
/// Once wrapped you can use the [`bytemuck::TransparentWrapper`] methods and
|
||||
/// all the free methods that come with [`bytemuck::Pod`] and [`bytemuck::Zeroable`].
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Once wrapped, the resulting type must follow all the invariants
|
||||
/// of the [`bytemuck::Pod`] and [`bytemuck::Zeroable`] traits.
|
||||
#[macro_export]
|
||||
macro_rules! bytemuck_wrapper {
|
||||
(unsafe struct $name:ident($inner:ty)) => {
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(transparent)]
|
||||
struct $name($inner);
|
||||
|
||||
unsafe impl bytemuck::Zeroable for $name {}
|
||||
unsafe impl bytemuck::Pod for $name {}
|
||||
unsafe impl bytemuck::TransparentWrapper<$inner> for $name {}
|
||||
};
|
||||
}
|
||||
@ -23,6 +23,8 @@ use core::{
|
||||
ops::Range,
|
||||
};
|
||||
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
|
||||
#[cfg(any(feature = "serde", test))]
|
||||
use {
|
||||
alloc::format,
|
||||
@ -30,6 +32,7 @@ use {
|
||||
};
|
||||
|
||||
pub mod assertions;
|
||||
mod cast_utils;
|
||||
mod counters;
|
||||
mod env;
|
||||
mod features;
|
||||
@ -7214,7 +7217,7 @@ bitflags::bitflags! {
|
||||
|
||||
/// Argument buffer layout for `draw_indirect` commands.
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[derive(Copy, Clone, Debug, Default, Pod, Zeroable)]
|
||||
pub struct DrawIndirectArgs {
|
||||
/// The number of vertices to draw.
|
||||
pub vertex_count: u32,
|
||||
@ -7232,18 +7235,13 @@ impl DrawIndirectArgs {
|
||||
/// Returns the bytes representation of the struct, ready to be written in a buffer.
|
||||
#[must_use]
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
unsafe {
|
||||
core::mem::transmute(core::slice::from_raw_parts(
|
||||
core::ptr::from_ref(self).cast::<u8>(),
|
||||
size_of::<Self>(),
|
||||
))
|
||||
}
|
||||
bytemuck::bytes_of(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Argument buffer layout for `draw_indexed_indirect` commands.
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[derive(Copy, Clone, Debug, Default, Pod, Zeroable)]
|
||||
pub struct DrawIndexedIndirectArgs {
|
||||
/// The number of indices to draw.
|
||||
pub index_count: u32,
|
||||
@ -7263,18 +7261,13 @@ impl DrawIndexedIndirectArgs {
|
||||
/// Returns the bytes representation of the struct, ready to be written in a buffer.
|
||||
#[must_use]
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
unsafe {
|
||||
core::mem::transmute(core::slice::from_raw_parts(
|
||||
core::ptr::from_ref(self).cast::<u8>(),
|
||||
size_of::<Self>(),
|
||||
))
|
||||
}
|
||||
bytemuck::bytes_of(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Argument buffer layout for `dispatch_indirect` commands.
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[derive(Copy, Clone, Debug, Default, Pod, Zeroable)]
|
||||
pub struct DispatchIndirectArgs {
|
||||
/// The number of work groups in X dimension.
|
||||
pub x: u32,
|
||||
@ -7288,12 +7281,7 @@ impl DispatchIndirectArgs {
|
||||
/// Returns the bytes representation of the struct, ready to be written into a buffer.
|
||||
#[must_use]
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
unsafe {
|
||||
core::mem::transmute(core::slice::from_raw_parts(
|
||||
core::ptr::from_ref(self).cast::<u8>(),
|
||||
size_of::<Self>(),
|
||||
))
|
||||
}
|
||||
bytemuck::bytes_of(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user