wgpu_native/
device.rs

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
5use crate::GLOBAL;
6
7use core::{gfx_select, hub::Token, id};
8use wgt::{BackendBit, DeviceDescriptor, Limits};
9
10use std::{marker::PhantomData, slice};
11
12#[cfg(target_os = "macos")]
13use objc::{msg_send, runtime::Object, sel, sel_impl};
14
15pub type RequestAdapterCallback =
16    unsafe extern "C" fn(id: Option<id::AdapterId>, userdata: *mut std::ffi::c_void);
17
18pub fn wgpu_create_surface(raw_handle: raw_window_handle::RawWindowHandle) -> id::SurfaceId {
19    use raw_window_handle::RawWindowHandle as Rwh;
20
21    let instance = &GLOBAL.instance;
22    let surface = match raw_handle {
23        #[cfg(target_os = "ios")]
24        Rwh::IOS(h) => core::instance::Surface {
25            #[cfg(feature = "vulkan-portability")]
26            vulkan: None,
27            metal: instance
28                .metal
29                .create_surface_from_uiview(h.ui_view, cfg!(debug_assertions)),
30        },
31        #[cfg(target_os = "macos")]
32        Rwh::MacOS(h) => {
33            let ns_view = if h.ns_view.is_null() {
34                let ns_window = h.ns_window as *mut Object;
35                unsafe { msg_send![ns_window, contentView] }
36            } else {
37                h.ns_view
38            };
39            core::instance::Surface {
40                #[cfg(feature = "vulkan-portability")]
41                vulkan: instance
42                    .vulkan
43                    .as_ref()
44                    .map(|inst| inst.create_surface_from_ns_view(ns_view)),
45                metal: instance
46                    .metal
47                    .create_surface_from_nsview(ns_view, cfg!(debug_assertions)),
48            }
49        }
50        #[cfg(all(unix, not(target_os = "ios"), not(target_os = "macos")))]
51        Rwh::Xlib(h) => core::instance::Surface {
52            vulkan: instance
53                .vulkan
54                .as_ref()
55                .map(|inst| inst.create_surface_from_xlib(h.display as _, h.window as _)),
56        },
57        #[cfg(all(unix, not(target_os = "ios"), not(target_os = "macos")))]
58        Rwh::Wayland(h) => core::instance::Surface {
59            vulkan: instance
60                .vulkan
61                .as_ref()
62                .map(|inst| inst.create_surface_from_wayland(h.display, h.surface)),
63        },
64        #[cfg(windows)]
65        Rwh::Windows(h) => core::instance::Surface {
66            vulkan: instance
67                .vulkan
68                .as_ref()
69                .map(|inst| inst.create_surface_from_hwnd(std::ptr::null_mut(), h.hwnd)),
70            dx12: instance
71                .dx12
72                .as_ref()
73                .map(|inst| inst.create_surface_from_hwnd(h.hwnd)),
74            dx11: instance.dx11.create_surface_from_hwnd(h.hwnd),
75        },
76        _ => panic!("Unsupported window handle"),
77    };
78
79    let mut token = Token::root();
80    GLOBAL
81        .surfaces
82        .register_identity(PhantomData, surface, &mut token)
83}
84
85#[cfg(all(unix, not(target_os = "ios"), not(target_os = "macos")))]
86#[no_mangle]
87pub extern "C" fn wgpu_create_surface_from_xlib(
88    display: *mut *const std::ffi::c_void,
89    window: libc::c_ulong,
90) -> id::SurfaceId {
91    use raw_window_handle::unix::XlibHandle;
92    wgpu_create_surface(raw_window_handle::RawWindowHandle::Xlib(XlibHandle {
93        window,
94        display: display as *mut _,
95        ..XlibHandle::empty()
96    }))
97}
98
99#[cfg(all(unix, not(target_os = "ios"), not(target_os = "macos")))]
100#[no_mangle]
101pub extern "C" fn wgpu_create_surface_from_wayland(
102    surface: *mut std::ffi::c_void,
103    display: *mut std::ffi::c_void,
104) -> id::SurfaceId {
105    use raw_window_handle::unix::WaylandHandle;
106    wgpu_create_surface(raw_window_handle::RawWindowHandle::Wayland(WaylandHandle {
107        surface,
108        display,
109        ..WaylandHandle::empty()
110    }))
111}
112
113#[cfg(any(target_os = "ios", target_os = "macos"))]
114#[no_mangle]
115pub extern "C" fn wgpu_create_surface_from_metal_layer(
116    layer: *mut std::ffi::c_void,
117) -> id::SurfaceId {
118    let surface = core::instance::Surface {
119        #[cfg(feature = "vulkan-portability")]
120        vulkan: None, //TODO: currently requires `NSView`
121        metal: GLOBAL
122            .instance
123            .metal
124            .create_surface_from_layer(layer as *mut _, cfg!(debug_assertions)),
125    };
126
127    GLOBAL
128        .surfaces
129        .register_identity(PhantomData, surface, &mut Token::root())
130}
131
132#[cfg(windows)]
133#[no_mangle]
134pub extern "C" fn wgpu_create_surface_from_windows_hwnd(
135    _hinstance: *mut std::ffi::c_void,
136    hwnd: *mut std::ffi::c_void,
137) -> id::SurfaceId {
138    use raw_window_handle::windows::WindowsHandle;
139    wgpu_create_surface(raw_window_handle::RawWindowHandle::Windows(
140        raw_window_handle::windows::WindowsHandle {
141            hwnd,
142            ..WindowsHandle::empty()
143        },
144    ))
145}
146
147pub fn wgpu_enumerate_adapters(mask: BackendBit) -> Vec<id::AdapterId> {
148    GLOBAL.enumerate_adapters(core::instance::AdapterInputs::Mask(mask, || PhantomData))
149}
150
151/// # Safety
152///
153/// This function is unsafe as it calls an unsafe extern callback.
154#[no_mangle]
155pub unsafe extern "C" fn wgpu_request_adapter_async(
156    desc: Option<&core::instance::RequestAdapterOptions>,
157    mask: BackendBit,
158    callback: RequestAdapterCallback,
159    userdata: *mut std::ffi::c_void,
160) {
161    let id = GLOBAL.pick_adapter(
162        &desc.cloned().unwrap_or_default(),
163        core::instance::AdapterInputs::Mask(mask, || PhantomData),
164    );
165    callback(id, userdata);
166}
167
168#[no_mangle]
169pub extern "C" fn wgpu_adapter_request_device(
170    adapter_id: id::AdapterId,
171    desc: Option<&DeviceDescriptor>,
172) -> id::DeviceId {
173    let desc = &desc.cloned().unwrap_or_default();
174    gfx_select!(adapter_id => GLOBAL.adapter_request_device(adapter_id, desc, PhantomData))
175}
176
177pub fn adapter_get_info(adapter_id: id::AdapterId) -> core::instance::AdapterInfo {
178    gfx_select!(adapter_id => GLOBAL.adapter_get_info(adapter_id))
179}
180
181#[no_mangle]
182pub extern "C" fn wgpu_adapter_destroy(adapter_id: id::AdapterId) {
183    gfx_select!(adapter_id => GLOBAL.adapter_destroy(adapter_id))
184}
185
186#[no_mangle]
187pub extern "C" fn wgpu_device_get_limits(_device_id: id::DeviceId, limits: &mut Limits) {
188    *limits = Limits::default(); // TODO
189}
190
191#[no_mangle]
192pub extern "C" fn wgpu_device_create_buffer(
193    device_id: id::DeviceId,
194    desc: &wgt::BufferDescriptor,
195) -> id::BufferId {
196    gfx_select!(device_id => GLOBAL.device_create_buffer(device_id, desc, PhantomData))
197}
198
199/// # Safety
200///
201/// This function is unsafe as there is no guarantee that the given pointer
202/// dereferenced in this function is valid.
203#[no_mangle]
204pub unsafe extern "C" fn wgpu_device_create_buffer_mapped(
205    device_id: id::DeviceId,
206    desc: &wgt::BufferDescriptor,
207    mapped_ptr_out: *mut *mut u8,
208) -> id::BufferId {
209    let (id, ptr) =
210        gfx_select!(device_id => GLOBAL.device_create_buffer_mapped(device_id, desc, PhantomData));
211    *mapped_ptr_out = ptr;
212    id
213}
214
215#[no_mangle]
216pub extern "C" fn wgpu_buffer_destroy(buffer_id: id::BufferId) {
217    gfx_select!(buffer_id => GLOBAL.buffer_destroy(buffer_id))
218}
219
220#[no_mangle]
221pub extern "C" fn wgpu_device_create_texture(
222    device_id: id::DeviceId,
223    desc: &wgt::TextureDescriptor,
224) -> id::TextureId {
225    gfx_select!(device_id => GLOBAL.device_create_texture(device_id, desc, PhantomData))
226}
227
228#[no_mangle]
229pub extern "C" fn wgpu_texture_destroy(texture_id: id::TextureId) {
230    gfx_select!(texture_id => GLOBAL.texture_destroy(texture_id))
231}
232
233#[no_mangle]
234pub extern "C" fn wgpu_texture_create_view(
235    texture_id: id::TextureId,
236    desc: Option<&wgt::TextureViewDescriptor>,
237) -> id::TextureViewId {
238    gfx_select!(texture_id => GLOBAL.texture_create_view(texture_id, desc, PhantomData))
239}
240
241#[no_mangle]
242pub extern "C" fn wgpu_texture_view_destroy(texture_view_id: id::TextureViewId) {
243    gfx_select!(texture_view_id => GLOBAL.texture_view_destroy(texture_view_id))
244}
245
246#[no_mangle]
247pub extern "C" fn wgpu_device_create_sampler(
248    device_id: id::DeviceId,
249    desc: &wgt::SamplerDescriptor,
250) -> id::SamplerId {
251    gfx_select!(device_id => GLOBAL.device_create_sampler(device_id, desc, PhantomData))
252}
253
254#[no_mangle]
255pub extern "C" fn wgpu_sampler_destroy(sampler_id: id::SamplerId) {
256    gfx_select!(sampler_id => GLOBAL.sampler_destroy(sampler_id))
257}
258
259#[no_mangle]
260pub extern "C" fn wgpu_device_create_bind_group_layout(
261    device_id: id::DeviceId,
262    desc: &core::binding_model::BindGroupLayoutDescriptor,
263) -> id::BindGroupLayoutId {
264    gfx_select!(device_id => GLOBAL.device_create_bind_group_layout(device_id, desc, PhantomData))
265}
266
267#[no_mangle]
268pub extern "C" fn wgpu_device_create_pipeline_layout(
269    device_id: id::DeviceId,
270    desc: &core::binding_model::PipelineLayoutDescriptor,
271) -> id::PipelineLayoutId {
272    gfx_select!(device_id => GLOBAL.device_create_pipeline_layout(device_id, desc, PhantomData))
273}
274
275#[no_mangle]
276pub extern "C" fn wgpu_device_create_bind_group(
277    device_id: id::DeviceId,
278    desc: &core::binding_model::BindGroupDescriptor,
279) -> id::BindGroupId {
280    gfx_select!(device_id => GLOBAL.device_create_bind_group(device_id, desc, PhantomData))
281}
282
283#[no_mangle]
284pub extern "C" fn wgpu_bind_group_destroy(bind_group_id: id::BindGroupId) {
285    gfx_select!(bind_group_id => GLOBAL.bind_group_destroy(bind_group_id))
286}
287
288#[no_mangle]
289pub extern "C" fn wgpu_device_create_shader_module(
290    device_id: id::DeviceId,
291    desc: &core::pipeline::ShaderModuleDescriptor,
292) -> id::ShaderModuleId {
293    gfx_select!(device_id => GLOBAL.device_create_shader_module(device_id, desc, PhantomData))
294}
295
296#[no_mangle]
297pub extern "C" fn wgpu_device_create_command_encoder(
298    device_id: id::DeviceId,
299    desc: Option<&wgt::CommandEncoderDescriptor>,
300) -> id::CommandEncoderId {
301    let desc = &desc.cloned().unwrap_or_default();
302    gfx_select!(device_id => GLOBAL.device_create_command_encoder(device_id, desc, PhantomData))
303}
304
305#[no_mangle]
306pub extern "C" fn wgpu_command_encoder_destroy(command_encoder_id: id::CommandEncoderId) {
307    gfx_select!(command_encoder_id => GLOBAL.command_encoder_destroy(command_encoder_id))
308}
309
310#[no_mangle]
311pub extern "C" fn wgpu_command_buffer_destroy(command_buffer_id: id::CommandBufferId) {
312    gfx_select!(command_buffer_id => GLOBAL.command_buffer_destroy(command_buffer_id))
313}
314
315#[no_mangle]
316pub extern "C" fn wgpu_device_get_default_queue(device_id: id::DeviceId) -> id::QueueId {
317    device_id
318}
319
320/// # Safety
321///
322/// This function is unsafe as there is no guarantee that the given pointer is
323/// valid for `command_buffers_length` elements.
324#[no_mangle]
325pub unsafe extern "C" fn wgpu_queue_submit(
326    queue_id: id::QueueId,
327    command_buffers: *const id::CommandBufferId,
328    command_buffers_length: usize,
329) {
330    let command_buffer_ids = slice::from_raw_parts(command_buffers, command_buffers_length);
331    gfx_select!(queue_id => GLOBAL.queue_submit(queue_id, command_buffer_ids))
332}
333
334#[no_mangle]
335pub extern "C" fn wgpu_device_create_render_pipeline(
336    device_id: id::DeviceId,
337    desc: &core::pipeline::RenderPipelineDescriptor,
338) -> id::RenderPipelineId {
339    gfx_select!(device_id => GLOBAL.device_create_render_pipeline(device_id, desc, PhantomData))
340}
341
342#[no_mangle]
343pub extern "C" fn wgpu_device_create_compute_pipeline(
344    device_id: id::DeviceId,
345    desc: &core::pipeline::ComputePipelineDescriptor,
346) -> id::ComputePipelineId {
347    gfx_select!(device_id => GLOBAL.device_create_compute_pipeline(device_id, desc, PhantomData))
348}
349
350#[no_mangle]
351pub extern "C" fn wgpu_device_create_swap_chain(
352    device_id: id::DeviceId,
353    surface_id: id::SurfaceId,
354    desc: &wgt::SwapChainDescriptor,
355) -> id::SwapChainId {
356    gfx_select!(device_id => GLOBAL.device_create_swap_chain(device_id, surface_id, desc))
357}
358
359#[no_mangle]
360pub extern "C" fn wgpu_device_poll(device_id: id::DeviceId, force_wait: bool) {
361    gfx_select!(device_id => GLOBAL.device_poll(device_id, force_wait))
362}
363
364#[no_mangle]
365pub extern "C" fn wgpu_device_destroy(device_id: id::DeviceId) {
366    gfx_select!(device_id => GLOBAL.device_destroy(device_id))
367}
368
369#[no_mangle]
370pub extern "C" fn wgpu_buffer_map_read_async(
371    buffer_id: id::BufferId,
372    start: wgt::BufferAddress,
373    size: wgt::BufferAddress,
374    callback: core::device::BufferMapReadCallback,
375    userdata: *mut u8,
376) {
377    let operation = core::resource::BufferMapOperation::Read { callback, userdata };
378
379    gfx_select!(buffer_id => GLOBAL.buffer_map_async(buffer_id, wgt::BufferUsage::MAP_READ, start .. start + size, operation))
380}
381
382#[no_mangle]
383pub extern "C" fn wgpu_buffer_map_write_async(
384    buffer_id: id::BufferId,
385    start: wgt::BufferAddress,
386    size: wgt::BufferAddress,
387    callback: core::device::BufferMapWriteCallback,
388    userdata: *mut u8,
389) {
390    let operation = core::resource::BufferMapOperation::Write { callback, userdata };
391
392    gfx_select!(buffer_id => GLOBAL.buffer_map_async(buffer_id, wgt::BufferUsage::MAP_WRITE, start .. start + size, operation))
393}
394
395#[no_mangle]
396pub extern "C" fn wgpu_buffer_unmap(buffer_id: id::BufferId) {
397    gfx_select!(buffer_id => GLOBAL.buffer_unmap(buffer_id))
398}
399
400#[no_mangle]
401pub extern "C" fn wgpu_swap_chain_get_next_texture(
402    swap_chain_id: id::SwapChainId,
403) -> core::swap_chain::SwapChainOutput {
404    gfx_select!(swap_chain_id => GLOBAL.swap_chain_get_next_texture(swap_chain_id, PhantomData))
405        .unwrap_or(core::swap_chain::SwapChainOutput { view_id: None })
406}
407
408#[no_mangle]
409pub extern "C" fn wgpu_swap_chain_present(swap_chain_id: id::SwapChainId) {
410    gfx_select!(swap_chain_id => GLOBAL.swap_chain_present(swap_chain_id))
411}