wgpu_hal/noop/
mod.rs

1#![allow(unused_variables)]
2
3use alloc::{string::String, vec, vec::Vec};
4use core::{ptr, sync::atomic::Ordering, time::Duration};
5
6#[cfg(supports_64bit_atomics)]
7use core::sync::atomic::AtomicU64;
8#[cfg(not(supports_64bit_atomics))]
9use portable_atomic::AtomicU64;
10
11use crate::TlasInstance;
12
13mod buffer;
14pub use buffer::Buffer;
15mod command;
16pub use command::CommandBuffer;
17
18#[derive(Clone, Debug)]
19pub struct Api;
20pub struct Context;
21#[derive(Debug)]
22pub struct Encoder;
23#[derive(Debug)]
24pub struct Resource;
25
26#[derive(Debug)]
27pub struct Fence {
28    value: AtomicU64,
29}
30
31type DeviceResult<T> = Result<T, crate::DeviceError>;
32
33impl crate::Api for Api {
34    type Instance = Context;
35    type Surface = Context;
36    type Adapter = Context;
37    type Device = Context;
38
39    type Queue = Context;
40    type CommandEncoder = CommandBuffer;
41    type CommandBuffer = CommandBuffer;
42
43    type Buffer = Buffer;
44    type Texture = Resource;
45    type SurfaceTexture = Resource;
46    type TextureView = Resource;
47    type Sampler = Resource;
48    type QuerySet = Resource;
49    type Fence = Fence;
50    type AccelerationStructure = Resource;
51    type PipelineCache = Resource;
52
53    type BindGroupLayout = Resource;
54    type BindGroup = Resource;
55    type PipelineLayout = Resource;
56    type ShaderModule = Resource;
57    type RenderPipeline = Resource;
58    type ComputePipeline = Resource;
59}
60
61crate::impl_dyn_resource!(Buffer, CommandBuffer, Context, Fence, Resource);
62
63impl crate::DynAccelerationStructure for Resource {}
64impl crate::DynBindGroup for Resource {}
65impl crate::DynBindGroupLayout for Resource {}
66impl crate::DynBuffer for Buffer {}
67impl crate::DynCommandBuffer for CommandBuffer {}
68impl crate::DynComputePipeline for Resource {}
69impl crate::DynFence for Fence {}
70impl crate::DynPipelineCache for Resource {}
71impl crate::DynPipelineLayout for Resource {}
72impl crate::DynQuerySet for Resource {}
73impl crate::DynRenderPipeline for Resource {}
74impl crate::DynSampler for Resource {}
75impl crate::DynShaderModule for Resource {}
76impl crate::DynSurfaceTexture for Resource {}
77impl crate::DynTexture for Resource {}
78impl crate::DynTextureView for Resource {}
79
80impl core::borrow::Borrow<dyn crate::DynTexture> for Resource {
81    fn borrow(&self) -> &dyn crate::DynTexture {
82        self
83    }
84}
85
86impl crate::Instance for Context {
87    type A = Api;
88
89    unsafe fn init(desc: &crate::InstanceDescriptor) -> Result<Self, crate::InstanceError> {
90        let crate::InstanceDescriptor {
91            backend_options:
92                wgt::BackendOptions {
93                    noop: wgt::NoopBackendOptions { enable },
94                    ..
95                },
96            name: _,
97            flags: _,
98            memory_budget_thresholds: _,
99        } = *desc;
100        if enable {
101            Ok(Context)
102        } else {
103            Err(crate::InstanceError::new(String::from(
104                "noop backend disabled because NoopBackendOptions::enable is false",
105            )))
106        }
107    }
108    unsafe fn create_surface(
109        &self,
110        _display_handle: raw_window_handle::RawDisplayHandle,
111        _window_handle: raw_window_handle::RawWindowHandle,
112    ) -> Result<Context, crate::InstanceError> {
113        Ok(Context)
114    }
115    unsafe fn enumerate_adapters(
116        &self,
117        _surface_hint: Option<&Context>,
118    ) -> Vec<crate::ExposedAdapter<Api>> {
119        vec![crate::ExposedAdapter {
120            adapter: Context,
121            info: wgt::AdapterInfo {
122                name: String::from("noop wgpu backend"),
123                vendor: 0,
124                device: 0,
125                device_type: wgt::DeviceType::Cpu,
126                driver: String::from("wgpu"),
127                driver_info: String::new(),
128                backend: wgt::Backend::Noop,
129            },
130            features: wgt::Features::all(),
131            capabilities: CAPABILITIES,
132        }]
133    }
134}
135
136const CAPABILITIES: crate::Capabilities = {
137    /// Guaranteed to be no bigger than isize::MAX which is the maximum size of an allocation,
138    /// except on 16-bit platforms which we certainly don’t fit in.
139    const ALLOC_MAX_U32: u32 = i32::MAX as u32;
140
141    crate::Capabilities {
142        limits: wgt::Limits {
143            // All maximally permissive
144            max_texture_dimension_1d: ALLOC_MAX_U32,
145            max_texture_dimension_2d: ALLOC_MAX_U32,
146            max_texture_dimension_3d: ALLOC_MAX_U32,
147            max_texture_array_layers: ALLOC_MAX_U32,
148            max_bind_groups: ALLOC_MAX_U32,
149            max_bindings_per_bind_group: ALLOC_MAX_U32,
150            max_dynamic_uniform_buffers_per_pipeline_layout: ALLOC_MAX_U32,
151            max_dynamic_storage_buffers_per_pipeline_layout: ALLOC_MAX_U32,
152            max_sampled_textures_per_shader_stage: ALLOC_MAX_U32,
153            max_samplers_per_shader_stage: ALLOC_MAX_U32,
154            max_storage_buffers_per_shader_stage: ALLOC_MAX_U32,
155            max_storage_textures_per_shader_stage: ALLOC_MAX_U32,
156            max_uniform_buffers_per_shader_stage: ALLOC_MAX_U32,
157            max_binding_array_elements_per_shader_stage: ALLOC_MAX_U32,
158            max_binding_array_sampler_elements_per_shader_stage: ALLOC_MAX_U32,
159            max_uniform_buffer_binding_size: ALLOC_MAX_U32,
160            max_storage_buffer_binding_size: ALLOC_MAX_U32,
161            max_vertex_buffers: ALLOC_MAX_U32,
162            max_buffer_size: ALLOC_MAX_U32 as u64,
163            max_vertex_attributes: ALLOC_MAX_U32,
164            max_vertex_buffer_array_stride: ALLOC_MAX_U32,
165            min_uniform_buffer_offset_alignment: 1,
166            min_storage_buffer_offset_alignment: 1,
167            max_inter_stage_shader_components: ALLOC_MAX_U32,
168            max_color_attachments: ALLOC_MAX_U32,
169            max_color_attachment_bytes_per_sample: ALLOC_MAX_U32,
170            max_compute_workgroup_storage_size: ALLOC_MAX_U32,
171            max_compute_invocations_per_workgroup: ALLOC_MAX_U32,
172            max_compute_workgroup_size_x: ALLOC_MAX_U32,
173            max_compute_workgroup_size_y: ALLOC_MAX_U32,
174            max_compute_workgroup_size_z: ALLOC_MAX_U32,
175            max_compute_workgroups_per_dimension: ALLOC_MAX_U32,
176            min_subgroup_size: 1,
177            max_subgroup_size: ALLOC_MAX_U32,
178            max_push_constant_size: ALLOC_MAX_U32,
179            max_non_sampler_bindings: ALLOC_MAX_U32,
180            max_blas_primitive_count: ALLOC_MAX_U32,
181            max_blas_geometry_count: ALLOC_MAX_U32,
182            max_tlas_instance_count: ALLOC_MAX_U32,
183            max_acceleration_structures_per_shader_stage: ALLOC_MAX_U32,
184        },
185        alignments: crate::Alignments {
186            // All maximally permissive
187            buffer_copy_offset: wgt::BufferSize::MIN,
188            buffer_copy_pitch: wgt::BufferSize::MIN,
189            uniform_bounds_check_alignment: wgt::BufferSize::MIN,
190            raw_tlas_instance_size: 0,
191            ray_tracing_scratch_buffer_alignment: 1,
192        },
193        downlevel: wgt::DownlevelCapabilities {
194            flags: wgt::DownlevelFlags::all(),
195            limits: wgt::DownlevelLimits {},
196            shader_model: wgt::ShaderModel::Sm5,
197        },
198    }
199};
200
201impl crate::Surface for Context {
202    type A = Api;
203
204    unsafe fn configure(
205        &self,
206        device: &Context,
207        config: &crate::SurfaceConfiguration,
208    ) -> Result<(), crate::SurfaceError> {
209        Ok(())
210    }
211
212    unsafe fn unconfigure(&self, device: &Context) {}
213
214    unsafe fn acquire_texture(
215        &self,
216        timeout: Option<Duration>,
217        fence: &Fence,
218    ) -> Result<Option<crate::AcquiredSurfaceTexture<Api>>, crate::SurfaceError> {
219        Ok(None)
220    }
221    unsafe fn discard_texture(&self, texture: Resource) {}
222}
223
224impl crate::Adapter for Context {
225    type A = Api;
226
227    unsafe fn open(
228        &self,
229        features: wgt::Features,
230        _limits: &wgt::Limits,
231        _memory_hints: &wgt::MemoryHints,
232    ) -> DeviceResult<crate::OpenDevice<Api>> {
233        Ok(crate::OpenDevice {
234            device: Context,
235            queue: Context,
236        })
237    }
238    unsafe fn texture_format_capabilities(
239        &self,
240        format: wgt::TextureFormat,
241    ) -> crate::TextureFormatCapabilities {
242        crate::TextureFormatCapabilities::empty()
243    }
244
245    unsafe fn surface_capabilities(&self, surface: &Context) -> Option<crate::SurfaceCapabilities> {
246        None
247    }
248
249    unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp {
250        wgt::PresentationTimestamp::INVALID_TIMESTAMP
251    }
252}
253
254impl crate::Queue for Context {
255    type A = Api;
256
257    unsafe fn submit(
258        &self,
259        command_buffers: &[&CommandBuffer],
260        surface_textures: &[&Resource],
261        (fence, fence_value): (&mut Fence, crate::FenceValue),
262    ) -> DeviceResult<()> {
263        // All commands are executed synchronously.
264        for cb in command_buffers {
265            // SAFETY: Caller is responsible for ensuring synchronization between commands and
266            // other mutations.
267            unsafe {
268                cb.execute();
269            }
270        }
271        fence.value.store(fence_value, Ordering::Release);
272        Ok(())
273    }
274    unsafe fn present(
275        &self,
276        surface: &Context,
277        texture: Resource,
278    ) -> Result<(), crate::SurfaceError> {
279        Ok(())
280    }
281
282    unsafe fn get_timestamp_period(&self) -> f32 {
283        1.0
284    }
285}
286
287impl crate::Device for Context {
288    type A = Api;
289
290    unsafe fn create_buffer(&self, desc: &crate::BufferDescriptor) -> DeviceResult<Buffer> {
291        Buffer::new(desc)
292    }
293
294    unsafe fn destroy_buffer(&self, buffer: Buffer) {}
295    unsafe fn add_raw_buffer(&self, _buffer: &Buffer) {}
296
297    unsafe fn map_buffer(
298        &self,
299        buffer: &Buffer,
300        range: crate::MemoryRange,
301    ) -> DeviceResult<crate::BufferMapping> {
302        // Safety: the `wgpu-core` validation layer will prevent any user-accessible aliasing
303        // mappings from being created, so we don’t need to perform any checks here, except for
304        // bounds checks on the range which are built into `get_slice_ptr()`.
305        Ok(crate::BufferMapping {
306            ptr: ptr::NonNull::new(buffer.get_slice_ptr(range).cast::<u8>()).unwrap(),
307            is_coherent: true,
308        })
309    }
310    unsafe fn unmap_buffer(&self, buffer: &Buffer) {}
311    unsafe fn flush_mapped_ranges<I>(&self, buffer: &Buffer, ranges: I) {}
312    unsafe fn invalidate_mapped_ranges<I>(&self, buffer: &Buffer, ranges: I) {}
313
314    unsafe fn create_texture(&self, desc: &crate::TextureDescriptor) -> DeviceResult<Resource> {
315        Ok(Resource)
316    }
317    unsafe fn destroy_texture(&self, texture: Resource) {}
318    unsafe fn add_raw_texture(&self, _texture: &Resource) {}
319
320    unsafe fn create_texture_view(
321        &self,
322        texture: &Resource,
323        desc: &crate::TextureViewDescriptor,
324    ) -> DeviceResult<Resource> {
325        Ok(Resource)
326    }
327    unsafe fn destroy_texture_view(&self, view: Resource) {}
328    unsafe fn create_sampler(&self, desc: &crate::SamplerDescriptor) -> DeviceResult<Resource> {
329        Ok(Resource)
330    }
331    unsafe fn destroy_sampler(&self, sampler: Resource) {}
332
333    unsafe fn create_command_encoder(
334        &self,
335        desc: &crate::CommandEncoderDescriptor<Context>,
336    ) -> DeviceResult<CommandBuffer> {
337        Ok(CommandBuffer::new())
338    }
339
340    unsafe fn create_bind_group_layout(
341        &self,
342        desc: &crate::BindGroupLayoutDescriptor,
343    ) -> DeviceResult<Resource> {
344        Ok(Resource)
345    }
346    unsafe fn destroy_bind_group_layout(&self, bg_layout: Resource) {}
347    unsafe fn create_pipeline_layout(
348        &self,
349        desc: &crate::PipelineLayoutDescriptor<Resource>,
350    ) -> DeviceResult<Resource> {
351        Ok(Resource)
352    }
353    unsafe fn destroy_pipeline_layout(&self, pipeline_layout: Resource) {}
354    unsafe fn create_bind_group(
355        &self,
356        desc: &crate::BindGroupDescriptor<Resource, Buffer, Resource, Resource, Resource>,
357    ) -> DeviceResult<Resource> {
358        Ok(Resource)
359    }
360    unsafe fn destroy_bind_group(&self, group: Resource) {}
361
362    unsafe fn create_shader_module(
363        &self,
364        desc: &crate::ShaderModuleDescriptor,
365        shader: crate::ShaderInput,
366    ) -> Result<Resource, crate::ShaderError> {
367        Ok(Resource)
368    }
369    unsafe fn destroy_shader_module(&self, module: Resource) {}
370    unsafe fn create_render_pipeline(
371        &self,
372        desc: &crate::RenderPipelineDescriptor<Resource, Resource, Resource>,
373    ) -> Result<Resource, crate::PipelineError> {
374        Ok(Resource)
375    }
376    unsafe fn create_mesh_pipeline(
377        &self,
378        desc: &crate::MeshPipelineDescriptor<
379            <Self::A as crate::Api>::PipelineLayout,
380            <Self::A as crate::Api>::ShaderModule,
381            <Self::A as crate::Api>::PipelineCache,
382        >,
383    ) -> Result<<Self::A as crate::Api>::RenderPipeline, crate::PipelineError> {
384        Ok(Resource)
385    }
386    unsafe fn destroy_render_pipeline(&self, pipeline: Resource) {}
387    unsafe fn create_compute_pipeline(
388        &self,
389        desc: &crate::ComputePipelineDescriptor<Resource, Resource, Resource>,
390    ) -> Result<Resource, crate::PipelineError> {
391        Ok(Resource)
392    }
393    unsafe fn destroy_compute_pipeline(&self, pipeline: Resource) {}
394    unsafe fn create_pipeline_cache(
395        &self,
396        desc: &crate::PipelineCacheDescriptor<'_>,
397    ) -> Result<Resource, crate::PipelineCacheError> {
398        Ok(Resource)
399    }
400    unsafe fn destroy_pipeline_cache(&self, cache: Resource) {}
401
402    unsafe fn create_query_set(
403        &self,
404        desc: &wgt::QuerySetDescriptor<crate::Label>,
405    ) -> DeviceResult<Resource> {
406        Ok(Resource)
407    }
408    unsafe fn destroy_query_set(&self, set: Resource) {}
409    unsafe fn create_fence(&self) -> DeviceResult<Fence> {
410        Ok(Fence {
411            value: AtomicU64::new(0),
412        })
413    }
414    unsafe fn destroy_fence(&self, fence: Fence) {}
415    unsafe fn get_fence_value(&self, fence: &Fence) -> DeviceResult<crate::FenceValue> {
416        Ok(fence.value.load(Ordering::Acquire))
417    }
418    unsafe fn wait(
419        &self,
420        fence: &Fence,
421        value: crate::FenceValue,
422        timeout_ms: u32,
423    ) -> DeviceResult<bool> {
424        // The relevant commands must have already been submitted, and noop-backend commands are
425        // executed synchronously, so there is no waiting — either it is already done,
426        // or this method was called incorrectly.
427        assert!(
428            fence.value.load(Ordering::Acquire) >= value,
429            "submission must have already been done"
430        );
431        Ok(true)
432    }
433
434    unsafe fn start_graphics_debugger_capture(&self) -> bool {
435        false
436    }
437    unsafe fn stop_graphics_debugger_capture(&self) {}
438    unsafe fn create_acceleration_structure(
439        &self,
440        desc: &crate::AccelerationStructureDescriptor,
441    ) -> DeviceResult<Resource> {
442        Ok(Resource)
443    }
444    unsafe fn get_acceleration_structure_build_sizes<'a>(
445        &self,
446        _desc: &crate::GetAccelerationStructureBuildSizesDescriptor<'a, Buffer>,
447    ) -> crate::AccelerationStructureBuildSizes {
448        Default::default()
449    }
450    unsafe fn get_acceleration_structure_device_address(
451        &self,
452        _acceleration_structure: &Resource,
453    ) -> wgt::BufferAddress {
454        Default::default()
455    }
456    unsafe fn destroy_acceleration_structure(&self, _acceleration_structure: Resource) {}
457
458    fn tlas_instance_to_bytes(&self, instance: TlasInstance) -> Vec<u8> {
459        vec![]
460    }
461
462    fn get_internal_counters(&self) -> wgt::HalCounters {
463        Default::default()
464    }
465
466    fn check_if_oom(&self) -> DeviceResult<()> {
467        Ok(())
468    }
469}