Vendor wgpu-hal 29.0.4 and i-slint-renderer-skia 1.17.1, unmodified

The Android develop view reads its frame back through memory (TD-1)
because wgpu's Vulkan swapchain never pre-rotates, and a portrait window
on this tablet's landscape panel then tears. The fix is a small patch to
each of these two crates, and this commit is only the ground it lands on:
both are byte-for-byte the crates.io sources the lockfile already
resolved, so the commits that follow are the patch and nothing else.

third_party/ is excluded from the workspace, or every path dependency
under the root would become a member and `--workspace` would test and
lint upstream code as ours. The README says how to carry the patches
across a Slint or wgpu bump, which matters because a stale version here
does not fail the build — cargo just warns and uses the unpatched crate.
This commit is contained in:
2026-09-25 04:18:39 -04:00
parent b5ae5c2be1
commit dc1add9dbb
112 changed files with 60304 additions and 4 deletions
+88
View File
@@ -0,0 +1,88 @@
use alloc::vec::Vec;
use core::{cell::UnsafeCell, ops::Range, ptr};
cfg_if::cfg_if! {
if #[cfg(supports_ptr_atomics)] {
use alloc::sync::Arc;
} else if #[cfg(feature = "portable-atomic")] {
use portable_atomic_util::Arc;
}
}
#[derive(Clone, Debug)]
pub struct Buffer {
/// This data is potentially accessed mutably in arbitrary non-overlapping slices,
/// so we must store it in `UnsafeCell` to avoid making any too-strong no-aliasing claims.
storage: Arc<UnsafeCell<[u8]>>,
/// Size of the allocation.
///
/// This is redundant with `storage.get().len()`, but that method is not
/// available until our MSRV is 1.79 or greater.
size: usize,
}
/// SAFETY:
/// This shared mutable data will not be accessed in a way which causes data races;
/// the obligation to do so is on the caller of the HAL API.
/// For safe code, `wgpu-core` validation manages appropriate access.
unsafe impl Send for Buffer {}
unsafe impl Sync for Buffer {}
impl Buffer {
pub(super) fn new(desc: &crate::BufferDescriptor) -> Result<Self, crate::DeviceError> {
let &crate::BufferDescriptor {
label: _,
size,
usage: _,
memory_flags: _,
} = desc;
let size = usize::try_from(size).map_err(|_| crate::DeviceError::OutOfMemory)?;
let mut vector: Vec<u8> = Vec::new();
vector
.try_reserve_exact(size)
.map_err(|_| crate::DeviceError::OutOfMemory)?;
vector.resize(size, 0);
let storage: Arc<[u8]> = Arc::from(vector);
debug_assert_eq!(storage.len(), size);
// SAFETY: `UnsafeCell<[u8]>` and `[u8]` have the same layout.
// This is just adding a wrapper type without changing any layout,
// because there is not currently a safe language/`std` way to accomplish this.
let storage: Arc<UnsafeCell<[u8]>> =
unsafe { Arc::from_raw(Arc::into_raw(storage) as *mut UnsafeCell<[u8]>) };
Ok(Buffer { storage, size })
}
/// Returns a pointer to the memory owned by this buffer within the given `range`.
///
/// This may be used to create any number of simultaneous pointers;
/// aliasing is only a concern when actually reading, writing, or converting the pointer
/// to a reference.
pub(super) fn get_slice_ptr(&self, range: crate::MemoryRange) -> *mut [u8] {
let base_ptr = self.storage.get();
let range = range_to_usize(range, self.size);
// We must obtain a slice pointer without ever creating a slice reference
// that could alias with another slice.
ptr::slice_from_raw_parts_mut(
// SAFETY: `range_to_usize` bounds checks this addition.
unsafe { base_ptr.cast::<u8>().add(range.start) },
range.len(),
)
}
}
/// Convert a [`crate::MemoryRange`] to `Range<usize>` and bounds check it.
fn range_to_usize(range: crate::MemoryRange, upper_bound: usize) -> Range<usize> {
// Note: these assertions should be impossible to trigger from safe code.
// We're doing them anyway since this entire backend is for testing
// (except for when it is an unused placeholder)
let start = usize::try_from(range.start).expect("range too large");
let end = usize::try_from(range.end).expect("range too large");
assert!(start <= end && end <= upper_bound, "range out of bounds");
start..end
}
+336
View File
@@ -0,0 +1,336 @@
use alloc::vec::Vec;
use core::mem;
use core::ops::Range;
use super::{Api, Buffer, DeviceResult, Resource};
/// Command buffer type, which performs double duty as the command encoder type too.
#[derive(Debug)]
pub struct CommandBuffer {
commands: Vec<Command>,
}
#[derive(Debug)]
enum Command {
ClearBuffer {
buffer: Buffer,
range: crate::MemoryRange,
},
CopyBufferToBuffer {
src: Buffer,
dst: Buffer,
regions: Vec<crate::BufferCopy>,
},
}
impl CommandBuffer {
/// # Safety
///
/// Must be called with appropriate synchronization for the resources affected by the command,
/// such as ensuring that buffers are not accessed by a command while aliasing references exist.
pub(crate) unsafe fn execute(&self) {
for command in &self.commands {
unsafe { command.execute() };
}
}
pub(crate) fn new() -> Self {
Self {
commands: Vec::new(),
}
}
}
impl crate::CommandEncoder for CommandBuffer {
type A = Api;
unsafe fn begin_encoding(&mut self, label: crate::Label) -> DeviceResult<()> {
assert!(self.commands.is_empty());
Ok(())
}
unsafe fn discard_encoding(&mut self) {
self.commands.clear();
}
unsafe fn end_encoding(&mut self) -> DeviceResult<CommandBuffer> {
Ok(CommandBuffer {
commands: mem::take(&mut self.commands),
})
}
unsafe fn reset_all<I>(&mut self, command_buffers: I) {}
unsafe fn transition_buffers<'a, T>(&mut self, barriers: T)
where
T: Iterator<Item = crate::BufferBarrier<'a, Buffer>>,
{
}
unsafe fn transition_textures<'a, T>(&mut self, barriers: T)
where
T: Iterator<Item = crate::TextureBarrier<'a, Resource>>,
{
}
unsafe fn clear_buffer(&mut self, buffer: &Buffer, range: crate::MemoryRange) {
self.commands.push(Command::ClearBuffer {
buffer: buffer.clone(),
range,
})
}
unsafe fn copy_buffer_to_buffer<T>(&mut self, src: &Buffer, dst: &Buffer, regions: T)
where
T: Iterator<Item = crate::BufferCopy>,
{
self.commands.push(Command::CopyBufferToBuffer {
src: src.clone(),
dst: dst.clone(),
regions: regions.collect(),
});
}
#[cfg(webgl)]
unsafe fn copy_external_image_to_texture<T>(
&mut self,
src: &wgt::CopyExternalImageSourceInfo,
dst: &Resource,
dst_premultiplication: bool,
regions: T,
) where
T: Iterator<Item = crate::TextureCopy>,
{
}
unsafe fn copy_texture_to_texture<T>(
&mut self,
src: &Resource,
src_usage: wgt::TextureUses,
dst: &Resource,
regions: T,
) {
// TODO: consider implementing this and other texture manipulation
}
unsafe fn copy_buffer_to_texture<T>(&mut self, src: &Buffer, dst: &Resource, regions: T) {
// TODO: consider implementing this and other texture manipulation
}
unsafe fn copy_texture_to_buffer<T>(
&mut self,
src: &Resource,
src_usage: wgt::TextureUses,
dst: &Buffer,
regions: T,
) {
// TODO: consider implementing this and other texture manipulation
}
unsafe fn begin_query(&mut self, set: &Resource, index: u32) {}
unsafe fn end_query(&mut self, set: &Resource, index: u32) {}
unsafe fn write_timestamp(&mut self, set: &Resource, index: u32) {}
unsafe fn read_acceleration_structure_compact_size(
&mut self,
acceleration_structure: &Resource,
buf: &Buffer,
) {
}
unsafe fn reset_queries(&mut self, set: &Resource, range: Range<u32>) {}
unsafe fn copy_query_results(
&mut self,
set: &Resource,
range: Range<u32>,
buffer: &Buffer,
offset: wgt::BufferAddress,
stride: wgt::BufferSize,
) {
}
// render
unsafe fn begin_render_pass(
&mut self,
desc: &crate::RenderPassDescriptor<Resource, Resource>,
) -> DeviceResult<()> {
Ok(())
}
unsafe fn end_render_pass(&mut self) {}
unsafe fn set_bind_group(
&mut self,
layout: &Resource,
index: u32,
group: &Resource,
dynamic_offsets: &[wgt::DynamicOffset],
) {
}
unsafe fn set_immediates(&mut self, layout: &Resource, offset_bytes: u32, data: &[u32]) {}
unsafe fn insert_debug_marker(&mut self, label: &str) {}
unsafe fn begin_debug_marker(&mut self, group_label: &str) {}
unsafe fn end_debug_marker(&mut self) {}
unsafe fn set_render_pipeline(&mut self, pipeline: &Resource) {}
unsafe fn set_index_buffer<'a>(
&mut self,
binding: crate::BufferBinding<'a, Buffer>,
format: wgt::IndexFormat,
) {
}
unsafe fn set_vertex_buffer<'a>(
&mut self,
index: u32,
binding: crate::BufferBinding<'a, Buffer>,
) {
}
unsafe fn set_viewport(&mut self, rect: &crate::Rect<f32>, depth_range: Range<f32>) {}
unsafe fn set_scissor_rect(&mut self, rect: &crate::Rect<u32>) {}
unsafe fn set_stencil_reference(&mut self, value: u32) {}
unsafe fn set_blend_constants(&mut self, color: &[f32; 4]) {}
unsafe fn draw(
&mut self,
first_vertex: u32,
vertex_count: u32,
first_instance: u32,
instance_count: u32,
) {
}
unsafe fn draw_indexed(
&mut self,
first_index: u32,
index_count: u32,
base_vertex: i32,
first_instance: u32,
instance_count: u32,
) {
}
unsafe fn draw_mesh_tasks(
&mut self,
group_count_x: u32,
group_count_y: u32,
group_count_z: u32,
) {
}
unsafe fn draw_indirect(
&mut self,
buffer: &Buffer,
offset: wgt::BufferAddress,
draw_count: u32,
) {
}
unsafe fn draw_indexed_indirect(
&mut self,
buffer: &Buffer,
offset: wgt::BufferAddress,
draw_count: u32,
) {
}
unsafe fn draw_mesh_tasks_indirect(
&mut self,
buffer: &<Self::A as crate::Api>::Buffer,
offset: wgt::BufferAddress,
draw_count: u32,
) {
}
unsafe fn draw_indirect_count(
&mut self,
buffer: &Buffer,
offset: wgt::BufferAddress,
count_buffer: &Buffer,
count_offset: wgt::BufferAddress,
max_count: u32,
) {
}
unsafe fn draw_indexed_indirect_count(
&mut self,
buffer: &Buffer,
offset: wgt::BufferAddress,
count_buffer: &Buffer,
count_offset: wgt::BufferAddress,
max_count: u32,
) {
}
unsafe fn draw_mesh_tasks_indirect_count(
&mut self,
buffer: &<Self::A as crate::Api>::Buffer,
offset: wgt::BufferAddress,
count_buffer: &<Self::A as crate::Api>::Buffer,
count_offset: wgt::BufferAddress,
max_count: u32,
) {
}
// compute
unsafe fn begin_compute_pass(&mut self, desc: &crate::ComputePassDescriptor<Resource>) {}
unsafe fn end_compute_pass(&mut self) {}
unsafe fn set_compute_pipeline(&mut self, pipeline: &Resource) {}
unsafe fn dispatch(&mut self, count: [u32; 3]) {}
unsafe fn dispatch_indirect(&mut self, buffer: &Buffer, offset: wgt::BufferAddress) {}
unsafe fn build_acceleration_structures<'a, T>(
&mut self,
_descriptor_count: u32,
descriptors: T,
) where
Api: 'a,
T: IntoIterator<Item = crate::BuildAccelerationStructureDescriptor<'a, Buffer, Resource>>,
{
}
unsafe fn place_acceleration_structure_barrier(
&mut self,
_barriers: crate::AccelerationStructureBarrier,
) {
}
unsafe fn copy_acceleration_structure_to_acceleration_structure(
&mut self,
src: &Resource,
dst: &Resource,
copy: wgt::AccelerationStructureCopy,
) {
}
unsafe fn set_acceleration_structure_dependencies(
command_buffers: &[&CommandBuffer],
dependencies: &[&Resource],
) {
}
}
impl Command {
/// # Safety
///
/// Must be called with appropriate synchronization for the resources affected by the command,
/// such as ensuring that buffers are not accessed by a command while aliasing references exist.
unsafe fn execute(&self) {
match self {
Command::ClearBuffer { ref buffer, range } => {
// SAFETY:
// Caller is responsible for ensuring this does not alias.
let buffer_slice: &mut [u8] = unsafe { &mut *buffer.get_slice_ptr(range.clone()) };
buffer_slice.fill(0);
}
Command::CopyBufferToBuffer { src, dst, regions } => {
for &crate::BufferCopy {
src_offset,
dst_offset,
size,
} in regions
{
// SAFETY:
// Caller is responsible for ensuring this does not alias.
let src_region: &[u8] =
unsafe { &*src.get_slice_ptr(src_offset..src_offset + size.get()) };
let dst_region: &mut [u8] =
unsafe { &mut *dst.get_slice_ptr(dst_offset..dst_offset + size.get()) };
dst_region.copy_from_slice(src_region);
}
}
}
}
}
+507
View File
@@ -0,0 +1,507 @@
#![allow(unused_variables)]
use alloc::{string::String, vec, vec::Vec};
use core::{ptr, sync::atomic::Ordering, time::Duration};
#[cfg(supports_64bit_atomics)]
use core::sync::atomic::AtomicU64;
#[cfg(not(supports_64bit_atomics))]
use portable_atomic::AtomicU64;
use crate::TlasInstance;
mod buffer;
pub use buffer::Buffer;
mod command;
pub use command::CommandBuffer;
#[derive(Clone, Debug)]
pub struct Api;
pub struct Context;
#[derive(Debug)]
pub struct Encoder;
#[derive(Debug)]
pub struct Resource;
#[derive(Debug)]
pub struct Fence {
value: AtomicU64,
}
type DeviceResult<T> = Result<T, crate::DeviceError>;
impl crate::Api for Api {
const VARIANT: wgt::Backend = wgt::Backend::Noop;
type Instance = Context;
type Surface = Context;
type Adapter = Context;
type Device = Context;
type Queue = Context;
type CommandEncoder = CommandBuffer;
type CommandBuffer = CommandBuffer;
type Buffer = Buffer;
type Texture = Resource;
type SurfaceTexture = Resource;
type TextureView = Resource;
type Sampler = Resource;
type QuerySet = Resource;
type Fence = Fence;
type AccelerationStructure = Resource;
type PipelineCache = Resource;
type BindGroupLayout = Resource;
type BindGroup = Resource;
type PipelineLayout = Resource;
type ShaderModule = Resource;
type RenderPipeline = Resource;
type ComputePipeline = Resource;
}
crate::impl_dyn_resource!(Buffer, CommandBuffer, Context, Fence, Resource);
impl crate::DynAccelerationStructure for Resource {}
impl crate::DynBindGroup for Resource {}
impl crate::DynBindGroupLayout for Resource {}
impl crate::DynBuffer for Buffer {}
impl crate::DynCommandBuffer for CommandBuffer {}
impl crate::DynComputePipeline for Resource {}
impl crate::DynFence for Fence {}
impl crate::DynPipelineCache for Resource {}
impl crate::DynPipelineLayout for Resource {}
impl crate::DynQuerySet for Resource {}
impl crate::DynRenderPipeline for Resource {}
impl crate::DynSampler for Resource {}
impl crate::DynShaderModule for Resource {}
impl crate::DynSurfaceTexture for Resource {}
impl crate::DynTexture for Resource {}
impl crate::DynTextureView for Resource {}
impl core::borrow::Borrow<dyn crate::DynTexture> for Resource {
fn borrow(&self) -> &dyn crate::DynTexture {
self
}
}
impl crate::Instance for Context {
type A = Api;
unsafe fn init(desc: &crate::InstanceDescriptor<'_>) -> Result<Self, crate::InstanceError> {
let crate::InstanceDescriptor {
backend_options:
wgt::BackendOptions {
noop: wgt::NoopBackendOptions { enable },
..
},
name: _,
flags: _,
memory_budget_thresholds: _,
telemetry: _,
display: _,
} = *desc;
if enable {
Ok(Context)
} else {
Err(crate::InstanceError::new(String::from(
"noop backend disabled because NoopBackendOptions::enable is false",
)))
}
}
unsafe fn create_surface(
&self,
_display_handle: raw_window_handle::RawDisplayHandle,
_window_handle: raw_window_handle::RawWindowHandle,
) -> Result<Context, crate::InstanceError> {
Ok(Context)
}
unsafe fn enumerate_adapters(
&self,
_surface_hint: Option<&Context>,
) -> Vec<crate::ExposedAdapter<Api>> {
vec![crate::ExposedAdapter {
adapter: Context,
info: adapter_info(),
features: wgt::Features::all(),
capabilities: CAPABILITIES,
}]
}
}
/// Returns the adapter info for the noop backend.
///
/// This is used in the test harness to construct info about
/// the noop backend adapter without actually initializing wgpu.
pub fn adapter_info() -> wgt::AdapterInfo {
wgt::AdapterInfo {
name: String::from("noop wgpu backend"),
vendor: 0,
device: 0,
device_type: wgt::DeviceType::Cpu,
device_pci_bus_id: String::new(),
driver: String::from("wgpu"),
driver_info: String::new(),
backend: wgt::Backend::Noop,
subgroup_min_size: wgt::MINIMUM_SUBGROUP_MIN_SIZE,
subgroup_max_size: wgt::MAXIMUM_SUBGROUP_MAX_SIZE,
transient_saves_memory: false,
}
}
/// The capabilities of the noop backend.
///
/// This is used in the test harness to construct capabilities
/// of the noop backend without actually initializing wgpu.
pub const CAPABILITIES: crate::Capabilities = {
/// Guaranteed to be no bigger than isize::MAX which is the maximum size of an allocation,
/// except on 16-bit platforms which we certainly don’t fit in.
const ALLOC_MAX_U32: u32 = i32::MAX as u32;
/// Guaranteed to be no bigger than isize::MAX which is the maximum size of an allocation,
/// except on 16-bit platforms which we certainly don’t fit in.
const ALLOC_MAX_U64: u64 = i32::MAX as u64;
crate::Capabilities {
limits: wgt::Limits {
// All maximally permissive
max_texture_dimension_1d: ALLOC_MAX_U32,
max_texture_dimension_2d: ALLOC_MAX_U32,
max_texture_dimension_3d: ALLOC_MAX_U32,
max_texture_array_layers: ALLOC_MAX_U32,
max_bind_groups: ALLOC_MAX_U32,
max_bindings_per_bind_group: ALLOC_MAX_U32,
max_dynamic_uniform_buffers_per_pipeline_layout: ALLOC_MAX_U32,
max_dynamic_storage_buffers_per_pipeline_layout: ALLOC_MAX_U32,
max_sampled_textures_per_shader_stage: ALLOC_MAX_U32,
max_samplers_per_shader_stage: ALLOC_MAX_U32,
max_storage_buffers_per_shader_stage: ALLOC_MAX_U32,
max_storage_textures_per_shader_stage: ALLOC_MAX_U32,
max_uniform_buffers_per_shader_stage: ALLOC_MAX_U32,
max_binding_array_elements_per_shader_stage: ALLOC_MAX_U32,
max_binding_array_sampler_elements_per_shader_stage: ALLOC_MAX_U32,
max_binding_array_acceleration_structure_elements_per_shader_stage: ALLOC_MAX_U32,
max_uniform_buffer_binding_size: ALLOC_MAX_U64,
max_storage_buffer_binding_size: ALLOC_MAX_U64,
max_vertex_buffers: ALLOC_MAX_U32,
max_buffer_size: ALLOC_MAX_U64,
max_vertex_attributes: ALLOC_MAX_U32,
max_vertex_buffer_array_stride: ALLOC_MAX_U32,
max_inter_stage_shader_variables: ALLOC_MAX_U32,
min_uniform_buffer_offset_alignment: 1,
min_storage_buffer_offset_alignment: 1,
max_color_attachments: ALLOC_MAX_U32,
max_color_attachment_bytes_per_sample: ALLOC_MAX_U32,
max_compute_workgroup_storage_size: ALLOC_MAX_U32,
max_compute_invocations_per_workgroup: ALLOC_MAX_U32,
max_compute_workgroup_size_x: ALLOC_MAX_U32,
max_compute_workgroup_size_y: ALLOC_MAX_U32,
max_compute_workgroup_size_z: ALLOC_MAX_U32,
max_compute_workgroups_per_dimension: ALLOC_MAX_U32,
max_immediate_size: ALLOC_MAX_U32,
max_non_sampler_bindings: ALLOC_MAX_U32,
max_task_mesh_workgroup_total_count: ALLOC_MAX_U32,
max_task_mesh_workgroups_per_dimension: ALLOC_MAX_U32,
max_task_invocations_per_workgroup: ALLOC_MAX_U32,
max_task_invocations_per_dimension: ALLOC_MAX_U32,
max_mesh_invocations_per_workgroup: ALLOC_MAX_U32,
max_mesh_invocations_per_dimension: ALLOC_MAX_U32,
max_task_payload_size: ALLOC_MAX_U32,
max_mesh_output_vertices: ALLOC_MAX_U32,
max_mesh_output_primitives: ALLOC_MAX_U32,
max_mesh_output_layers: ALLOC_MAX_U32,
max_mesh_multiview_view_count: ALLOC_MAX_U32,
max_blas_primitive_count: ALLOC_MAX_U32,
max_blas_geometry_count: ALLOC_MAX_U32,
max_tlas_instance_count: ALLOC_MAX_U32,
max_acceleration_structures_per_shader_stage: ALLOC_MAX_U32,
max_multiview_view_count: ALLOC_MAX_U32,
},
alignments: crate::Alignments {
// All maximally permissive
buffer_copy_offset: wgt::BufferSize::MIN,
buffer_copy_pitch: wgt::BufferSize::MIN,
uniform_bounds_check_alignment: wgt::BufferSize::MIN,
raw_tlas_instance_size: 0,
ray_tracing_scratch_buffer_alignment: 1,
},
downlevel: wgt::DownlevelCapabilities {
flags: wgt::DownlevelFlags::all(),
limits: wgt::DownlevelLimits {},
shader_model: wgt::ShaderModel::Sm5,
},
cooperative_matrix_properties: Vec::new(),
}
};
impl crate::Surface for Context {
type A = Api;
unsafe fn configure(
&self,
device: &Context,
config: &crate::SurfaceConfiguration,
) -> Result<(), crate::SurfaceError> {
Ok(())
}
unsafe fn unconfigure(&self, device: &Context) {}
unsafe fn acquire_texture(
&self,
_timeout: Option<Duration>,
_fence: &Fence,
) -> Result<crate::AcquiredSurfaceTexture<Api>, crate::SurfaceError> {
Err(crate::SurfaceError::Timeout)
}
unsafe fn discard_texture(&self, texture: Resource) {}
}
impl crate::Adapter for Context {
type A = Api;
unsafe fn open(
&self,
features: wgt::Features,
_limits: &wgt::Limits,
_memory_hints: &wgt::MemoryHints,
) -> DeviceResult<crate::OpenDevice<Api>> {
Ok(crate::OpenDevice {
device: Context,
queue: Context,
})
}
unsafe fn texture_format_capabilities(
&self,
format: wgt::TextureFormat,
) -> crate::TextureFormatCapabilities {
crate::TextureFormatCapabilities::empty()
}
unsafe fn surface_capabilities(&self, surface: &Context) -> Option<crate::SurfaceCapabilities> {
None
}
unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp {
wgt::PresentationTimestamp::INVALID_TIMESTAMP
}
fn get_ordered_buffer_usages(&self) -> wgt::BufferUses {
wgt::BufferUses::INCLUSIVE | wgt::BufferUses::MAP_WRITE
}
fn get_ordered_texture_usages(&self) -> wgt::TextureUses {
wgt::TextureUses::INCLUSIVE
| wgt::TextureUses::COLOR_TARGET
| wgt::TextureUses::DEPTH_STENCIL_WRITE
}
}
impl crate::Queue for Context {
type A = Api;
unsafe fn submit(
&self,
command_buffers: &[&CommandBuffer],
surface_textures: &[&Resource],
(fence, fence_value): (&mut Fence, crate::FenceValue),
) -> DeviceResult<()> {
// All commands are executed synchronously.
for cb in command_buffers {
// SAFETY: Caller is responsible for ensuring synchronization between commands and
// other mutations.
unsafe {
cb.execute();
}
}
fence.value.store(fence_value, Ordering::Release);
Ok(())
}
unsafe fn present(
&self,
surface: &Context,
texture: Resource,
) -> Result<(), crate::SurfaceError> {
Ok(())
}
unsafe fn get_timestamp_period(&self) -> f32 {
1.0
}
}
impl crate::Device for Context {
type A = Api;
unsafe fn create_buffer(&self, desc: &crate::BufferDescriptor) -> DeviceResult<Buffer> {
Buffer::new(desc)
}
unsafe fn destroy_buffer(&self, buffer: Buffer) {}
unsafe fn add_raw_buffer(&self, _buffer: &Buffer) {}
unsafe fn map_buffer(
&self,
buffer: &Buffer,
range: crate::MemoryRange,
) -> DeviceResult<crate::BufferMapping> {
// Safety: the `wgpu-core` validation layer will prevent any user-accessible aliasing
// mappings from being created, so we don’t need to perform any checks here, except for
// bounds checks on the range which are built into `get_slice_ptr()`.
Ok(crate::BufferMapping {
ptr: ptr::NonNull::new(buffer.get_slice_ptr(range).cast::<u8>()).unwrap(),
is_coherent: true,
})
}
unsafe fn unmap_buffer(&self, buffer: &Buffer) {}
unsafe fn flush_mapped_ranges<I>(&self, buffer: &Buffer, ranges: I) {}
unsafe fn invalidate_mapped_ranges<I>(&self, buffer: &Buffer, ranges: I) {}
unsafe fn create_texture(&self, desc: &crate::TextureDescriptor) -> DeviceResult<Resource> {
Ok(Resource)
}
unsafe fn destroy_texture(&self, texture: Resource) {}
unsafe fn add_raw_texture(&self, _texture: &Resource) {}
unsafe fn create_texture_view(
&self,
texture: &Resource,
desc: &crate::TextureViewDescriptor,
) -> DeviceResult<Resource> {
Ok(Resource)
}
unsafe fn destroy_texture_view(&self, view: Resource) {}
unsafe fn create_sampler(&self, desc: &crate::SamplerDescriptor) -> DeviceResult<Resource> {
Ok(Resource)
}
unsafe fn destroy_sampler(&self, sampler: Resource) {}
unsafe fn create_command_encoder(
&self,
desc: &crate::CommandEncoderDescriptor<Context>,
) -> DeviceResult<CommandBuffer> {
Ok(CommandBuffer::new())
}
unsafe fn create_bind_group_layout(
&self,
desc: &crate::BindGroupLayoutDescriptor,
) -> DeviceResult<Resource> {
Ok(Resource)
}
unsafe fn destroy_bind_group_layout(&self, bg_layout: Resource) {}
unsafe fn create_pipeline_layout(
&self,
desc: &crate::PipelineLayoutDescriptor<Resource>,
) -> DeviceResult<Resource> {
Ok(Resource)
}
unsafe fn destroy_pipeline_layout(&self, pipeline_layout: Resource) {}
unsafe fn create_bind_group(
&self,
desc: &crate::BindGroupDescriptor<Resource, Buffer, Resource, Resource, Resource>,
) -> DeviceResult<Resource> {
Ok(Resource)
}
unsafe fn destroy_bind_group(&self, group: Resource) {}
unsafe fn create_shader_module(
&self,
desc: &crate::ShaderModuleDescriptor,
shader: crate::ShaderInput,
) -> Result<Resource, crate::ShaderError> {
Ok(Resource)
}
unsafe fn destroy_shader_module(&self, module: Resource) {}
unsafe fn create_render_pipeline(
&self,
desc: &crate::RenderPipelineDescriptor<Resource, Resource, Resource>,
) -> Result<Resource, crate::PipelineError> {
Ok(Resource)
}
unsafe fn destroy_render_pipeline(&self, pipeline: Resource) {}
unsafe fn create_compute_pipeline(
&self,
desc: &crate::ComputePipelineDescriptor<Resource, Resource, Resource>,
) -> Result<Resource, crate::PipelineError> {
Ok(Resource)
}
unsafe fn destroy_compute_pipeline(&self, pipeline: Resource) {}
unsafe fn create_pipeline_cache(
&self,
desc: &crate::PipelineCacheDescriptor<'_>,
) -> Result<Resource, crate::PipelineCacheError> {
Ok(Resource)
}
unsafe fn destroy_pipeline_cache(&self, cache: Resource) {}
unsafe fn create_query_set(
&self,
desc: &wgt::QuerySetDescriptor<crate::Label>,
) -> DeviceResult<Resource> {
Ok(Resource)
}
unsafe fn destroy_query_set(&self, set: Resource) {}
unsafe fn create_fence(&self) -> DeviceResult<Fence> {
Ok(Fence {
value: AtomicU64::new(0),
})
}
unsafe fn destroy_fence(&self, fence: Fence) {}
unsafe fn get_fence_value(&self, fence: &Fence) -> DeviceResult<crate::FenceValue> {
Ok(fence.value.load(Ordering::Acquire))
}
unsafe fn wait(
&self,
fence: &Fence,
value: crate::FenceValue,
timeout: Option<Duration>,
) -> DeviceResult<bool> {
// The relevant commands must have already been submitted, and noop-backend commands are
// executed synchronously, so there is no waiting — either it is already done,
// or this method was called incorrectly.
assert!(
fence.value.load(Ordering::Acquire) >= value,
"submission must have already been done"
);
Ok(true)
}
unsafe fn start_graphics_debugger_capture(&self) -> bool {
false
}
unsafe fn stop_graphics_debugger_capture(&self) {}
unsafe fn create_acceleration_structure(
&self,
desc: &crate::AccelerationStructureDescriptor,
) -> DeviceResult<Resource> {
Ok(Resource)
}
unsafe fn get_acceleration_structure_build_sizes<'a>(
&self,
_desc: &crate::GetAccelerationStructureBuildSizesDescriptor<'a, Buffer>,
) -> crate::AccelerationStructureBuildSizes {
Default::default()
}
unsafe fn get_acceleration_structure_device_address(
&self,
_acceleration_structure: &Resource,
) -> wgt::BufferAddress {
Default::default()
}
unsafe fn destroy_acceleration_structure(&self, _acceleration_structure: Resource) {}
fn tlas_instance_to_bytes(&self, instance: TlasInstance) -> Vec<u8> {
vec![]
}
fn get_internal_counters(&self) -> wgt::HalCounters {
Default::default()
}
fn check_if_oom(&self) -> DeviceResult<()> {
Ok(())
}
}