Backed out changeset ba49d9bdc665 (bug 1852485) for causing non-unified build bustage...
[gecko.git] / gfx / wgpu_bindings / src / server.rs
blobb93ba7727d1bb161e8716de42fd0e9d62a601843
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 use crate::{
6     error::{ErrMsg, ErrorBuffer, ErrorBufferType},
7     identity::IdentityRecyclerFactory,
8     wgpu_string, AdapterInformation, ByteBuf, CommandEncoderAction, DeviceAction, DropAction,
9     QueueWriteAction, TextureAction,
12 use nsstring::{nsACString, nsCString, nsString};
14 use wgc::{gfx_select, id};
15 use wgc::{pipeline::CreateShaderModuleError, resource::BufferAccessError};
17 use std::borrow::Cow;
18 use std::slice;
19 use std::sync::atomic::{AtomicU32, Ordering};
21 // The seemingly redundant u64 suffixes help cbindgen with generating the right C++ code.
22 // See https://github.com/mozilla/cbindgen/issues/849.
24 /// We limit the size of buffer allocations for stability reason.
25 /// We can reconsider this limit in the future. Note that some drivers (mesa for example),
26 /// have issues when the size of a buffer, mapping or copy command does not fit into a
27 /// signed 32 bits integer, so beyond a certain size, large allocations will need some form
28 /// of driver allow/blocklist.
29 pub const MAX_BUFFER_SIZE: wgt::BufferAddress = 1u64 << 30u64;
30 // Mesa has issues with height/depth that don't fit in a 16 bits signed integers.
31 const MAX_TEXTURE_EXTENT: u32 = std::i16::MAX as u32;
33 fn restrict_limits(limits: wgt::Limits) -> wgt::Limits {
34     wgt::Limits {
35         max_buffer_size: limits.max_buffer_size.min(MAX_BUFFER_SIZE),
36         max_texture_dimension_1d: limits.max_texture_dimension_1d.min(MAX_TEXTURE_EXTENT),
37         max_texture_dimension_2d: limits.max_texture_dimension_2d.min(MAX_TEXTURE_EXTENT),
38         max_texture_dimension_3d: limits.max_texture_dimension_3d.min(MAX_TEXTURE_EXTENT),
39         max_non_sampler_bindings: 10_000,
40         .. limits
41     }
44 // hide wgc's global in private
45 pub struct Global(wgc::global::Global<IdentityRecyclerFactory>);
47 impl std::ops::Deref for Global {
48     type Target = wgc::global::Global<IdentityRecyclerFactory>;
49     fn deref(&self) -> &Self::Target {
50         &self.0
51     }
54 #[no_mangle]
55 pub extern "C" fn wgpu_server_new(factory: IdentityRecyclerFactory) -> *mut Global {
56     log::info!("Initializing WGPU server");
57     let backends_pref = static_prefs::pref!("dom.webgpu.wgpu-backend").to_string();
58     let backends = if backends_pref.is_empty() {
59         wgt::Backends::PRIMARY
60     } else {
61         log::info!(
62             "Selecting backends based on dom.webgpu.wgpu-backend pref: {:?}",
63             backends_pref
64         );
65         wgc::instance::parse_backends_from_comma_list(&backends_pref)
66     };
67     let global = Global(wgc::global::Global::new(
68         "wgpu",
69         factory,
70         wgt::InstanceDescriptor {
71             backends,
72             dx12_shader_compiler: wgt::Dx12Compiler::Fxc,
73             gles_minor_version: wgt::Gles3MinorVersion::Automatic,
74         },
75     ));
76     Box::into_raw(Box::new(global))
79 /// # Safety
80 ///
81 /// This function is unsafe because improper use may lead to memory
82 /// problems. For example, a double-free may occur if the function is called
83 /// twice on the same raw pointer.
84 #[no_mangle]
85 pub unsafe extern "C" fn wgpu_server_delete(global: *mut Global) {
86     log::info!("Terminating WGPU server");
87     let _ = Box::from_raw(global);
90 #[no_mangle]
91 pub extern "C" fn wgpu_server_poll_all_devices(global: &Global, force_wait: bool) {
92     global.poll_all_devices(force_wait).unwrap();
95 /// Request an adapter according to the specified options.
96 /// Provide the list of IDs to pick from.
97 ///
98 /// Returns the index in this list, or -1 if unable to pick.
99 ///
100 /// # Safety
102 /// This function is unsafe as there is no guarantee that the given pointer is
103 /// valid for `id_length` elements.
104 #[no_mangle]
105 pub unsafe extern "C" fn wgpu_server_instance_request_adapter(
106     global: &Global,
107     desc: &wgc::instance::RequestAdapterOptions,
108     ids: *const id::AdapterId,
109     id_length: usize,
110     mut error_buf: ErrorBuffer,
111 ) -> i8 {
112     let ids = slice::from_raw_parts(ids, id_length);
113     match global.request_adapter(
114         desc,
115         wgc::instance::AdapterInputs::IdSet(ids, |i| i.backend()),
116     ) {
117         Ok(id) => ids.iter().position(|&i| i == id).unwrap() as i8,
118         Err(e) => {
119             error_buf.init(e);
120             -1
121         }
122     }
125 #[no_mangle]
126 pub unsafe extern "C" fn wgpu_server_adapter_pack_info(
127     global: &Global,
128     self_id: Option<id::AdapterId>,
129     byte_buf: &mut ByteBuf,
130 ) {
131     let mut data = Vec::new();
132     match self_id {
133         Some(id) => {
134             let wgt::AdapterInfo {
135                 name,
136                 vendor,
137                 device,
138                 device_type,
139                 driver,
140                 driver_info,
141                 backend,
142             } = gfx_select!(id => global.adapter_get_info(id)).unwrap();
144             let info = AdapterInformation {
145                 id,
146                 limits: restrict_limits(gfx_select!(id => global.adapter_limits(id)).unwrap()),
147                 features: gfx_select!(id => global.adapter_features(id)).unwrap(),
148                 name,
149                 vendor,
150                 device,
151                 device_type,
152                 driver,
153                 driver_info,
154                 backend,
155             };
156             bincode::serialize_into(&mut data, &info).unwrap();
157         }
158         None => {
159             bincode::serialize_into(&mut data, &0u64).unwrap();
160         }
161     }
162     *byte_buf = ByteBuf::from_vec(data);
165 static TRACE_IDX: AtomicU32 = AtomicU32::new(0);
167 #[no_mangle]
168 pub unsafe extern "C" fn wgpu_server_adapter_request_device(
169     global: &Global,
170     self_id: id::AdapterId,
171     byte_buf: &ByteBuf,
172     new_id: id::DeviceId,
173     mut error_buf: ErrorBuffer,
174 ) {
175     let desc: wgc::device::DeviceDescriptor = bincode::deserialize(byte_buf.as_slice()).unwrap();
176     let trace_string = std::env::var("WGPU_TRACE").ok().map(|s| {
177         let idx = TRACE_IDX.fetch_add(1, Ordering::Relaxed);
178         let path = format!("{}/{}/", s, idx);
180         if std::fs::create_dir_all(&path).is_err() {
181             log::warn!("Failed to create directory {:?} for wgpu recording.", path);
182         }
184         path
185     });
186     let trace_path = trace_string
187         .as_ref()
188         .map(|string| std::path::Path::new(string.as_str()));
189     let (_, error) =
190         gfx_select!(self_id => global.adapter_request_device(self_id, &desc, trace_path, new_id));
191     if let Some(err) = error {
192         error_buf.init(err);
193     }
196 #[no_mangle]
197 pub extern "C" fn wgpu_server_adapter_drop(global: &Global, adapter_id: id::AdapterId) {
198     gfx_select!(adapter_id => global.adapter_drop(adapter_id))
201 #[no_mangle]
202 pub extern "C" fn wgpu_server_device_drop(global: &Global, self_id: id::DeviceId) {
203     gfx_select!(self_id => global.device_drop(self_id))
206 impl ShaderModuleCompilationMessage {
207     fn set_error(&mut self, error: &CreateShaderModuleError, source: &str) {
208         // The WebGPU spec says that if the message doesn't point to a particular position in
209         // the source, the line number, position, offset and lengths should be zero.
210         self.line_number = 0;
211         self.line_pos = 0;
212         self.utf16_offset = 0;
213         self.utf16_length = 0;
215         if let Some(location) = error.location(source) {
216             self.line_number = location.line_number as u64;
217             self.line_pos = location.line_position as u64;
219             let start = location.offset as usize;
220             let end = start + location.length as usize;
221             self.utf16_offset = source[0..start].chars().map(|c| c.len_utf16() as u64).sum();
222             self.utf16_length = source[start..end]
223                 .chars()
224                 .map(|c| c.len_utf16() as u64)
225                 .sum();
226         }
228         let error_string = error.to_string();
230         if !error_string.is_empty() {
231             self.message = nsString::from(&error_string[..]);
232         }
233     }
236 /// A compilation message representation for the ffi boundary.
237 /// the message is immediately copied into an equivalent C++
238 /// structure that owns its strings.
239 #[repr(C)]
240 #[derive(Clone)]
241 pub struct ShaderModuleCompilationMessage {
242     pub line_number: u64,
243     pub line_pos: u64,
244     pub utf16_offset: u64,
245     pub utf16_length: u64,
246     pub message: nsString,
249 /// Creates a shader module and returns an object describing the errors if any.
251 /// If there was no error, the returned pointer is nil.
252 #[no_mangle]
253 pub extern "C" fn wgpu_server_device_create_shader_module(
254     global: &Global,
255     self_id: id::DeviceId,
256     module_id: id::ShaderModuleId,
257     label: Option<&nsACString>,
258     code: &nsCString,
259     out_message: &mut ShaderModuleCompilationMessage,
260 ) -> bool {
261     let utf8_label = label.map(|utf16| utf16.to_string());
262     let label = utf8_label.as_ref().map(|s| Cow::from(&s[..]));
264     let source_str = code.to_utf8();
266     let source = wgc::pipeline::ShaderModuleSource::Wgsl(Cow::from(&source_str[..]));
268     let desc = wgc::pipeline::ShaderModuleDescriptor {
269         label,
270         shader_bound_checks: wgt::ShaderBoundChecks::new(),
271     };
273     let (_, error) = gfx_select!(
274         self_id => global.device_create_shader_module(
275             self_id, &desc, source, module_id
276         )
277     );
279     if let Some(err) = error {
280         out_message.set_error(&err, &source_str[..]);
281         return false;
282     }
284     // Avoid allocating the structure that holds errors in the common case (no errors).
285     return true;
288 #[no_mangle]
289 pub extern "C" fn wgpu_server_device_create_buffer(
290     global: &Global,
291     self_id: id::DeviceId,
292     buffer_id: id::BufferId,
293     label: Option<&nsACString>,
294     size: wgt::BufferAddress,
295     usage: u32,
296     mapped_at_creation: bool,
297     shm_allocation_failed: bool,
298     mut error_buf: ErrorBuffer,
299 ) {
300     let utf8_label = label.map(|utf16| utf16.to_string());
301     let label = utf8_label.as_ref().map(|s| Cow::from(&s[..]));
302     let usage = wgt::BufferUsages::from_bits_retain(usage);
304     // Don't trust the graphics driver with buffer sizes larger than our conservative max texture size.
305     if shm_allocation_failed || size > MAX_BUFFER_SIZE {
306         error_buf.init(ErrMsg {
307             message: "Out of memory",
308             r#type: ErrorBufferType::OutOfMemory,
309         });
310         gfx_select!(self_id => global.create_buffer_error(buffer_id, label));
311         return;
312     }
314     let desc = wgc::resource::BufferDescriptor {
315         label,
316         size,
317         usage,
318         mapped_at_creation,
319     };
320     let (_, error) = gfx_select!(self_id => global.device_create_buffer(self_id, &desc, buffer_id));
321     if let Some(err) = error {
322         error_buf.init(err);
323     }
326 /// # Safety
328 /// Callers are responsible for ensuring `callback` is well-formed.
329 #[no_mangle]
330 pub unsafe extern "C" fn wgpu_server_buffer_map(
331     global: &Global,
332     buffer_id: id::BufferId,
333     start: wgt::BufferAddress,
334     size: wgt::BufferAddress,
335     map_mode: wgc::device::HostMap,
336     callback: wgc::resource::BufferMapCallbackC,
337 ) {
338     let callback = wgc::resource::BufferMapCallback::from_c(callback);
339     let operation = wgc::resource::BufferMapOperation {
340         host: map_mode,
341         callback,
342     };
343     // All errors are also exposed to the mapping callback, so we handle them there and ignore
344     // the returned value of buffer_map_async.
345     let _ = gfx_select!(buffer_id => global.buffer_map_async(
346         buffer_id,
347         start .. start + size,
348         operation
349     ));
352 #[repr(C)]
353 pub struct MappedBufferSlice {
354     pub ptr: *mut u8,
355     pub length: u64,
358 /// # Safety
360 /// This function is unsafe as there is no guarantee that the given pointer is
361 /// valid for `size` elements.
362 #[no_mangle]
363 pub unsafe extern "C" fn wgpu_server_buffer_get_mapped_range(
364     global: &Global,
365     buffer_id: id::BufferId,
366     start: wgt::BufferAddress,
367     size: wgt::BufferAddress,
368 ) -> MappedBufferSlice {
369     let result = gfx_select!(buffer_id => global.buffer_get_mapped_range(
370         buffer_id,
371         start,
372         Some(size)
373     ));
375     // TODO: error reporting.
377     result
378         .map(|(ptr, length)| MappedBufferSlice { ptr, length })
379         .unwrap_or(MappedBufferSlice {
380             ptr: std::ptr::null_mut(),
381             length: 0,
382         })
385 #[no_mangle]
386 pub extern "C" fn wgpu_server_buffer_unmap(
387     global: &Global,
388     buffer_id: id::BufferId,
389     mut error_buf: ErrorBuffer,
390 ) {
391     if let Err(e) = gfx_select!(buffer_id => global.buffer_unmap(buffer_id)) {
392         match e {
393             // NOTE: This is presumed by CTS test cases, and was even formally specified in the
394             // WebGPU spec. previously, but this doesn't seem formally specified now. :confused:
395             //
396             // TODO: upstream this; see <https://bugzilla.mozilla.org/show_bug.cgi?id=1842297>.
397             BufferAccessError::Invalid => (),
398             other => error_buf.init(other),
399         }
400     }
403 #[no_mangle]
404 pub extern "C" fn wgpu_server_buffer_destroy(global: &Global, self_id: id::BufferId) {
405     // Per spec, there is no need for the buffer or even device to be in a valid state,
406     // even calling calling destroy multiple times is fine, so no error to push into
407     // an error scope.
408     let _ = gfx_select!(self_id => global.buffer_destroy(self_id));
411 #[no_mangle]
412 pub extern "C" fn wgpu_server_buffer_drop(global: &Global, self_id: id::BufferId) {
413     gfx_select!(self_id => global.buffer_drop(self_id, false));
416 impl Global {
417     fn device_action<A: wgc::hal_api::HalApi>(
418         &self,
419         self_id: id::DeviceId,
420         action: DeviceAction,
421         mut error_buf: ErrorBuffer,
422     ) {
423         match action {
424             DeviceAction::CreateTexture(id, desc) => {
425                 let max = MAX_TEXTURE_EXTENT;
426                 if desc.size.width > max
427                     || desc.size.height > max
428                     || desc.size.depth_or_array_layers > max
429                 {
430                     gfx_select!(self_id => self.create_texture_error(id, desc.label));
431                     error_buf.init(ErrMsg {
432                         message: "Out of memory",
433                         r#type: ErrorBufferType::OutOfMemory,
434                     });
435                     return;
436                 }
437                 let (_, error) = self.device_create_texture::<A>(self_id, &desc, id);
438                 if let Some(err) = error {
439                     error_buf.init(err);
440                 }
441             }
442             DeviceAction::CreateSampler(id, desc) => {
443                 let (_, error) = self.device_create_sampler::<A>(self_id, &desc, id);
444                 if let Some(err) = error {
445                     error_buf.init(err);
446                 }
447             }
448             DeviceAction::CreateBindGroupLayout(id, desc) => {
449                 let (_, error) = self.device_create_bind_group_layout::<A>(self_id, &desc, id);
450                 if let Some(err) = error {
451                     error_buf.init(err);
452                 }
453             }
454             DeviceAction::CreatePipelineLayout(id, desc) => {
455                 let (_, error) = self.device_create_pipeline_layout::<A>(self_id, &desc, id);
456                 if let Some(err) = error {
457                     error_buf.init(err);
458                 }
459             }
460             DeviceAction::CreateBindGroup(id, desc) => {
461                 let (_, error) = self.device_create_bind_group::<A>(self_id, &desc, id);
462                 if let Some(err) = error {
463                     error_buf.init(err);
464                 }
465             }
466             DeviceAction::CreateShaderModule(id, desc, code) => {
467                 let source = wgc::pipeline::ShaderModuleSource::Wgsl(code);
468                 let (_, error) = self.device_create_shader_module::<A>(self_id, &desc, source, id);
469                 if let Some(err) = error {
470                     error_buf.init(err);
471                 }
472             }
473             DeviceAction::CreateComputePipeline(id, desc, implicit) => {
474                 let implicit_ids = implicit
475                     .as_ref()
476                     .map(|imp| wgc::device::ImplicitPipelineIds {
477                         root_id: imp.pipeline,
478                         group_ids: &imp.bind_groups,
479                     });
480                 let (_, error) =
481                     self.device_create_compute_pipeline::<A>(self_id, &desc, id, implicit_ids);
482                 if let Some(err) = error {
483                     error_buf.init(err);
484                 }
485             }
486             DeviceAction::CreateRenderPipeline(id, desc, implicit) => {
487                 let implicit_ids = implicit
488                     .as_ref()
489                     .map(|imp| wgc::device::ImplicitPipelineIds {
490                         root_id: imp.pipeline,
491                         group_ids: &imp.bind_groups,
492                     });
493                 let (_, error) =
494                     self.device_create_render_pipeline::<A>(self_id, &desc, id, implicit_ids);
495                 if let Some(err) = error {
496                     error_buf.init(err);
497                 }
498             }
499             DeviceAction::CreateRenderBundle(id, encoder, desc) => {
500                 let (_, error) = self.render_bundle_encoder_finish::<A>(encoder, &desc, id);
501                 if let Some(err) = error {
502                     error_buf.init(err);
503                 }
504             }
505             DeviceAction::CreateRenderBundleError(buffer_id, label) => {
506                 self.create_render_bundle_error::<A>(buffer_id, label);
507             }
508             DeviceAction::CreateCommandEncoder(id, desc) => {
509                 let (_, error) = self.device_create_command_encoder::<A>(self_id, &desc, id);
510                 if let Some(err) = error {
511                     error_buf.init(err);
512                 }
513             }
514             DeviceAction::Error { message, r#type } => {
515                 error_buf.init(ErrMsg {
516                     message: &message,
517                     r#type,
518                 });
519             }
520         }
521     }
523     fn texture_action<A: wgc::hal_api::HalApi>(
524         &self,
525         self_id: id::TextureId,
526         action: TextureAction,
527         mut error_buf: ErrorBuffer,
528     ) {
529         match action {
530             TextureAction::CreateView(id, desc) => {
531                 let (_, error) = self.texture_create_view::<A>(self_id, &desc, id);
532                 if let Some(err) = error {
533                     error_buf.init(err);
534                 }
535             }
536         }
537     }
539     fn command_encoder_action<A: wgc::hal_api::HalApi>(
540         &self,
541         self_id: id::CommandEncoderId,
542         action: CommandEncoderAction,
543         mut error_buf: ErrorBuffer,
544     ) {
545         match action {
546             CommandEncoderAction::CopyBufferToBuffer {
547                 src,
548                 src_offset,
549                 dst,
550                 dst_offset,
551                 size,
552             } => {
553                 if let Err(err) = self.command_encoder_copy_buffer_to_buffer::<A>(
554                     self_id, src, src_offset, dst, dst_offset, size,
555                 ) {
556                     error_buf.init(err);
557                 }
558             }
559             CommandEncoderAction::CopyBufferToTexture { src, dst, size } => {
560                 if let Err(err) =
561                     self.command_encoder_copy_buffer_to_texture::<A>(self_id, &src, &dst, &size)
562                 {
563                     error_buf.init(err);
564                 }
565             }
566             CommandEncoderAction::CopyTextureToBuffer { src, dst, size } => {
567                 if let Err(err) =
568                     self.command_encoder_copy_texture_to_buffer::<A>(self_id, &src, &dst, &size)
569                 {
570                     error_buf.init(err);
571                 }
572             }
573             CommandEncoderAction::CopyTextureToTexture { src, dst, size } => {
574                 if let Err(err) =
575                     self.command_encoder_copy_texture_to_texture::<A>(self_id, &src, &dst, &size)
576                 {
577                     error_buf.init(err);
578                 }
579             }
580             CommandEncoderAction::RunComputePass {
581                 base,
582                 timestamp_writes,
583             } => {
584                 if let Err(err) = self.command_encoder_run_compute_pass_impl::<A>(
585                     self_id,
586                     base.as_ref(),
587                     timestamp_writes.as_ref(),
588                 ) {
589                     error_buf.init(err);
590                 }
591             }
592             CommandEncoderAction::WriteTimestamp {
593                 query_set_id,
594                 query_index,
595             } => {
596                 if let Err(err) =
597                     self.command_encoder_write_timestamp::<A>(self_id, query_set_id, query_index)
598                 {
599                     error_buf.init(err);
600                 }
601             }
602             CommandEncoderAction::ResolveQuerySet {
603                 query_set_id,
604                 start_query,
605                 query_count,
606                 destination,
607                 destination_offset,
608             } => {
609                 if let Err(err) = self.command_encoder_resolve_query_set::<A>(
610                     self_id,
611                     query_set_id,
612                     start_query,
613                     query_count,
614                     destination,
615                     destination_offset,
616                 ) {
617                     error_buf.init(err);
618                 }
619             }
620             CommandEncoderAction::RunRenderPass {
621                 base,
622                 target_colors,
623                 target_depth_stencil,
624                 timestamp_writes,
625                 occlusion_query_set_id,
626             } => {
627                 if let Err(err) = self.command_encoder_run_render_pass_impl::<A>(
628                     self_id,
629                     base.as_ref(),
630                     &target_colors,
631                     target_depth_stencil.as_ref(),
632                     timestamp_writes.as_ref(),
633                     occlusion_query_set_id,
634                 ) {
635                     error_buf.init(err);
636                 }
637             }
638             CommandEncoderAction::ClearBuffer { dst, offset, size } => {
639                 if let Err(err) = self.command_encoder_clear_buffer::<A>(self_id, dst, offset, size)
640                 {
641                     error_buf.init(err);
642                 }
643             }
644             CommandEncoderAction::ClearTexture {
645                 dst,
646                 ref subresource_range,
647             } => {
648                 if let Err(err) =
649                     self.command_encoder_clear_texture::<A>(self_id, dst, subresource_range)
650                 {
651                     error_buf.init(err);
652                 }
653             }
654             CommandEncoderAction::PushDebugGroup(marker) => {
655                 if let Err(err) = self.command_encoder_push_debug_group::<A>(self_id, &marker) {
656                     error_buf.init(err);
657                 }
658             }
659             CommandEncoderAction::PopDebugGroup => {
660                 if let Err(err) = self.command_encoder_pop_debug_group::<A>(self_id) {
661                     error_buf.init(err);
662                 }
663             }
664             CommandEncoderAction::InsertDebugMarker(marker) => {
665                 if let Err(err) = self.command_encoder_insert_debug_marker::<A>(self_id, &marker) {
666                     error_buf.init(err);
667                 }
668             }
669         }
670     }
673 #[no_mangle]
674 pub unsafe extern "C" fn wgpu_server_device_action(
675     global: &Global,
676     self_id: id::DeviceId,
677     byte_buf: &ByteBuf,
678     error_buf: ErrorBuffer,
679 ) {
680     let action = bincode::deserialize(byte_buf.as_slice()).unwrap();
681     gfx_select!(self_id => global.device_action(self_id, action, error_buf));
684 #[no_mangle]
685 pub unsafe extern "C" fn wgpu_server_texture_action(
686     global: &Global,
687     self_id: id::TextureId,
688     byte_buf: &ByteBuf,
689     error_buf: ErrorBuffer,
690 ) {
691     let action = bincode::deserialize(byte_buf.as_slice()).unwrap();
692     gfx_select!(self_id => global.texture_action(self_id, action, error_buf));
695 #[no_mangle]
696 pub unsafe extern "C" fn wgpu_server_command_encoder_action(
697     global: &Global,
698     self_id: id::CommandEncoderId,
699     byte_buf: &ByteBuf,
700     error_buf: ErrorBuffer,
701 ) {
702     let action = bincode::deserialize(byte_buf.as_slice()).unwrap();
703     gfx_select!(self_id => global.command_encoder_action(self_id, action, error_buf));
706 #[no_mangle]
707 pub extern "C" fn wgpu_server_device_create_encoder(
708     global: &Global,
709     self_id: id::DeviceId,
710     desc: &wgt::CommandEncoderDescriptor<Option<&nsACString>>,
711     new_id: id::CommandEncoderId,
712     mut error_buf: ErrorBuffer,
713 ) {
714     let utf8_label = desc.label.map(|utf16| utf16.to_string());
715     let label = utf8_label.as_ref().map(|s| Cow::from(&s[..]));
717     let desc = desc.map_label(|_| label);
718     let (_, error) =
719         gfx_select!(self_id => global.device_create_command_encoder(self_id, &desc, new_id));
720     if let Some(err) = error {
721         error_buf.init(err);
722     }
725 #[no_mangle]
726 pub extern "C" fn wgpu_server_encoder_finish(
727     global: &Global,
728     self_id: id::CommandEncoderId,
729     desc: &wgt::CommandBufferDescriptor<Option<&nsACString>>,
730     mut error_buf: ErrorBuffer,
731 ) {
732     let label = wgpu_string(desc.label);
733     let desc = desc.map_label(|_| label);
734     let (_, error) = gfx_select!(self_id => global.command_encoder_finish(self_id, &desc));
735     if let Some(err) = error {
736         error_buf.init(err);
737     }
740 #[no_mangle]
741 pub extern "C" fn wgpu_server_encoder_drop(global: &Global, self_id: id::CommandEncoderId) {
742     gfx_select!(self_id => global.command_encoder_drop(self_id));
745 #[no_mangle]
746 pub extern "C" fn wgpu_server_command_buffer_drop(global: &Global, self_id: id::CommandBufferId) {
747     gfx_select!(self_id => global.command_buffer_drop(self_id));
750 #[no_mangle]
751 pub extern "C" fn wgpu_server_render_bundle_drop(global: &Global, self_id: id::RenderBundleId) {
752     gfx_select!(self_id => global.render_bundle_drop(self_id));
755 #[no_mangle]
756 pub unsafe extern "C" fn wgpu_server_encoder_copy_texture_to_buffer(
757     global: &Global,
758     self_id: id::CommandEncoderId,
759     source: &wgc::command::ImageCopyTexture,
760     dst_buffer: wgc::id::BufferId,
761     dst_layout: &crate::ImageDataLayout,
762     size: &wgt::Extent3d,
763 ) {
764     let destination = wgc::command::ImageCopyBuffer {
765         buffer: dst_buffer,
766         layout: dst_layout.into_wgt(),
767     };
768     gfx_select!(self_id => global.command_encoder_copy_texture_to_buffer(self_id, source, &destination, size)).unwrap();
771 /// # Safety
773 /// This function is unsafe as there is no guarantee that the given pointer is
774 /// valid for `command_buffer_id_length` elements.
775 #[no_mangle]
776 pub unsafe extern "C" fn wgpu_server_queue_submit(
777     global: &Global,
778     self_id: id::QueueId,
779     command_buffer_ids: *const id::CommandBufferId,
780     command_buffer_id_length: usize,
781     mut error_buf: ErrorBuffer,
782 ) {
783     let command_buffers = slice::from_raw_parts(command_buffer_ids, command_buffer_id_length);
784     let result = gfx_select!(self_id => global.queue_submit(self_id, command_buffers));
785     if let Err(err) = result {
786         error_buf.init(err);
787     }
790 #[no_mangle]
791 pub unsafe extern "C" fn wgpu_server_on_submitted_work_done(
792     global: &Global,
793     self_id: id::QueueId,
794     callback: wgc::device::queue::SubmittedWorkDoneClosureC,
795 ) {
796     gfx_select!(self_id => global.queue_on_submitted_work_done(self_id, wgc::device::queue::SubmittedWorkDoneClosure::from_c(callback))).unwrap();
799 /// # Safety
801 /// This function is unsafe as there is no guarantee that the given pointer is
802 /// valid for `data_length` elements.
803 #[no_mangle]
804 pub unsafe extern "C" fn wgpu_server_queue_write_action(
805     global: &Global,
806     self_id: id::QueueId,
807     byte_buf: &ByteBuf,
808     data: *const u8,
809     data_length: usize,
810     mut error_buf: ErrorBuffer,
811 ) {
812     let action: QueueWriteAction = bincode::deserialize(byte_buf.as_slice()).unwrap();
813     let data = slice::from_raw_parts(data, data_length);
814     let result = match action {
815         QueueWriteAction::Buffer { dst, offset } => {
816             gfx_select!(self_id => global.queue_write_buffer(self_id, dst, offset, data))
817         }
818         QueueWriteAction::Texture { dst, layout, size } => {
819             gfx_select!(self_id => global.queue_write_texture(self_id, &dst, data, &layout, &size))
820         }
821     };
822     if let Err(err) = result {
823         error_buf.init(err);
824     }
827 #[no_mangle]
828 pub extern "C" fn wgpu_server_bind_group_layout_drop(
829     global: &Global,
830     self_id: id::BindGroupLayoutId,
831 ) {
832     gfx_select!(self_id => global.bind_group_layout_drop(self_id));
835 #[no_mangle]
836 pub extern "C" fn wgpu_server_pipeline_layout_drop(global: &Global, self_id: id::PipelineLayoutId) {
837     gfx_select!(self_id => global.pipeline_layout_drop(self_id));
840 #[no_mangle]
841 pub extern "C" fn wgpu_server_bind_group_drop(global: &Global, self_id: id::BindGroupId) {
842     gfx_select!(self_id => global.bind_group_drop(self_id));
845 #[no_mangle]
846 pub extern "C" fn wgpu_server_shader_module_drop(global: &Global, self_id: id::ShaderModuleId) {
847     gfx_select!(self_id => global.shader_module_drop(self_id));
850 #[no_mangle]
851 pub extern "C" fn wgpu_server_compute_pipeline_drop(
852     global: &Global,
853     self_id: id::ComputePipelineId,
854 ) {
855     gfx_select!(self_id => global.compute_pipeline_drop(self_id));
858 #[no_mangle]
859 pub extern "C" fn wgpu_server_render_pipeline_drop(global: &Global, self_id: id::RenderPipelineId) {
860     gfx_select!(self_id => global.render_pipeline_drop(self_id));
863 #[no_mangle]
864 pub extern "C" fn wgpu_server_texture_drop(global: &Global, self_id: id::TextureId) {
865     gfx_select!(self_id => global.texture_drop(self_id, false));
868 #[no_mangle]
869 pub extern "C" fn wgpu_server_texture_view_drop(global: &Global, self_id: id::TextureViewId) {
870     gfx_select!(self_id => global.texture_view_drop(self_id, false)).unwrap();
873 #[no_mangle]
874 pub extern "C" fn wgpu_server_sampler_drop(global: &Global, self_id: id::SamplerId) {
875     gfx_select!(self_id => global.sampler_drop(self_id));
878 #[no_mangle]
879 pub extern "C" fn wgpu_server_compute_pipeline_get_bind_group_layout(
880     global: &Global,
881     self_id: id::ComputePipelineId,
882     index: u32,
883     assign_id: id::BindGroupLayoutId,
884     mut error_buf: ErrorBuffer,
885 ) {
886     let (_, error) = gfx_select!(self_id => global.compute_pipeline_get_bind_group_layout(self_id, index, assign_id));
887     if let Some(err) = error {
888         error_buf.init(err);
889     }
892 #[no_mangle]
893 pub extern "C" fn wgpu_server_render_pipeline_get_bind_group_layout(
894     global: &Global,
895     self_id: id::RenderPipelineId,
896     index: u32,
897     assign_id: id::BindGroupLayoutId,
898     mut error_buf: ErrorBuffer,
899 ) {
900     let (_, error) = gfx_select!(self_id => global.render_pipeline_get_bind_group_layout(self_id, index, assign_id));
901     if let Some(err) = error {
902         error_buf.init(err);
903     }
906 /// Encode the freeing of the selected ID into a byte buf.
907 #[no_mangle]
908 pub extern "C" fn wgpu_server_adapter_free(id: id::AdapterId, drop_byte_buf: &mut ByteBuf) {
909     *drop_byte_buf = DropAction::Adapter(id).to_byte_buf();
911 #[no_mangle]
912 pub extern "C" fn wgpu_server_device_free(id: id::DeviceId, drop_byte_buf: &mut ByteBuf) {
913     *drop_byte_buf = DropAction::Device(id).to_byte_buf();
915 #[no_mangle]
916 pub extern "C" fn wgpu_server_shader_module_free(
917     id: id::ShaderModuleId,
918     drop_byte_buf: &mut ByteBuf,
919 ) {
920     *drop_byte_buf = DropAction::ShaderModule(id).to_byte_buf();
922 #[no_mangle]
923 pub extern "C" fn wgpu_server_pipeline_layout_free(
924     id: id::PipelineLayoutId,
925     drop_byte_buf: &mut ByteBuf,
926 ) {
927     *drop_byte_buf = DropAction::PipelineLayout(id).to_byte_buf();
929 #[no_mangle]
930 pub extern "C" fn wgpu_server_bind_group_layout_free(
931     id: id::BindGroupLayoutId,
932     drop_byte_buf: &mut ByteBuf,
933 ) {
934     *drop_byte_buf = DropAction::BindGroupLayout(id).to_byte_buf();
936 #[no_mangle]
937 pub extern "C" fn wgpu_server_bind_group_free(id: id::BindGroupId, drop_byte_buf: &mut ByteBuf) {
938     *drop_byte_buf = DropAction::BindGroup(id).to_byte_buf();
940 #[no_mangle]
941 pub extern "C" fn wgpu_server_command_buffer_free(
942     id: id::CommandBufferId,
943     drop_byte_buf: &mut ByteBuf,
944 ) {
945     *drop_byte_buf = DropAction::CommandBuffer(id).to_byte_buf();
947 #[no_mangle]
948 pub extern "C" fn wgpu_server_render_bundle_free(
949     id: id::RenderBundleId,
950     drop_byte_buf: &mut ByteBuf,
951 ) {
952     *drop_byte_buf = DropAction::RenderBundle(id).to_byte_buf();
954 #[no_mangle]
955 pub extern "C" fn wgpu_server_render_pipeline_free(
956     id: id::RenderPipelineId,
957     drop_byte_buf: &mut ByteBuf,
958 ) {
959     *drop_byte_buf = DropAction::RenderPipeline(id).to_byte_buf();
961 #[no_mangle]
962 pub extern "C" fn wgpu_server_compute_pipeline_free(
963     id: id::ComputePipelineId,
964     drop_byte_buf: &mut ByteBuf,
965 ) {
966     *drop_byte_buf = DropAction::ComputePipeline(id).to_byte_buf();
968 #[no_mangle]
969 pub extern "C" fn wgpu_server_buffer_free(id: id::BufferId, drop_byte_buf: &mut ByteBuf) {
970     *drop_byte_buf = DropAction::Buffer(id).to_byte_buf();
972 #[no_mangle]
973 pub extern "C" fn wgpu_server_texture_free(id: id::TextureId, drop_byte_buf: &mut ByteBuf) {
974     *drop_byte_buf = DropAction::Texture(id).to_byte_buf();
976 #[no_mangle]
977 pub extern "C" fn wgpu_server_texture_view_free(
978     id: id::TextureViewId,
979     drop_byte_buf: &mut ByteBuf,
980 ) {
981     *drop_byte_buf = DropAction::TextureView(id).to_byte_buf();
983 #[no_mangle]
984 pub extern "C" fn wgpu_server_sampler_free(id: id::SamplerId, drop_byte_buf: &mut ByteBuf) {
985     *drop_byte_buf = DropAction::Sampler(id).to_byte_buf();