#[cfg(std)]
mod belt;
mod device;
mod encoder;
mod init;
mod mutex;
mod texture_blitter;
use alloc::{borrow::Cow, format, string::String, vec};
use core::ptr::copy_nonoverlapping;
#[cfg(std)]
pub use belt::StagingBelt;
pub use device::{BufferInitDescriptor, DeviceExt};
pub use encoder::RenderEncoder;
pub use init::*;
#[cfg(feature = "wgsl")]
pub use texture_blitter::{TextureBlitter, TextureBlitterBuilder};
pub use wgt::{
math::*, DispatchIndirectArgs, DrawIndexedIndirectArgs, DrawIndirectArgs, TextureDataOrder,
};
pub(crate) use mutex::Mutex;
use crate::dispatch;
#[cfg(feature = "spirv")]
pub fn make_spirv(data: &[u8]) -> super::ShaderSource<'_> {
super::ShaderSource::SpirV(make_spirv_raw(data))
}
pub fn make_spirv_raw(data: &[u8]) -> Cow<'_, [u32]> {
const MAGIC_NUMBER: u32 = 0x0723_0203;
assert_eq!(
data.len() % size_of::<u32>(),
0,
"data size is not a multiple of 4"
);
assert_ne!(data.len(), 0, "data size must be larger than zero");
let mut words = if data.as_ptr().align_offset(align_of::<u32>()) == 0 {
let (pre, words, post) = unsafe { data.align_to::<u32>() };
debug_assert!(pre.is_empty());
debug_assert!(post.is_empty());
Cow::from(words)
} else {
let mut words = vec![0u32; data.len() / size_of::<u32>()];
unsafe {
copy_nonoverlapping(data.as_ptr(), words.as_mut_ptr() as *mut u8, data.len());
}
Cow::from(words)
};
if words[0] == MAGIC_NUMBER.swap_bytes() {
for word in Cow::to_mut(&mut words) {
*word = word.swap_bytes();
}
}
assert_eq!(
words[0], MAGIC_NUMBER,
"wrong magic word {:x}. Make sure you are using a binary SPIRV file.",
words[0]
);
words
}
pub struct DownloadBuffer {
_gpu_buffer: super::Buffer,
mapped_range: dispatch::DispatchBufferMappedRange,
}
impl DownloadBuffer {
pub fn read_buffer(
device: &super::Device,
queue: &super::Queue,
buffer: &super::BufferSlice<'_>,
callback: impl FnOnce(Result<Self, super::BufferAsyncError>) + Send + 'static,
) {
let size = buffer.size.into();
let download = device.create_buffer(&super::BufferDescriptor {
size,
usage: super::BufferUsages::COPY_DST | super::BufferUsages::MAP_READ,
mapped_at_creation: false,
label: None,
});
let mut encoder =
device.create_command_encoder(&super::CommandEncoderDescriptor { label: None });
encoder.copy_buffer_to_buffer(buffer.buffer, buffer.offset, &download, 0, size);
let command_buffer: super::CommandBuffer = encoder.finish();
queue.submit(Some(command_buffer));
download
.clone()
.slice(..)
.map_async(super::MapMode::Read, move |result| {
if let Err(e) = result {
callback(Err(e));
return;
}
let mapped_range = download.inner.get_mapped_range(0..size);
callback(Ok(Self {
_gpu_buffer: download,
mapped_range,
}));
});
}
}
impl core::ops::Deref for DownloadBuffer {
type Target = [u8];
fn deref(&self) -> &[u8] {
self.mapped_range.slice()
}
}
pub fn pipeline_cache_key(adapter_info: &wgt::AdapterInfo) -> Option<String> {
match adapter_info.backend {
wgt::Backend::Vulkan => Some(format!(
"wgpu_pipeline_cache_vulkan_{}_{}",
adapter_info.vendor, adapter_info.device
)),
_ => None,
}
}
pub trait TextureFormatExt {
#[cfg(wgpu_core)]
fn from_storage_format(storage_format: crate::naga::StorageFormat) -> Self;
#[cfg(wgpu_core)]
fn to_storage_format(&self) -> Option<crate::naga::StorageFormat>;
}
impl TextureFormatExt for wgt::TextureFormat {
#[cfg(wgpu_core)]
fn from_storage_format(storage_format: crate::naga::StorageFormat) -> Self {
wgc::map_storage_format_from_naga(storage_format)
}
#[cfg(wgpu_core)]
fn to_storage_format(&self) -> Option<crate::naga::StorageFormat> {
wgc::map_storage_format_to_naga(*self)
}
}