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