Skip to main content

skia_safe/gpu/vk/
vulkan_backend_context_builder.rs

1use super::{
2    Device, GetProc, Instance, PhysicalDevice, Queue, Version,
3    vulkan_backend_context::BackendContext,
4};
5use crate::gpu;
6
7/// Builds a Vulkan [`BackendContext`] with optional extensions and protected mode.
8pub struct BackendContextBuilder<'a> {
9    instance: Instance,
10    physical_device: PhysicalDevice,
11    device: Device,
12    queue: Queue,
13    queue_index: usize,
14    get_proc: &'a dyn GetProc,
15    max_api_version: Option<Version>,
16    instance_extensions: Vec<String>,
17    device_extensions: Vec<String>,
18    protected_context: Option<gpu::Protected>,
19}
20
21impl std::fmt::Debug for BackendContextBuilder<'_> {
22    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        f.debug_struct("BackendContextBuilder")
24            .field("instance", &self.instance)
25            .field("physical_device", &self.physical_device)
26            .field("device", &self.device)
27            .field("queue", &self.queue)
28            .field("queue_index", &self.queue_index)
29            .field("get_proc", &"<dyn GetProc>")
30            .field("max_api_version", &self.max_api_version)
31            .field("instance_extensions", &self.instance_extensions)
32            .field("device_extensions", &self.device_extensions)
33            .field("protected_context", &self.protected_context)
34            .finish()
35    }
36}
37
38impl<'a> BackendContextBuilder<'a> {
39    /// Creates a new builder for a Vulkan backend context.
40    ///
41    /// The `max_api_version` is applied during native context creation, before
42    /// the Vulkan memory allocator is initialized.
43    ///
44    /// If a version is provided, it should match the value provided in
45    /// `VkApplicationInfo::apiVersion` when creating the `VkInstance`. Pass `None` to leave Skia's
46    /// `VulkanBackendContext::fMaxAPIVersion` at its default `0`; Skia then queries
47    /// `vkEnumerateInstanceVersion()` and uses that loader-reported version as the upper limit when
48    /// validating Vulkan entry points and creating the memory allocator.
49    ///
50    /// Skia requires Vulkan 1.1 as the minimum supported API version.
51    pub fn new(
52        instance: Instance,
53        physical_device: PhysicalDevice,
54        device: Device,
55        (queue, queue_index): (Queue, usize),
56        get_proc: &'a impl GetProc,
57        max_api_version: impl Into<Option<Version>>,
58    ) -> Self {
59        Self {
60            instance,
61            physical_device,
62            device,
63            queue,
64            queue_index,
65            get_proc,
66            max_api_version: max_api_version.into(),
67            instance_extensions: Vec::new(),
68            device_extensions: Vec::new(),
69            protected_context: None,
70        }
71    }
72
73    /// Sets the Vulkan instance and device extension names expected by Skia.
74    ///
75    /// The provided names are copied into the builder.
76    pub fn with_extensions(
77        mut self,
78        instance_extensions: &[&str],
79        device_extensions: &[&str],
80    ) -> Self {
81        self.instance_extensions = instance_extensions
82            .iter()
83            .map(|s| (*s).to_owned())
84            .collect();
85        self.device_extensions = device_extensions.iter().map(|s| (*s).to_owned()).collect();
86        self
87    }
88
89    /// Configures whether the context should operate in protected mode.
90    pub fn with_protected_context(mut self, protected_context: gpu::Protected) -> Self {
91        self.protected_context = Some(protected_context);
92        self
93    }
94
95    /// Creates the Vulkan [`BackendContext`] from the configured builder state.
96    ///
97    /// If [`Self::with_protected_context()`] is not called, protected mode defaults to
98    /// [`gpu::Protected::No`].
99    /// # Safety
100    /// `instance`, `physical_device`, `device`, and `queue` must outlive the `BackendContext`
101    /// returned.
102    pub unsafe fn build(self) -> BackendContext<'a> {
103        let instance_extensions: Vec<&str> = self
104            .instance_extensions
105            .iter()
106            .map(String::as_str)
107            .collect();
108        let device_extensions: Vec<&str> =
109            self.device_extensions.iter().map(String::as_str).collect();
110
111        unsafe {
112            BackendContext::new_internal(
113                self.instance,
114                self.physical_device,
115                self.device,
116                (self.queue, self.queue_index),
117                self.get_proc,
118                self.max_api_version,
119                self.protected_context.unwrap_or(gpu::Protected::No),
120                &instance_extensions,
121                &device_extensions,
122            )
123        }
124    }
125}