Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_render/src/renderer/raw_vulkan_init.rs
6596 views
1
use alloc::sync::Arc;
2
use bevy_ecs::resource::Resource;
3
use bevy_platform::collections::HashSet;
4
use core::any::{Any, TypeId};
5
use thiserror::Error;
6
use wgpu::{
7
hal::api::Vulkan, Adapter, Device, DeviceDescriptor, Instance, InstanceDescriptor, Queue,
8
};
9
10
/// When the `raw_vulkan_init` feature is enabled, these settings will be used to configure the raw vulkan instance.
11
#[derive(Resource, Default, Clone)]
12
pub struct RawVulkanInitSettings {
13
// SAFETY: this must remain private to ensure that registering callbacks is unsafe
14
create_instance_callbacks: Vec<
15
Arc<
16
dyn Fn(
17
&mut wgpu::hal::vulkan::CreateInstanceCallbackArgs,
18
&mut AdditionalVulkanFeatures,
19
) + Send
20
+ Sync,
21
>,
22
>,
23
// SAFETY: this must remain private to ensure that registering callbacks is unsafe
24
create_device_callbacks: Vec<
25
Arc<
26
dyn Fn(
27
&mut wgpu::hal::vulkan::CreateDeviceCallbackArgs,
28
&wgpu::hal::vulkan::Adapter,
29
&mut AdditionalVulkanFeatures,
30
) + Send
31
+ Sync,
32
>,
33
>,
34
}
35
36
impl RawVulkanInitSettings {
37
/// Adds a new Vulkan create instance callback. See [`wgpu::hal::vulkan::Instance::init_with_callback`] for details.
38
///
39
/// # Safety
40
/// - Callback must not remove features.
41
/// - Callback must not change anything to what the instance does not support.
42
pub unsafe fn add_create_instance_callback(
43
&mut self,
44
callback: impl Fn(&mut wgpu::hal::vulkan::CreateInstanceCallbackArgs, &mut AdditionalVulkanFeatures)
45
+ Send
46
+ Sync
47
+ 'static,
48
) {
49
self.create_instance_callbacks.push(Arc::new(callback));
50
}
51
52
/// Adds a new Vulkan create device callback. See [`wgpu::hal::vulkan::Adapter::open_with_callback`] for details.
53
///
54
/// # Safety
55
/// - Callback must not remove features.
56
/// - Callback must not change anything to what the device does not support.
57
pub unsafe fn add_create_device_callback(
58
&mut self,
59
callback: impl Fn(
60
&mut wgpu::hal::vulkan::CreateDeviceCallbackArgs,
61
&wgpu::hal::vulkan::Adapter,
62
&mut AdditionalVulkanFeatures,
63
) + Send
64
+ Sync
65
+ 'static,
66
) {
67
self.create_device_callbacks.push(Arc::new(callback));
68
}
69
}
70
71
pub(crate) fn create_raw_vulkan_instance(
72
instance_descriptor: &InstanceDescriptor,
73
settings: &RawVulkanInitSettings,
74
additional_features: &mut AdditionalVulkanFeatures,
75
) -> Instance {
76
// SAFETY: Registering callbacks is unsafe. Callback authors promise not to remove features
77
// or change the instance to something it does not support
78
unsafe {
79
wgpu::hal::vulkan::Instance::init_with_callback(
80
&wgpu::hal::InstanceDescriptor {
81
name: "wgpu",
82
flags: instance_descriptor.flags,
83
memory_budget_thresholds: instance_descriptor.memory_budget_thresholds,
84
backend_options: instance_descriptor.backend_options.clone(),
85
},
86
Some(Box::new(|mut args| {
87
for callback in &settings.create_instance_callbacks {
88
(callback)(&mut args, additional_features);
89
}
90
})),
91
)
92
.map(|raw_instance| Instance::from_hal::<Vulkan>(raw_instance))
93
.unwrap_or_else(|_| Instance::new(instance_descriptor))
94
}
95
}
96
97
pub(crate) async fn create_raw_device(
98
adapter: &Adapter,
99
device_descriptor: &DeviceDescriptor<'_>,
100
settings: &RawVulkanInitSettings,
101
additional_features: &mut AdditionalVulkanFeatures,
102
) -> Result<(Device, Queue), CreateRawVulkanDeviceError> {
103
// SAFETY: Registering callbacks is unsafe. Callback authors promise not to remove features
104
// or change the adapter to something it does not support
105
unsafe {
106
let Some(raw_adapter) = adapter.as_hal::<Vulkan>() else {
107
return Ok(adapter.request_device(device_descriptor).await?);
108
};
109
let open_device = raw_adapter.open_with_callback(
110
device_descriptor.required_features,
111
&device_descriptor.memory_hints,
112
Some(Box::new(|mut args| {
113
for callback in &settings.create_device_callbacks {
114
(callback)(&mut args, &raw_adapter, additional_features);
115
}
116
})),
117
)?;
118
119
Ok(adapter.create_device_from_hal::<Vulkan>(open_device, device_descriptor)?)
120
}
121
}
122
123
#[derive(Error, Debug)]
124
pub(crate) enum CreateRawVulkanDeviceError {
125
#[error(transparent)]
126
RequestDeviceError(#[from] wgpu::RequestDeviceError),
127
#[error(transparent)]
128
DeviceError(#[from] wgpu::hal::DeviceError),
129
}
130
131
/// A list of additional Vulkan features that are supported by the current wgpu instance / adapter. This is populated
132
/// by callbacks defined in [`RawVulkanInitSettings`]
133
#[derive(Resource, Default, Clone)]
134
pub struct AdditionalVulkanFeatures(HashSet<TypeId>);
135
136
impl AdditionalVulkanFeatures {
137
pub fn insert<T: Any>(&mut self) {
138
self.0.insert(TypeId::of::<T>());
139
}
140
141
pub fn has<T: Any>(&self) -> bool {
142
self.0.contains(&TypeId::of::<T>())
143
}
144
145
pub fn remove<T: Any>(&mut self) {
146
self.0.remove(&TypeId::of::<T>());
147
}
148
}
149
150