skia_safe/gpu/vk/
vulkan_backend_context.rs1use std::{
2 cell::RefCell,
3 ffi::{self, CString},
4 fmt, mem,
5 ops::Deref,
6 os::raw::{self, c_char},
7 ptr,
8};
9
10use super::{Device, GetProc, GetProcOf, Instance, PhysicalDevice, Queue, Version};
11use crate::gpu;
12use skia_bindings as sb;
13
14pub struct BackendContext<'a> {
17 pub(crate) native: ptr::NonNull<ffi::c_void>,
18 get_proc: &'a dyn GetProc,
19}
20
21impl Drop for BackendContext<'_> {
22 fn drop(&mut self) {
23 unsafe { sb::C_VulkanBackendContext_delete(self.native.as_ptr()) }
24 }
25}
26
27impl fmt::Debug for BackendContext<'_> {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 f.debug_struct("BackendContext")
30 .field("native", &self.native)
31 .finish()
32 }
33}
34
35impl BackendContext<'_> {
40 pub unsafe fn new(
44 instance: Instance,
45 physical_device: PhysicalDevice,
46 device: Device,
47 (queue, queue_index): (Queue, usize),
48 get_proc: &impl GetProc,
49 ) -> BackendContext {
50 Self::new_with_extensions(
51 instance,
52 physical_device,
53 device,
54 (queue, queue_index),
55 get_proc,
56 &[],
57 &[],
58 )
59 }
60
61 pub unsafe fn new_with_extensions<'a>(
65 instance: Instance,
66 physical_device: PhysicalDevice,
67 device: Device,
68 (queue, queue_index): (Queue, usize),
69 get_proc: &'a impl GetProc,
70 instance_extensions: &[&str],
71 device_extensions: &[&str],
72 ) -> BackendContext<'a> {
73 let instance_extensions: Vec<CString> = instance_extensions
76 .iter()
77 .map(|str| CString::new(*str).unwrap())
78 .collect();
79 let instance_extensions: Vec<*const c_char> =
80 instance_extensions.iter().map(|cs| cs.as_ptr()).collect();
81 let device_extensions: Vec<CString> = device_extensions
82 .iter()
83 .map(|str| CString::new(*str).unwrap())
84 .collect();
85 let device_extensions: Vec<*const c_char> =
86 device_extensions.iter().map(|cs| cs.as_ptr()).collect();
87
88 let resolver = Self::begin_resolving_proc(get_proc);
89 let native = sb::C_VulkanBackendContext_new(
90 instance as _,
91 physical_device as _,
92 device as _,
93 queue as _,
94 queue_index.try_into().unwrap(),
95 Some(global_get_proc),
96 instance_extensions.as_ptr(),
97 instance_extensions.len(),
98 device_extensions.as_ptr(),
99 device_extensions.len(),
100 );
101 drop(resolver);
102 BackendContext {
103 native: ptr::NonNull::new(native).unwrap(),
104 get_proc,
105 }
106 }
107
108 pub fn set_protected_context(&mut self, protected_context: gpu::Protected) -> &mut Self {
109 unsafe {
110 sb::C_VulkanBackendContext_setProtectedContext(
111 self.native.as_ptr() as _,
112 protected_context,
113 )
114 }
115 self
116 }
117
118 pub fn set_max_api_version(&mut self, version: impl Into<Version>) -> &mut Self {
119 unsafe {
120 sb::C_VulkanBackendContext_setMaxAPIVersion(
121 self.native.as_ptr() as _,
122 *version.into().deref(),
123 )
124 }
125 self
126 }
127
128 pub(crate) unsafe fn begin_resolving(&self) -> impl Drop {
129 Self::begin_resolving_proc(self.get_proc)
130 }
131
132 unsafe fn begin_resolving_proc(get_proc_trait_object: &dyn GetProc) -> impl Drop {
140 THREAD_LOCAL_GET_PROC.with(|get_proc| {
141 *get_proc.borrow_mut() = Some(mem::transmute::<&dyn GetProc, TraitObject>(
142 get_proc_trait_object,
143 ))
144 });
145
146 EndResolving {}
147 }
148}
149
150struct EndResolving {}
151
152impl Drop for EndResolving {
153 fn drop(&mut self) {
154 THREAD_LOCAL_GET_PROC.with(|get_proc| *get_proc.borrow_mut() = None)
155 }
156}
157
158thread_local! {
159 static THREAD_LOCAL_GET_PROC: RefCell<Option<TraitObject>> = const { RefCell::new(None) };
160}
161
162#[repr(C)]
164#[derive(Copy, Clone)]
167struct TraitObject {
168 pub data: *mut (),
169 pub vtable: *mut (),
170}
171
172unsafe extern "C" fn global_get_proc(
174 name: *const raw::c_char,
175 instance: Instance,
176 device: Device,
177) -> *const raw::c_void {
178 THREAD_LOCAL_GET_PROC.with(|get_proc| {
179 match *get_proc.borrow() {
180 Some(get_proc) => {
181 let get_proc_trait_object: &dyn GetProc = mem::transmute(get_proc);
182 if !device.is_null() {
183 get_proc_trait_object(GetProcOf::Device(device, name))
184 } else {
185 get_proc_trait_object(GetProcOf::Instance(instance, name))
187 }
188 }
189 None => panic!("Vulkan GetProc called outside of a thread local resolvement context."),
190 }
191 })
192}