wgpu_hal/noop/
mod.rs

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