use std::sync::Arc;
use timeline_syncobj::render_node::DrmRenderNode;
use vulkano::{
Validated, Version, VulkanError, VulkanLibrary,
command_buffer::allocator::{
StandardCommandBufferAllocator, StandardCommandBufferAllocatorCreateInfo,
},
descriptor_set::allocator::{
StandardDescriptorSetAllocator, StandardDescriptorSetAllocatorCreateInfo,
},
device::{
Device, DeviceCreateInfo, DeviceExtensions, DeviceFeatures, Queue, QueueCreateFlags,
QueueCreateInfo, QueueFlags,
physical::{PhysicalDevice, PhysicalDeviceType},
},
instance::{Instance, InstanceCreateInfo, InstanceExtensions},
memory::allocator::StandardMemoryAllocator,
};
use crate::queue::StarlightQueue;
pub mod command_buffer;
pub mod dmatex;
pub mod images;
pub mod materials;
pub mod mesh_manager;
pub mod object_manager;
pub mod pipeline_pieces;
pub mod queue;
pub mod render;
pub mod resource_manager;
pub mod resources;
pub mod subpasses;
pub mod vulkano_exts;
pub struct Context {
pub instance: Arc<Instance>,
pub phys_dev: Arc<PhysicalDevice>,
pub device: Arc<Device>,
pub alloc: Arc<StandardMemoryAllocator>,
pub cmd_buf_alloc: Arc<StandardCommandBufferAllocator>,
pub descriptor_set_alloc: Arc<StandardDescriptorSetAllocator>,
pub gfx_queue: StarlightQueue,
pub transfer_queue: Option<StarlightQueue>,
pub drm_render_node: DrmRenderNode,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ApplicationInfo {
pub name: Option<String>,
pub version: Version,
}
impl Context {
pub fn new(
entry: &Arc<VulkanLibrary>,
app_info: ApplicationInfo,
additional_instance_exts: InstanceExtensions,
additional_device_exts: DeviceExtensions,
additional_device_features: DeviceFeatures,
) -> Self {
Self::new_custom_init(
entry,
app_info,
additional_instance_exts,
additional_device_exts,
additional_device_features,
|info| Instance::new(entry.clone(), info),
|instance, required_device_extensions, required_device_features| {
let mut devs = instance
.enumerate_physical_devices()
.unwrap()
.collect::<Vec<_>>();
devs.sort_by_key(|dev| match dev.properties().device_type {
PhysicalDeviceType::DiscreteGpu => 0,
PhysicalDeviceType::IntegratedGpu => 1,
PhysicalDeviceType::VirtualGpu => 2,
PhysicalDeviceType::Cpu => 3,
PhysicalDeviceType::Other => 4,
_ => 5,
});
let phys_dev = devs
.into_iter()
.find(|dev| {
dbg!(required_device_extensions.difference(dev.supported_extensions()));
dbg!(required_device_features.difference(dev.supported_features()));
dev.supported_extensions()
.contains(&required_device_extensions)
&& dev.supported_features().contains(&required_device_features)
})
.expect("no suitable device found");
Ok(phys_dev)
},
|phys_dev, info| Device::new(phys_dev.clone(), info),
)
}
pub fn new_custom_init<I: ExactSizeIterator<Item = Arc<Queue>>>(
entry: &Arc<VulkanLibrary>,
app_info: ApplicationInfo,
additional_instance_exts: InstanceExtensions,
additional_device_exts: DeviceExtensions,
additional_device_features: DeviceFeatures,
instance_create: impl FnOnce(
InstanceCreateInfo,
) -> Result<Arc<Instance>, Validated<VulkanError>>,
select_phys_dev: impl FnOnce(
&Arc<Instance>,
&DeviceExtensions,
&DeviceFeatures,
) -> Result<Arc<PhysicalDevice>, Validated<VulkanError>>,
device_create: impl FnOnce(
&Arc<PhysicalDevice>,
DeviceCreateInfo,
) -> Result<(Arc<Device>, I), Validated<VulkanError>>,
) -> Self {
let required_exts = InstanceExtensions {
khr_external_memory_capabilities: true,
khr_external_semaphore_capabilities: true,
khr_get_physical_device_properties2: true,
ext_debug_utils: true,
..Default::default()
} | additional_instance_exts;
let supported_exts = entry.supported_extensions();
if !supported_exts.contains(&required_exts) {
panic!("required exts are not supported: {:#?}", supported_exts);
}
let instance = instance_create(InstanceCreateInfo {
application_name: app_info.name,
application_version: app_info.version,
engine_name: Some("Starlight Renderer".into()),
engine_version: Version {
major: 0,
minor: 1,
patch: 0,
},
max_api_version: Some(Version::V1_3),
enabled_extensions: required_exts,
..Default::default()
})
.unwrap();
let required_device_extensions = DeviceExtensions {
ext_image_drm_format_modifier: true,
khr_dynamic_rendering_local_read: true,
ext_ycbcr_image_arrays: true,
khr_external_memory: true,
khr_external_memory_fd: true,
khr_external_semaphore: true,
khr_external_semaphore_fd: true,
khr_push_descriptor: true,
..Default::default()
} | additional_device_exts;
let required_device_features = DeviceFeatures {
timeline_semaphore: true,
multi_draw_indirect: true,
draw_indirect_count: true,
descriptor_indexing: true,
runtime_descriptor_array: true,
descriptor_binding_partially_bound: true,
descriptor_binding_sampled_image_update_after_bind: true,
shader_sampled_image_array_non_uniform_indexing: true,
shader_input_attachment_array_dynamic_indexing: true,
shader_input_attachment_array_non_uniform_indexing: true,
image_cube_array: true,
dynamic_rendering: true,
dynamic_rendering_local_read: true,
synchronization2: true,
buffer_device_address: true,
multiview: true,
scalar_block_layout: true,
shader_int64: true,
shader_int8: true,
shader_draw_parameters: true,
storage_buffer8_bit_access: true,
independent_blend: true,
..Default::default()
} | additional_device_features;
let phys_dev = select_phys_dev(
&instance,
&required_device_extensions,
&required_device_features,
)
.expect("failed to select phys dev");
let info = phys_dev.queue_family_properties();
let mut graphics_queue_family_index = None;
let mut transfer_queue_family_index = None;
for (i, info) in info.into_iter().enumerate() {
if graphics_queue_family_index.is_none()
&& info.queue_flags.contains(QueueFlags::GRAPHICS)
{
graphics_queue_family_index.replace(i);
}
if transfer_queue_family_index.is_none()
&& info.queue_flags.contains(QueueFlags::TRANSFER)
&& !info.queue_flags.contains(QueueFlags::GRAPHICS)
{
transfer_queue_family_index.replace(i);
}
}
let gfx_queue_family = graphics_queue_family_index.expect("no graphics queue") as u32;
let mut queue_create_infos = vec![QueueCreateInfo {
flags: QueueCreateFlags::empty(),
queue_family_index: gfx_queue_family,
queues: vec![1.0],
..Default::default()
}];
if let Some(transfer_queue_family) = transfer_queue_family_index {
queue_create_infos.push(QueueCreateInfo {
flags: QueueCreateFlags::empty(),
queue_family_index: transfer_queue_family as u32,
queues: vec![1.0],
..Default::default()
});
}
let device_create_info = DeviceCreateInfo {
queue_create_infos,
enabled_extensions: required_device_extensions,
enabled_features: required_device_features,
..Default::default()
};
let (device, mut queues) = device_create(&phys_dev, device_create_info).unwrap();
let gfx_queue = queues.next().unwrap();
let transfer_queue = transfer_queue_family_index
.is_some()
.then(|| queues.next().unwrap());
let render_minor = phys_dev.properties().render_minor.unwrap();
let drm_render_node = DrmRenderNode::new(render_minor.cast_unsigned()).unwrap();
let gfx_queue = StarlightQueue::new(gfx_queue, drm_render_node.clone());
gfx_queue
.set_debug_label(Some("Main Graphics Queue"))
.unwrap();
let transfer_queue =
transfer_queue.map(|q| StarlightQueue::new(q, drm_render_node.clone()));
if let Some(q) = transfer_queue.as_ref() {
q.set_debug_label(Some("Transfer Queue")).unwrap();
}
Self {
alloc: Arc::new(StandardMemoryAllocator::new_default(device.clone())),
cmd_buf_alloc: Arc::new(StandardCommandBufferAllocator::new(
device.clone(),
StandardCommandBufferAllocatorCreateInfo::default(),
)),
descriptor_set_alloc: Arc::new(StandardDescriptorSetAllocator::new(
device.clone(),
StandardDescriptorSetAllocatorCreateInfo {
update_after_bind: true,
..Default::default()
},
)),
instance,
phys_dev,
device,
gfx_queue,
drm_render_node,
transfer_queue,
}
}
}