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