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/. */
4 
5 use crate::{
6     cow_label, AdapterInformation, ByteBuf, CommandEncoderAction, DeviceAction, DropAction,
7     ImplicitLayout, QueueWriteAction, RawString, TextureAction,
8 };
9 
10 use wgc::{hub::IdentityManager, id};
11 use wgt::Backend;
12 
13 pub use wgc::command::{compute_ffi::*, render_ffi::*};
14 
15 use parking_lot::Mutex;
16 
17 use std::{
18     borrow::Cow,
19     num::{NonZeroU32, NonZeroU8},
20     ptr,
21 };
22 
23 // we can't call `from_raw_parts` unconditionally because the caller
24 // may not even have a valid pointer (e.g. NULL) if the `length` is zero.
make_slice<'a, T>(pointer: *const T, length: usize) -> &'a [T]25 fn make_slice<'a, T>(pointer: *const T, length: usize) -> &'a [T] {
26     if length == 0 {
27         &[]
28     } else {
29         unsafe { std::slice::from_raw_parts(pointer, length) }
30     }
31 }
32 
make_byte_buf<T: serde::Serialize>(data: &T) -> ByteBuf33 fn make_byte_buf<T: serde::Serialize>(data: &T) -> ByteBuf {
34     let vec = bincode::serialize(data).unwrap();
35     ByteBuf::from_vec(vec)
36 }
37 
38 #[repr(C)]
39 pub struct ShaderModuleDescriptor {
40     label: RawString,
41     code: *const u8,
42     code_length: usize,
43 }
44 
45 #[repr(C)]
46 pub struct ProgrammableStageDescriptor {
47     module: id::ShaderModuleId,
48     entry_point: RawString,
49 }
50 
51 impl ProgrammableStageDescriptor {
to_wgpu(&self) -> wgc::pipeline::ProgrammableStageDescriptor52     fn to_wgpu(&self) -> wgc::pipeline::ProgrammableStageDescriptor {
53         wgc::pipeline::ProgrammableStageDescriptor {
54             module: self.module,
55             entry_point: cow_label(&self.entry_point).unwrap(),
56         }
57     }
58 }
59 
60 #[repr(C)]
61 pub struct ComputePipelineDescriptor {
62     label: RawString,
63     layout: Option<id::PipelineLayoutId>,
64     stage: ProgrammableStageDescriptor,
65 }
66 
67 #[repr(C)]
68 pub struct VertexBufferLayout {
69     array_stride: wgt::BufferAddress,
70     step_mode: wgt::VertexStepMode,
71     attributes: *const wgt::VertexAttribute,
72     attributes_length: usize,
73 }
74 
75 #[repr(C)]
76 pub struct VertexState {
77     stage: ProgrammableStageDescriptor,
78     buffers: *const VertexBufferLayout,
79     buffers_length: usize,
80 }
81 
82 impl VertexState {
to_wgpu(&self) -> wgc::pipeline::VertexState83     fn to_wgpu(&self) -> wgc::pipeline::VertexState {
84         let buffer_layouts = make_slice(self.buffers, self.buffers_length)
85             .iter()
86             .map(|vb| wgc::pipeline::VertexBufferLayout {
87                 array_stride: vb.array_stride,
88                 step_mode: vb.step_mode,
89                 attributes: Cow::Borrowed(make_slice(vb.attributes, vb.attributes_length)),
90             })
91             .collect();
92         wgc::pipeline::VertexState {
93             stage: self.stage.to_wgpu(),
94             buffers: Cow::Owned(buffer_layouts),
95         }
96     }
97 }
98 
99 #[repr(C)]
100 pub struct ColorTargetState<'a> {
101     format: wgt::TextureFormat,
102     blend: Option<&'a wgt::BlendState>,
103     write_mask: wgt::ColorWrites,
104 }
105 
106 #[repr(C)]
107 pub struct FragmentState<'a> {
108     stage: ProgrammableStageDescriptor,
109     targets: *const ColorTargetState<'a>,
110     targets_length: usize,
111 }
112 
113 impl FragmentState<'_> {
to_wgpu(&self) -> wgc::pipeline::FragmentState114     fn to_wgpu(&self) -> wgc::pipeline::FragmentState {
115         let color_targets = make_slice(self.targets, self.targets_length)
116             .iter()
117             .map(|ct| wgt::ColorTargetState {
118                 format: ct.format,
119                 blend: ct.blend.cloned(),
120                 write_mask: ct.write_mask,
121             })
122             .collect();
123         wgc::pipeline::FragmentState {
124             stage: self.stage.to_wgpu(),
125             targets: Cow::Owned(color_targets),
126         }
127     }
128 }
129 
130 #[repr(C)]
131 pub struct PrimitiveState<'a> {
132     topology: wgt::PrimitiveTopology,
133     strip_index_format: Option<&'a wgt::IndexFormat>,
134     front_face: wgt::FrontFace,
135     cull_mode: Option<&'a wgt::Face>,
136     polygon_mode: wgt::PolygonMode,
137     unclipped_depth: bool,
138 }
139 
140 impl PrimitiveState<'_> {
to_wgpu(&self) -> wgt::PrimitiveState141     fn to_wgpu(&self) -> wgt::PrimitiveState {
142         wgt::PrimitiveState {
143             topology: self.topology,
144             strip_index_format: self.strip_index_format.cloned(),
145             front_face: self.front_face.clone(),
146             cull_mode: self.cull_mode.cloned(),
147             polygon_mode: self.polygon_mode,
148             unclipped_depth: self.unclipped_depth,
149             conservative: false,
150         }
151     }
152 }
153 
154 #[repr(C)]
155 pub struct RenderPipelineDescriptor<'a> {
156     label: RawString,
157     layout: Option<id::PipelineLayoutId>,
158     vertex: &'a VertexState,
159     primitive: PrimitiveState<'a>,
160     fragment: Option<&'a FragmentState<'a>>,
161     depth_stencil: Option<&'a wgt::DepthStencilState>,
162     multisample: wgt::MultisampleState,
163 }
164 
165 #[repr(C)]
166 pub enum RawTextureSampleType {
167     Float,
168     UnfilterableFloat,
169     Uint,
170     Sint,
171     Depth,
172 }
173 
174 #[repr(C)]
175 pub enum RawBindingType {
176     UniformBuffer,
177     StorageBuffer,
178     ReadonlyStorageBuffer,
179     Sampler,
180     SampledTexture,
181     ReadonlyStorageTexture,
182     WriteonlyStorageTexture,
183 }
184 
185 #[repr(C)]
186 pub struct BindGroupLayoutEntry<'a> {
187     binding: u32,
188     visibility: wgt::ShaderStages,
189     ty: RawBindingType,
190     has_dynamic_offset: bool,
191     min_binding_size: Option<wgt::BufferSize>,
192     view_dimension: Option<&'a wgt::TextureViewDimension>,
193     texture_sample_type: Option<&'a RawTextureSampleType>,
194     multisampled: bool,
195     storage_texture_format: Option<&'a wgt::TextureFormat>,
196     sampler_filter: bool,
197     sampler_compare: bool,
198 }
199 
200 #[repr(C)]
201 pub struct BindGroupLayoutDescriptor<'a> {
202     label: RawString,
203     entries: *const BindGroupLayoutEntry<'a>,
204     entries_length: usize,
205 }
206 
207 #[repr(C)]
208 #[derive(Debug)]
209 pub struct BindGroupEntry {
210     binding: u32,
211     buffer: Option<id::BufferId>,
212     offset: wgt::BufferAddress,
213     size: Option<wgt::BufferSize>,
214     sampler: Option<id::SamplerId>,
215     texture_view: Option<id::TextureViewId>,
216 }
217 
218 #[repr(C)]
219 pub struct BindGroupDescriptor {
220     label: RawString,
221     layout: id::BindGroupLayoutId,
222     entries: *const BindGroupEntry,
223     entries_length: usize,
224 }
225 
226 #[repr(C)]
227 pub struct PipelineLayoutDescriptor {
228     label: RawString,
229     bind_group_layouts: *const id::BindGroupLayoutId,
230     bind_group_layouts_length: usize,
231 }
232 
233 #[repr(C)]
234 pub struct SamplerDescriptor<'a> {
235     label: RawString,
236     address_modes: [wgt::AddressMode; 3],
237     mag_filter: wgt::FilterMode,
238     min_filter: wgt::FilterMode,
239     mipmap_filter: wgt::FilterMode,
240     lod_min_clamp: f32,
241     lod_max_clamp: f32,
242     compare: Option<&'a wgt::CompareFunction>,
243     anisotropy_clamp: Option<NonZeroU8>,
244 }
245 
246 #[repr(C)]
247 pub struct TextureViewDescriptor<'a> {
248     label: RawString,
249     format: Option<&'a wgt::TextureFormat>,
250     dimension: Option<&'a wgt::TextureViewDimension>,
251     aspect: wgt::TextureAspect,
252     base_mip_level: u32,
253     mip_level_count: Option<NonZeroU32>,
254     base_array_layer: u32,
255     array_layer_count: Option<NonZeroU32>,
256 }
257 
258 #[repr(C)]
259 pub struct RenderBundleEncoderDescriptor<'a> {
260     label: RawString,
261     color_formats: *const wgt::TextureFormat,
262     color_formats_length: usize,
263     depth_stencil_format: Option<&'a wgt::TextureFormat>,
264     depth_read_only: bool,
265     stencil_read_only: bool,
266     sample_count: u32,
267 }
268 
269 #[derive(Debug, Default)]
270 struct IdentityHub {
271     adapters: IdentityManager,
272     devices: IdentityManager,
273     buffers: IdentityManager,
274     command_buffers: IdentityManager,
275     render_bundles: IdentityManager,
276     bind_group_layouts: IdentityManager,
277     pipeline_layouts: IdentityManager,
278     bind_groups: IdentityManager,
279     shader_modules: IdentityManager,
280     compute_pipelines: IdentityManager,
281     render_pipelines: IdentityManager,
282     textures: IdentityManager,
283     texture_views: IdentityManager,
284     samplers: IdentityManager,
285 }
286 
287 impl ImplicitLayout<'_> {
new(identities: &mut IdentityHub, backend: Backend) -> Self288     fn new(identities: &mut IdentityHub, backend: Backend) -> Self {
289         ImplicitLayout {
290             pipeline: identities.pipeline_layouts.alloc(backend),
291             bind_groups: Cow::Owned(
292                 (0..8) // hal::MAX_BIND_GROUPS
293                     .map(|_| identities.bind_group_layouts.alloc(backend))
294                     .collect(),
295             ),
296         }
297     }
298 }
299 
300 #[derive(Debug, Default)]
301 struct Identities {
302     vulkan: IdentityHub,
303     #[cfg(any(target_os = "ios", target_os = "macos"))]
304     metal: IdentityHub,
305     #[cfg(windows)]
306     dx12: IdentityHub,
307 }
308 
309 impl Identities {
select(&mut self, backend: Backend) -> &mut IdentityHub310     fn select(&mut self, backend: Backend) -> &mut IdentityHub {
311         match backend {
312             Backend::Vulkan => &mut self.vulkan,
313             #[cfg(any(target_os = "ios", target_os = "macos"))]
314             Backend::Metal => &mut self.metal,
315             #[cfg(windows)]
316             Backend::Dx12 => &mut self.dx12,
317             _ => panic!("Unexpected backend: {:?}", backend),
318         }
319     }
320 }
321 
322 #[derive(Debug)]
323 pub struct Client {
324     identities: Mutex<Identities>,
325 }
326 
327 #[no_mangle]
wgpu_client_drop_action(client: &mut Client, byte_buf: &ByteBuf)328 pub unsafe extern "C" fn wgpu_client_drop_action(client: &mut Client, byte_buf: &ByteBuf) {
329     let mut cursor = std::io::Cursor::new(byte_buf.as_slice());
330     let mut identities = client.identities.lock();
331     while let Ok(action) = bincode::deserialize_from(&mut cursor) {
332         match action {
333             DropAction::Adapter(id) => identities.select(id.backend()).adapters.free(id),
334             DropAction::Device(id) => identities.select(id.backend()).devices.free(id),
335             DropAction::ShaderModule(id) => identities.select(id.backend()).shader_modules.free(id),
336             DropAction::PipelineLayout(id) => {
337                 identities.select(id.backend()).pipeline_layouts.free(id)
338             }
339             DropAction::BindGroupLayout(id) => {
340                 identities.select(id.backend()).bind_group_layouts.free(id)
341             }
342             DropAction::BindGroup(id) => identities.select(id.backend()).bind_groups.free(id),
343             DropAction::CommandBuffer(id) => {
344                 identities.select(id.backend()).command_buffers.free(id)
345             }
346             DropAction::RenderBundle(id) => identities.select(id.backend()).render_bundles.free(id),
347             DropAction::RenderPipeline(id) => {
348                 identities.select(id.backend()).render_pipelines.free(id)
349             }
350             DropAction::ComputePipeline(id) => {
351                 identities.select(id.backend()).compute_pipelines.free(id)
352             }
353             DropAction::Buffer(id) => identities.select(id.backend()).buffers.free(id),
354             DropAction::Texture(id) => identities.select(id.backend()).textures.free(id),
355             DropAction::TextureView(id) => identities.select(id.backend()).texture_views.free(id),
356             DropAction::Sampler(id) => identities.select(id.backend()).samplers.free(id),
357         }
358     }
359 }
360 
361 #[no_mangle]
wgpu_client_kill_device_id(client: &Client, id: id::DeviceId)362 pub extern "C" fn wgpu_client_kill_device_id(client: &Client, id: id::DeviceId) {
363     client
364         .identities
365         .lock()
366         .select(id.backend())
367         .devices
368         .free(id)
369 }
370 
371 #[repr(C)]
372 #[derive(Debug)]
373 pub struct Infrastructure {
374     pub client: *mut Client,
375     pub error: *const u8,
376 }
377 
378 #[no_mangle]
wgpu_client_new() -> Infrastructure379 pub extern "C" fn wgpu_client_new() -> Infrastructure {
380     log::info!("Initializing WGPU client");
381     let client = Box::new(Client {
382         identities: Mutex::new(Identities::default()),
383     });
384     Infrastructure {
385         client: Box::into_raw(client),
386         error: ptr::null(),
387     }
388 }
389 
390 /// # Safety
391 ///
392 /// This function is unsafe because improper use may lead to memory
393 /// problems. For example, a double-free may occur if the function is called
394 /// twice on the same raw pointer.
395 #[no_mangle]
wgpu_client_delete(client: *mut Client)396 pub unsafe extern "C" fn wgpu_client_delete(client: *mut Client) {
397     log::info!("Terminating WGPU client");
398     let _client = Box::from_raw(client);
399 }
400 
401 /// # Safety
402 ///
403 /// This function is unsafe as there is no guarantee that the given pointer is
404 /// valid for `id_length` elements.
405 #[no_mangle]
wgpu_client_make_adapter_ids( client: &Client, ids: *mut id::AdapterId, id_length: usize, ) -> usize406 pub unsafe extern "C" fn wgpu_client_make_adapter_ids(
407     client: &Client,
408     ids: *mut id::AdapterId,
409     id_length: usize,
410 ) -> usize {
411     let mut identities = client.identities.lock();
412     assert_ne!(id_length, 0);
413     let mut ids = std::slice::from_raw_parts_mut(ids, id_length).iter_mut();
414 
415     *ids.next().unwrap() = identities.vulkan.adapters.alloc(Backend::Vulkan);
416 
417     #[cfg(any(target_os = "ios", target_os = "macos"))]
418     {
419         *ids.next().unwrap() = identities.metal.adapters.alloc(Backend::Metal);
420     }
421     #[cfg(windows)]
422     {
423         *ids.next().unwrap() = identities.dx12.adapters.alloc(Backend::Dx12);
424     }
425 
426     id_length - ids.len()
427 }
428 
429 #[no_mangle]
wgpu_client_fill_default_limits(limits: &mut wgt::Limits)430 pub extern "C" fn wgpu_client_fill_default_limits(limits: &mut wgt::Limits) {
431     *limits = wgt::Limits::default();
432 }
433 
434 #[no_mangle]
wgpu_client_adapter_extract_info( byte_buf: &ByteBuf, info: &mut AdapterInformation, )435 pub extern "C" fn wgpu_client_adapter_extract_info(
436     byte_buf: &ByteBuf,
437     info: &mut AdapterInformation,
438 ) {
439     *info = bincode::deserialize(unsafe { byte_buf.as_slice() }).unwrap();
440 }
441 
442 #[no_mangle]
wgpu_client_serialize_device_descriptor( desc: &wgt::DeviceDescriptor<RawString>, bb: &mut ByteBuf, )443 pub extern "C" fn wgpu_client_serialize_device_descriptor(
444     desc: &wgt::DeviceDescriptor<RawString>,
445     bb: &mut ByteBuf,
446 ) {
447     *bb = make_byte_buf(&desc.map_label(cow_label));
448 }
449 
450 #[no_mangle]
wgpu_client_make_device_id( client: &Client, adapter_id: id::AdapterId, ) -> id::DeviceId451 pub extern "C" fn wgpu_client_make_device_id(
452     client: &Client,
453     adapter_id: id::AdapterId,
454 ) -> id::DeviceId {
455     let backend = adapter_id.backend();
456     client
457         .identities
458         .lock()
459         .select(backend)
460         .devices
461         .alloc(backend)
462 }
463 
464 #[no_mangle]
wgpu_client_make_buffer_id( client: &Client, device_id: id::DeviceId, ) -> id::BufferId465 pub extern "C" fn wgpu_client_make_buffer_id(
466     client: &Client,
467     device_id: id::DeviceId,
468 ) -> id::BufferId {
469     let backend = device_id.backend();
470     client
471         .identities
472         .lock()
473         .select(backend)
474         .buffers
475         .alloc(backend)
476 }
477 
478 #[no_mangle]
wgpu_client_create_buffer( client: &Client, device_id: id::DeviceId, desc: &wgt::BufferDescriptor<RawString>, bb: &mut ByteBuf, ) -> id::BufferId479 pub extern "C" fn wgpu_client_create_buffer(
480     client: &Client,
481     device_id: id::DeviceId,
482     desc: &wgt::BufferDescriptor<RawString>,
483     bb: &mut ByteBuf,
484 ) -> id::BufferId {
485     let backend = device_id.backend();
486     let id = client
487         .identities
488         .lock()
489         .select(backend)
490         .buffers
491         .alloc(backend);
492 
493     let action = DeviceAction::CreateBuffer(id, desc.map_label(cow_label));
494     *bb = make_byte_buf(&action);
495     id
496 }
497 
498 #[no_mangle]
wgpu_client_create_texture( client: &Client, device_id: id::DeviceId, desc: &wgt::TextureDescriptor<RawString>, bb: &mut ByteBuf, ) -> id::TextureId499 pub extern "C" fn wgpu_client_create_texture(
500     client: &Client,
501     device_id: id::DeviceId,
502     desc: &wgt::TextureDescriptor<RawString>,
503     bb: &mut ByteBuf,
504 ) -> id::TextureId {
505     let backend = device_id.backend();
506     let id = client
507         .identities
508         .lock()
509         .select(backend)
510         .textures
511         .alloc(backend);
512 
513     let action = DeviceAction::CreateTexture(id, desc.map_label(cow_label));
514     *bb = make_byte_buf(&action);
515     id
516 }
517 
518 #[no_mangle]
wgpu_client_create_texture_view( client: &Client, device_id: id::DeviceId, desc: &TextureViewDescriptor, bb: &mut ByteBuf, ) -> id::TextureViewId519 pub extern "C" fn wgpu_client_create_texture_view(
520     client: &Client,
521     device_id: id::DeviceId,
522     desc: &TextureViewDescriptor,
523     bb: &mut ByteBuf,
524 ) -> id::TextureViewId {
525     let backend = device_id.backend();
526     let id = client
527         .identities
528         .lock()
529         .select(backend)
530         .texture_views
531         .alloc(backend);
532 
533     let wgpu_desc = wgc::resource::TextureViewDescriptor {
534         label: cow_label(&desc.label),
535         format: desc.format.cloned(),
536         dimension: desc.dimension.cloned(),
537         range: wgt::ImageSubresourceRange {
538             aspect: desc.aspect,
539             base_mip_level: desc.base_mip_level,
540             mip_level_count: desc.mip_level_count,
541             base_array_layer: desc.base_array_layer,
542             array_layer_count: desc.array_layer_count,
543         },
544     };
545 
546     let action = TextureAction::CreateView(id, wgpu_desc);
547     *bb = make_byte_buf(&action);
548     id
549 }
550 
551 #[no_mangle]
wgpu_client_create_sampler( client: &Client, device_id: id::DeviceId, desc: &SamplerDescriptor, bb: &mut ByteBuf, ) -> id::SamplerId552 pub extern "C" fn wgpu_client_create_sampler(
553     client: &Client,
554     device_id: id::DeviceId,
555     desc: &SamplerDescriptor,
556     bb: &mut ByteBuf,
557 ) -> id::SamplerId {
558     let backend = device_id.backend();
559     let id = client
560         .identities
561         .lock()
562         .select(backend)
563         .samplers
564         .alloc(backend);
565 
566     let wgpu_desc = wgc::resource::SamplerDescriptor {
567         label: cow_label(&desc.label),
568         address_modes: desc.address_modes,
569         mag_filter: desc.mag_filter,
570         min_filter: desc.min_filter,
571         mipmap_filter: desc.mipmap_filter,
572         lod_min_clamp: desc.lod_min_clamp,
573         lod_max_clamp: desc.lod_max_clamp,
574         compare: desc.compare.cloned(),
575         anisotropy_clamp: desc.anisotropy_clamp,
576         border_color: None,
577     };
578     let action = DeviceAction::CreateSampler(id, wgpu_desc);
579     *bb = make_byte_buf(&action);
580     id
581 }
582 
583 #[no_mangle]
wgpu_client_make_encoder_id( client: &Client, device_id: id::DeviceId, ) -> id::CommandEncoderId584 pub extern "C" fn wgpu_client_make_encoder_id(
585     client: &Client,
586     device_id: id::DeviceId,
587 ) -> id::CommandEncoderId {
588     let backend = device_id.backend();
589     client
590         .identities
591         .lock()
592         .select(backend)
593         .command_buffers
594         .alloc(backend)
595 }
596 
597 #[no_mangle]
wgpu_client_create_command_encoder( client: &Client, device_id: id::DeviceId, desc: &wgt::CommandEncoderDescriptor<RawString>, bb: &mut ByteBuf, ) -> id::CommandEncoderId598 pub extern "C" fn wgpu_client_create_command_encoder(
599     client: &Client,
600     device_id: id::DeviceId,
601     desc: &wgt::CommandEncoderDescriptor<RawString>,
602     bb: &mut ByteBuf,
603 ) -> id::CommandEncoderId {
604     let backend = device_id.backend();
605     let id = client
606         .identities
607         .lock()
608         .select(backend)
609         .command_buffers
610         .alloc(backend);
611 
612     let action = DeviceAction::CreateCommandEncoder(id, desc.map_label(cow_label));
613     *bb = make_byte_buf(&action);
614     id
615 }
616 
617 #[no_mangle]
wgpu_device_create_render_bundle_encoder( device_id: id::DeviceId, desc: &RenderBundleEncoderDescriptor, bb: &mut ByteBuf, ) -> *mut wgc::command::RenderBundleEncoder618 pub extern "C" fn wgpu_device_create_render_bundle_encoder(
619     device_id: id::DeviceId,
620     desc: &RenderBundleEncoderDescriptor,
621     bb: &mut ByteBuf,
622 ) -> *mut wgc::command::RenderBundleEncoder {
623     let descriptor = wgc::command::RenderBundleEncoderDescriptor {
624         label: cow_label(&desc.label),
625         color_formats: Cow::Borrowed(make_slice(desc.color_formats, desc.color_formats_length)),
626         depth_stencil: desc
627             .depth_stencil_format
628             .map(|&format| wgt::RenderBundleDepthStencil {
629                 format,
630                 depth_read_only: desc.depth_read_only,
631                 stencil_read_only: desc.stencil_read_only,
632             }),
633         sample_count: desc.sample_count,
634         multiview: None,
635     };
636     match wgc::command::RenderBundleEncoder::new(&descriptor, device_id, None) {
637         Ok(encoder) => Box::into_raw(Box::new(encoder)),
638         Err(e) => {
639             let message = format!("Error in Device::create_render_bundle_encoder: {}", e);
640             let action = DeviceAction::Error(message);
641             *bb = make_byte_buf(&action);
642             ptr::null_mut()
643         }
644     }
645 }
646 
647 #[no_mangle]
wgpu_render_bundle_encoder_destroy( pass: *mut wgc::command::RenderBundleEncoder, )648 pub unsafe extern "C" fn wgpu_render_bundle_encoder_destroy(
649     pass: *mut wgc::command::RenderBundleEncoder,
650 ) {
651     // The RB encoder is just a boxed Rust struct, it doesn't have any API primitives
652     // associated with it right now, but in the future it will.
653     let _ = Box::from_raw(pass);
654 }
655 
656 #[no_mangle]
wgpu_client_create_render_bundle( client: &Client, encoder: *mut wgc::command::RenderBundleEncoder, device_id: id::DeviceId, desc: &wgt::RenderBundleDescriptor<RawString>, bb: &mut ByteBuf, ) -> id::RenderBundleId657 pub unsafe extern "C" fn wgpu_client_create_render_bundle(
658     client: &Client,
659     encoder: *mut wgc::command::RenderBundleEncoder,
660     device_id: id::DeviceId,
661     desc: &wgt::RenderBundleDescriptor<RawString>,
662     bb: &mut ByteBuf,
663 ) -> id::RenderBundleId {
664     let backend = device_id.backend();
665     let id = client
666         .identities
667         .lock()
668         .select(backend)
669         .render_bundles
670         .alloc(backend);
671 
672     let action =
673         DeviceAction::CreateRenderBundle(id, *Box::from_raw(encoder), desc.map_label(cow_label));
674     *bb = make_byte_buf(&action);
675     id
676 }
677 
678 #[repr(C)]
679 pub struct ComputePassDescriptor {
680     pub label: RawString,
681 }
682 
683 #[no_mangle]
wgpu_command_encoder_begin_compute_pass( encoder_id: id::CommandEncoderId, desc: &ComputePassDescriptor, ) -> *mut wgc::command::ComputePass684 pub unsafe extern "C" fn wgpu_command_encoder_begin_compute_pass(
685     encoder_id: id::CommandEncoderId,
686     desc: &ComputePassDescriptor,
687 ) -> *mut wgc::command::ComputePass {
688     let pass = wgc::command::ComputePass::new(
689         encoder_id,
690         &wgc::command::ComputePassDescriptor {
691             label: cow_label(&desc.label),
692         },
693     );
694     Box::into_raw(Box::new(pass))
695 }
696 
697 #[no_mangle]
wgpu_compute_pass_finish( pass: *mut wgc::command::ComputePass, output: &mut ByteBuf, )698 pub unsafe extern "C" fn wgpu_compute_pass_finish(
699     pass: *mut wgc::command::ComputePass,
700     output: &mut ByteBuf,
701 ) {
702     let command = Box::from_raw(pass).into_command();
703     *output = make_byte_buf(&command);
704 }
705 
706 #[no_mangle]
wgpu_compute_pass_destroy(pass: *mut wgc::command::ComputePass)707 pub unsafe extern "C" fn wgpu_compute_pass_destroy(pass: *mut wgc::command::ComputePass) {
708     let _ = Box::from_raw(pass);
709 }
710 
711 #[repr(C)]
712 pub struct RenderPassDescriptor {
713     pub label: RawString,
714     pub color_attachments: *const wgc::command::RenderPassColorAttachment,
715     pub color_attachments_length: usize,
716     pub depth_stencil_attachment: *const wgc::command::RenderPassDepthStencilAttachment,
717 }
718 
719 #[no_mangle]
wgpu_command_encoder_begin_render_pass( encoder_id: id::CommandEncoderId, desc: &RenderPassDescriptor, ) -> *mut wgc::command::RenderPass720 pub unsafe extern "C" fn wgpu_command_encoder_begin_render_pass(
721     encoder_id: id::CommandEncoderId,
722     desc: &RenderPassDescriptor,
723 ) -> *mut wgc::command::RenderPass {
724     let pass = wgc::command::RenderPass::new(
725         encoder_id,
726         &wgc::command::RenderPassDescriptor {
727             label: cow_label(&desc.label),
728             color_attachments: Cow::Borrowed(make_slice(
729                 desc.color_attachments,
730                 desc.color_attachments_length,
731             )),
732             depth_stencil_attachment: desc.depth_stencil_attachment.as_ref(),
733         },
734     );
735     Box::into_raw(Box::new(pass))
736 }
737 
738 #[no_mangle]
wgpu_render_pass_finish( pass: *mut wgc::command::RenderPass, output: &mut ByteBuf, )739 pub unsafe extern "C" fn wgpu_render_pass_finish(
740     pass: *mut wgc::command::RenderPass,
741     output: &mut ByteBuf,
742 ) {
743     let command = Box::from_raw(pass).into_command();
744     *output = make_byte_buf(&command);
745 }
746 
747 #[no_mangle]
wgpu_render_pass_destroy(pass: *mut wgc::command::RenderPass)748 pub unsafe extern "C" fn wgpu_render_pass_destroy(pass: *mut wgc::command::RenderPass) {
749     let _ = Box::from_raw(pass);
750 }
751 
752 #[no_mangle]
wgpu_client_create_bind_group_layout( client: &Client, device_id: id::DeviceId, desc: &BindGroupLayoutDescriptor, bb: &mut ByteBuf, ) -> id::BindGroupLayoutId753 pub unsafe extern "C" fn wgpu_client_create_bind_group_layout(
754     client: &Client,
755     device_id: id::DeviceId,
756     desc: &BindGroupLayoutDescriptor,
757     bb: &mut ByteBuf,
758 ) -> id::BindGroupLayoutId {
759     let backend = device_id.backend();
760     let id = client
761         .identities
762         .lock()
763         .select(backend)
764         .bind_group_layouts
765         .alloc(backend);
766 
767     let mut entries = Vec::with_capacity(desc.entries_length);
768     for entry in make_slice(desc.entries, desc.entries_length) {
769         entries.push(wgt::BindGroupLayoutEntry {
770             binding: entry.binding,
771             visibility: entry.visibility,
772             count: None,
773             ty: match entry.ty {
774                 RawBindingType::UniformBuffer => wgt::BindingType::Buffer {
775                     ty: wgt::BufferBindingType::Uniform,
776                     has_dynamic_offset: entry.has_dynamic_offset,
777                     min_binding_size: entry.min_binding_size,
778                 },
779                 RawBindingType::StorageBuffer => wgt::BindingType::Buffer {
780                     ty: wgt::BufferBindingType::Storage { read_only: false },
781                     has_dynamic_offset: entry.has_dynamic_offset,
782                     min_binding_size: entry.min_binding_size,
783                 },
784                 RawBindingType::ReadonlyStorageBuffer => wgt::BindingType::Buffer {
785                     ty: wgt::BufferBindingType::Storage { read_only: true },
786                     has_dynamic_offset: entry.has_dynamic_offset,
787                     min_binding_size: entry.min_binding_size,
788                 },
789                 RawBindingType::Sampler => wgt::BindingType::Sampler(if entry.sampler_compare {
790                     wgt::SamplerBindingType::Comparison
791                 } else if entry.sampler_filter {
792                     wgt::SamplerBindingType::Filtering
793                 } else {
794                     wgt::SamplerBindingType::NonFiltering
795                 }),
796                 RawBindingType::SampledTexture => wgt::BindingType::Texture {
797                     //TODO: the spec has a bug here
798                     view_dimension: *entry
799                         .view_dimension
800                         .unwrap_or(&wgt::TextureViewDimension::D2),
801                     sample_type: match entry.texture_sample_type {
802                         None | Some(RawTextureSampleType::Float) => {
803                             wgt::TextureSampleType::Float { filterable: true }
804                         }
805                         Some(RawTextureSampleType::UnfilterableFloat) => {
806                             wgt::TextureSampleType::Float { filterable: false }
807                         }
808                         Some(RawTextureSampleType::Uint) => wgt::TextureSampleType::Uint,
809                         Some(RawTextureSampleType::Sint) => wgt::TextureSampleType::Sint,
810                         Some(RawTextureSampleType::Depth) => wgt::TextureSampleType::Depth,
811                     },
812                     multisampled: entry.multisampled,
813                 },
814                 RawBindingType::ReadonlyStorageTexture => wgt::BindingType::StorageTexture {
815                     access: wgt::StorageTextureAccess::ReadOnly,
816                     view_dimension: *entry.view_dimension.unwrap(),
817                     format: *entry.storage_texture_format.unwrap(),
818                 },
819                 RawBindingType::WriteonlyStorageTexture => wgt::BindingType::StorageTexture {
820                     access: wgt::StorageTextureAccess::WriteOnly,
821                     view_dimension: *entry.view_dimension.unwrap(),
822                     format: *entry.storage_texture_format.unwrap(),
823                 },
824             },
825         });
826     }
827     let wgpu_desc = wgc::binding_model::BindGroupLayoutDescriptor {
828         label: cow_label(&desc.label),
829         entries: Cow::Owned(entries),
830     };
831 
832     let action = DeviceAction::CreateBindGroupLayout(id, wgpu_desc);
833     *bb = make_byte_buf(&action);
834     id
835 }
836 
837 #[no_mangle]
wgpu_client_create_pipeline_layout( client: &Client, device_id: id::DeviceId, desc: &PipelineLayoutDescriptor, bb: &mut ByteBuf, ) -> id::PipelineLayoutId838 pub unsafe extern "C" fn wgpu_client_create_pipeline_layout(
839     client: &Client,
840     device_id: id::DeviceId,
841     desc: &PipelineLayoutDescriptor,
842     bb: &mut ByteBuf,
843 ) -> id::PipelineLayoutId {
844     let backend = device_id.backend();
845     let id = client
846         .identities
847         .lock()
848         .select(backend)
849         .pipeline_layouts
850         .alloc(backend);
851 
852     let wgpu_desc = wgc::binding_model::PipelineLayoutDescriptor {
853         label: cow_label(&desc.label),
854         bind_group_layouts: Cow::Borrowed(make_slice(
855             desc.bind_group_layouts,
856             desc.bind_group_layouts_length,
857         )),
858         push_constant_ranges: Cow::Borrowed(&[]),
859     };
860 
861     let action = DeviceAction::CreatePipelineLayout(id, wgpu_desc);
862     *bb = make_byte_buf(&action);
863     id
864 }
865 
866 #[no_mangle]
wgpu_client_create_bind_group( client: &Client, device_id: id::DeviceId, desc: &BindGroupDescriptor, bb: &mut ByteBuf, ) -> id::BindGroupId867 pub unsafe extern "C" fn wgpu_client_create_bind_group(
868     client: &Client,
869     device_id: id::DeviceId,
870     desc: &BindGroupDescriptor,
871     bb: &mut ByteBuf,
872 ) -> id::BindGroupId {
873     let backend = device_id.backend();
874     let id = client
875         .identities
876         .lock()
877         .select(backend)
878         .bind_groups
879         .alloc(backend);
880 
881     let mut entries = Vec::with_capacity(desc.entries_length);
882     for entry in make_slice(desc.entries, desc.entries_length) {
883         entries.push(wgc::binding_model::BindGroupEntry {
884             binding: entry.binding,
885             resource: if let Some(id) = entry.buffer {
886                 wgc::binding_model::BindingResource::Buffer(wgc::binding_model::BufferBinding {
887                     buffer_id: id,
888                     offset: entry.offset,
889                     size: entry.size,
890                 })
891             } else if let Some(id) = entry.sampler {
892                 wgc::binding_model::BindingResource::Sampler(id)
893             } else if let Some(id) = entry.texture_view {
894                 wgc::binding_model::BindingResource::TextureView(id)
895             } else {
896                 panic!("Unexpected binding entry {:?}", entry);
897             },
898         });
899     }
900     let wgpu_desc = wgc::binding_model::BindGroupDescriptor {
901         label: cow_label(&desc.label),
902         layout: desc.layout,
903         entries: Cow::Owned(entries),
904     };
905 
906     let action = DeviceAction::CreateBindGroup(id, wgpu_desc);
907     *bb = make_byte_buf(&action);
908     id
909 }
910 
911 #[no_mangle]
wgpu_client_create_shader_module( client: &Client, device_id: id::DeviceId, desc: &ShaderModuleDescriptor, bb: &mut ByteBuf, ) -> id::ShaderModuleId912 pub unsafe extern "C" fn wgpu_client_create_shader_module(
913     client: &Client,
914     device_id: id::DeviceId,
915     desc: &ShaderModuleDescriptor,
916     bb: &mut ByteBuf,
917 ) -> id::ShaderModuleId {
918     let backend = device_id.backend();
919     let id = client
920         .identities
921         .lock()
922         .select(backend)
923         .shader_modules
924         .alloc(backend);
925 
926     let code =
927         std::str::from_utf8_unchecked(std::slice::from_raw_parts(desc.code, desc.code_length));
928     let desc = wgc::pipeline::ShaderModuleDescriptor {
929         label: cow_label(&desc.label),
930         shader_bound_checks: wgt::ShaderBoundChecks::new(),
931     };
932 
933     let action = DeviceAction::CreateShaderModule(id, desc, Cow::Borrowed(code));
934     *bb = make_byte_buf(&action);
935     id
936 }
937 
938 #[no_mangle]
wgpu_client_create_compute_pipeline( client: &Client, device_id: id::DeviceId, desc: &ComputePipelineDescriptor, bb: &mut ByteBuf, implicit_pipeline_layout_id: *mut Option<id::PipelineLayoutId>, implicit_bind_group_layout_ids: *mut Option<id::BindGroupLayoutId>, ) -> id::ComputePipelineId939 pub unsafe extern "C" fn wgpu_client_create_compute_pipeline(
940     client: &Client,
941     device_id: id::DeviceId,
942     desc: &ComputePipelineDescriptor,
943     bb: &mut ByteBuf,
944     implicit_pipeline_layout_id: *mut Option<id::PipelineLayoutId>,
945     implicit_bind_group_layout_ids: *mut Option<id::BindGroupLayoutId>,
946 ) -> id::ComputePipelineId {
947     let backend = device_id.backend();
948     let mut identities = client.identities.lock();
949     let id = identities.select(backend).compute_pipelines.alloc(backend);
950 
951     let wgpu_desc = wgc::pipeline::ComputePipelineDescriptor {
952         label: cow_label(&desc.label),
953         layout: desc.layout,
954         stage: desc.stage.to_wgpu(),
955     };
956 
957     let implicit = match desc.layout {
958         Some(_) => None,
959         None => {
960             let implicit = ImplicitLayout::new(identities.select(backend), backend);
961             ptr::write(implicit_pipeline_layout_id, Some(implicit.pipeline));
962             for (i, bgl_id) in implicit.bind_groups.iter().enumerate() {
963                 *implicit_bind_group_layout_ids.add(i) = Some(*bgl_id);
964             }
965             Some(implicit)
966         }
967     };
968 
969     let action = DeviceAction::CreateComputePipeline(id, wgpu_desc, implicit);
970     *bb = make_byte_buf(&action);
971     id
972 }
973 
974 #[no_mangle]
wgpu_client_create_render_pipeline( client: &Client, device_id: id::DeviceId, desc: &RenderPipelineDescriptor, bb: &mut ByteBuf, implicit_pipeline_layout_id: *mut Option<id::PipelineLayoutId>, implicit_bind_group_layout_ids: *mut Option<id::BindGroupLayoutId>, ) -> id::RenderPipelineId975 pub unsafe extern "C" fn wgpu_client_create_render_pipeline(
976     client: &Client,
977     device_id: id::DeviceId,
978     desc: &RenderPipelineDescriptor,
979     bb: &mut ByteBuf,
980     implicit_pipeline_layout_id: *mut Option<id::PipelineLayoutId>,
981     implicit_bind_group_layout_ids: *mut Option<id::BindGroupLayoutId>,
982 ) -> id::RenderPipelineId {
983     let backend = device_id.backend();
984     let mut identities = client.identities.lock();
985     let id = identities.select(backend).render_pipelines.alloc(backend);
986 
987     let wgpu_desc = wgc::pipeline::RenderPipelineDescriptor {
988         label: cow_label(&desc.label),
989         layout: desc.layout,
990         vertex: desc.vertex.to_wgpu(),
991         fragment: desc.fragment.map(FragmentState::to_wgpu),
992         primitive: desc.primitive.to_wgpu(),
993         depth_stencil: desc.depth_stencil.cloned(),
994         multisample: desc.multisample.clone(),
995         multiview: None,
996     };
997 
998     let implicit = match desc.layout {
999         Some(_) => None,
1000         None => {
1001             let implicit = ImplicitLayout::new(identities.select(backend), backend);
1002             ptr::write(implicit_pipeline_layout_id, Some(implicit.pipeline));
1003             for (i, bgl_id) in implicit.bind_groups.iter().enumerate() {
1004                 *implicit_bind_group_layout_ids.add(i) = Some(*bgl_id);
1005             }
1006             Some(implicit)
1007         }
1008     };
1009 
1010     let action = DeviceAction::CreateRenderPipeline(id, wgpu_desc, implicit);
1011     *bb = make_byte_buf(&action);
1012     id
1013 }
1014 
1015 #[no_mangle]
wgpu_command_encoder_copy_buffer_to_buffer( src: id::BufferId, src_offset: wgt::BufferAddress, dst: id::BufferId, dst_offset: wgt::BufferAddress, size: wgt::BufferAddress, bb: &mut ByteBuf, )1016 pub unsafe extern "C" fn wgpu_command_encoder_copy_buffer_to_buffer(
1017     src: id::BufferId,
1018     src_offset: wgt::BufferAddress,
1019     dst: id::BufferId,
1020     dst_offset: wgt::BufferAddress,
1021     size: wgt::BufferAddress,
1022     bb: &mut ByteBuf,
1023 ) {
1024     let action = CommandEncoderAction::CopyBufferToBuffer {
1025         src,
1026         src_offset,
1027         dst,
1028         dst_offset,
1029         size,
1030     };
1031     *bb = make_byte_buf(&action);
1032 }
1033 
1034 #[no_mangle]
wgpu_command_encoder_copy_texture_to_buffer( src: wgc::command::ImageCopyTexture, dst: wgc::command::ImageCopyBuffer, size: wgt::Extent3d, bb: &mut ByteBuf, )1035 pub unsafe extern "C" fn wgpu_command_encoder_copy_texture_to_buffer(
1036     src: wgc::command::ImageCopyTexture,
1037     dst: wgc::command::ImageCopyBuffer,
1038     size: wgt::Extent3d,
1039     bb: &mut ByteBuf,
1040 ) {
1041     let action = CommandEncoderAction::CopyTextureToBuffer { src, dst, size };
1042     *bb = make_byte_buf(&action);
1043 }
1044 
1045 #[no_mangle]
wgpu_command_encoder_copy_buffer_to_texture( src: wgc::command::ImageCopyBuffer, dst: wgc::command::ImageCopyTexture, size: wgt::Extent3d, bb: &mut ByteBuf, )1046 pub unsafe extern "C" fn wgpu_command_encoder_copy_buffer_to_texture(
1047     src: wgc::command::ImageCopyBuffer,
1048     dst: wgc::command::ImageCopyTexture,
1049     size: wgt::Extent3d,
1050     bb: &mut ByteBuf,
1051 ) {
1052     let action = CommandEncoderAction::CopyBufferToTexture { src, dst, size };
1053     *bb = make_byte_buf(&action);
1054 }
1055 
1056 #[no_mangle]
wgpu_command_encoder_copy_texture_to_texture( src: wgc::command::ImageCopyTexture, dst: wgc::command::ImageCopyTexture, size: wgt::Extent3d, bb: &mut ByteBuf, )1057 pub unsafe extern "C" fn wgpu_command_encoder_copy_texture_to_texture(
1058     src: wgc::command::ImageCopyTexture,
1059     dst: wgc::command::ImageCopyTexture,
1060     size: wgt::Extent3d,
1061     bb: &mut ByteBuf,
1062 ) {
1063     let action = CommandEncoderAction::CopyTextureToTexture { src, dst, size };
1064     *bb = make_byte_buf(&action);
1065 }
1066 
1067 #[no_mangle]
wgpu_command_encoder_push_debug_group( marker: RawString, bb: &mut ByteBuf, )1068 pub unsafe extern "C" fn wgpu_command_encoder_push_debug_group(
1069     marker: RawString,
1070     bb: &mut ByteBuf,
1071 ) {
1072     let cstr = std::ffi::CStr::from_ptr(marker);
1073     let string = cstr.to_str().unwrap_or_default().to_string();
1074     let action = CommandEncoderAction::PushDebugGroup(string);
1075     *bb = make_byte_buf(&action);
1076 }
1077 
1078 #[no_mangle]
wgpu_command_encoder_pop_debug_group(bb: &mut ByteBuf)1079 pub unsafe extern "C" fn wgpu_command_encoder_pop_debug_group(bb: &mut ByteBuf) {
1080     let action = CommandEncoderAction::PopDebugGroup;
1081     *bb = make_byte_buf(&action);
1082 }
1083 
1084 #[no_mangle]
wgpu_command_encoder_insert_debug_marker( marker: RawString, bb: &mut ByteBuf, )1085 pub unsafe extern "C" fn wgpu_command_encoder_insert_debug_marker(
1086     marker: RawString,
1087     bb: &mut ByteBuf,
1088 ) {
1089     let cstr = std::ffi::CStr::from_ptr(marker);
1090     let string = cstr.to_str().unwrap_or_default().to_string();
1091     let action = CommandEncoderAction::InsertDebugMarker(string);
1092     *bb = make_byte_buf(&action);
1093 }
1094 
1095 #[no_mangle]
wgpu_render_pass_set_index_buffer( pass: &mut wgc::command::RenderPass, buffer: wgc::id::BufferId, index_format: wgt::IndexFormat, offset: wgt::BufferAddress, size: Option<wgt::BufferSize>, )1096 pub unsafe extern "C" fn wgpu_render_pass_set_index_buffer(
1097     pass: &mut wgc::command::RenderPass,
1098     buffer: wgc::id::BufferId,
1099     index_format: wgt::IndexFormat,
1100     offset: wgt::BufferAddress,
1101     size: Option<wgt::BufferSize>,
1102 ) {
1103     pass.set_index_buffer(buffer, index_format, offset, size);
1104 }
1105 
1106 #[no_mangle]
wgpu_render_bundle_set_index_buffer( encoder: &mut wgc::command::RenderBundleEncoder, buffer: wgc::id::BufferId, index_format: wgt::IndexFormat, offset: wgt::BufferAddress, size: Option<wgt::BufferSize>, )1107 pub unsafe extern "C" fn wgpu_render_bundle_set_index_buffer(
1108     encoder: &mut wgc::command::RenderBundleEncoder,
1109     buffer: wgc::id::BufferId,
1110     index_format: wgt::IndexFormat,
1111     offset: wgt::BufferAddress,
1112     size: Option<wgt::BufferSize>,
1113 ) {
1114     encoder.set_index_buffer(buffer, index_format, offset, size);
1115 }
1116 
1117 #[no_mangle]
wgpu_queue_write_buffer( dst: id::BufferId, offset: wgt::BufferAddress, bb: &mut ByteBuf, )1118 pub unsafe extern "C" fn wgpu_queue_write_buffer(
1119     dst: id::BufferId,
1120     offset: wgt::BufferAddress,
1121     bb: &mut ByteBuf,
1122 ) {
1123     let action = QueueWriteAction::Buffer { dst, offset };
1124     *bb = make_byte_buf(&action);
1125 }
1126 
1127 #[no_mangle]
wgpu_queue_write_texture( dst: wgt::ImageCopyTexture<id::TextureId>, layout: wgt::ImageDataLayout, size: wgt::Extent3d, bb: &mut ByteBuf, )1128 pub unsafe extern "C" fn wgpu_queue_write_texture(
1129     dst: wgt::ImageCopyTexture<id::TextureId>,
1130     layout: wgt::ImageDataLayout,
1131     size: wgt::Extent3d,
1132     bb: &mut ByteBuf,
1133 ) {
1134     let action = QueueWriteAction::Texture { dst, layout, size };
1135     *bb = make_byte_buf(&action);
1136 }
1137