diff options
Diffstat (limited to 'src/graphics/permanent.rs')
| -rw-r--r-- | src/graphics/permanent.rs | 120 |
1 files changed, 97 insertions, 23 deletions
diff --git a/src/graphics/permanent.rs b/src/graphics/permanent.rs index b39dbdd..6c4e02d 100644 --- a/src/graphics/permanent.rs +++ b/src/graphics/permanent.rs @@ -8,7 +8,7 @@ use vulkanalia::bytecode::Bytecode; use vulkanalia::loader::{ LibloadingLoader, LIBRARY }; use vulkanalia::vk::{ self, HasBuilder, ApplicationInfo, InstanceCreateInfo, - DeviceV1_0, EntryV1_0, InstanceV1_0, + DeviceV1_0, EntryV1_0, InstanceV1_0, InstanceV1_1, ExtDebugUtilsExtensionInstanceCommands, KhrSurfaceExtensionInstanceCommands }; use winit::dpi::LogicalSize; @@ -16,6 +16,7 @@ use winit::event_loop::ActiveEventLoop; use winit::window::{ Window, WindowAttributes }; +const VULKAN_MINIMUM_VERSION: Version = Version::new(1, 4, 0); const VULKAN_FIRST_PORTABILITY_VERSION: Version = Version::new(1, 3, 216); @@ -135,7 +136,8 @@ impl Permanent { = init_vulkan_device(&instance, &surface, enable_validation, enable_portability)?; - let descriptor_set_layout = init_descriptor_set_layout(&device)?; + let (primary_descriptor_set_layout, push_descriptor_set_layout) + = init_descriptor_set_layouts(&device)?; let (primary_command_pool, transient_command_pool) = init_command_pools(&device, &indices)?; @@ -145,7 +147,8 @@ impl Permanent { graphics_queue, presentation_queue, primary_command_pool, transient_command_pool, }, ForReinit { - indices, sample_count, descriptor_set_layout, + indices, sample_count, + primary_descriptor_set_layout, push_descriptor_set_layout, }, enable_anisotropy, enable_swapchain)) } @@ -236,7 +239,8 @@ impl Permanent { pub struct ForReinit { pub indices: QueueFamilyIndices, pub sample_count: vk::SampleCountFlags, - pub descriptor_set_layout: vk::DescriptorSetLayout, + pub primary_descriptor_set_layout: vk::DescriptorSetLayout, + pub push_descriptor_set_layout: vk::DescriptorSetLayout, } @@ -244,7 +248,13 @@ impl ForReinit { #[allow(unsafe_code)] pub fn destroy(self, device: &Device) -> () { unsafe { - device.destroy_descriptor_set_layout(self.descriptor_set_layout, None) + device.destroy_descriptor_set_layout(self.primary_descriptor_set_layout, + None) + }; + + unsafe { + device.destroy_descriptor_set_layout(self.push_descriptor_set_layout, + None) }; } } @@ -366,12 +376,28 @@ fn init_vulkan(window: &Window) this may mean other messages don't show up."); } + // The api_version field here is the version of Vulkan we actually get. + // The official documentation is a bit misleading, since it says "maximum", + // but on close reading what it means is that we guarantee that we as the + // application will not require anything newer than that. So from our + // perspective it is the MINIMUM we will accept. + // + // We define a constant for it to make it easy to find, since it's far + // more important operationally than any of the other versions declared + // here. + // + // The validation layer enforces this API version on us, interposing + // itself when we attempt to load functions. Vulkanalia will panic!() on us + // when loading fails, with a message in the form "could not load + // vkWhateverWhatever", which can be quite confusing, so this comment text + // is here to make that easy to diagnose. If you got here for that reason, + // give thanks to the Waiting and its foresight. let application_info = ApplicationInfo::builder() .application_name(b"Surreality\0") .application_version(vk::make_version(1, 0, 0)) .engine_name(b"Surreality\0") .engine_version(vk::make_version(1, 0, 0)) - .api_version(vk::make_version(1, 0, 0)); + .api_version(u32::from(VULKAN_MINIMUM_VERSION)); // Deceptively, this DOES get mutated later, but Vulkanalia doesn't see // it that way. @@ -454,9 +480,24 @@ fn init_vulkan_device(instance: &Instance, surface: &vk::SurfaceKHR, // Old versions of Vulkan want layers to be enabled at the device // level as well. Newer ones will ignore this and just use the instance // layers. - let available_features = unsafe { - instance.get_physical_device_features(physical_device) + // + // Dealing with this struct chain is kind of risky lifetime-wise, because + // Vulkanalia unsafely discards the reference for our "convenience". Alas. + let mut available_features_14 + = vk::PhysicalDeviceVulkan14Features::default(); + let mut available_features = vk::PhysicalDeviceFeatures2::builder() + .push_next(&mut available_features_14); + unsafe { + instance.get_physical_device_features2(physical_device, + &mut available_features) }; + + // Another struct chain with a risky lifetime. Vulkanalia's mutation + // features return a copy, so we have to avoid mutating features_14 once we + // add it to the chain. Fortunately we only need it for one thing right now, + // so we do that here at the top and treat it as non-mutable. + let mut features_14 = vk::PhysicalDeviceVulkan14Features::builder() + .push_descriptor(true); let mut features = vk::PhysicalDeviceFeatures::builder(); let mut extensions = Vec::new(); let mut layers = Vec::new(); @@ -506,7 +547,7 @@ fn init_vulkan_device(instance: &Instance, surface: &vk::SurfaceKHR, EnableSwapchain(false) }; - let enable_anisotropy = if available_features.sampler_anisotropy + let enable_anisotropy = if available_features.features.sampler_anisotropy == vk::TRUE { features = features.sampler_anisotropy(true); @@ -535,11 +576,14 @@ fn init_vulkan_device(instance: &Instance, surface: &vk::SurfaceKHR, .queue_priorities(&[1.0])); } + let mut features2 = vk::PhysicalDeviceFeatures2::builder() + .features(features); let device_info = vk::DeviceCreateInfo::builder() .queue_create_infos(&queues) .enabled_layer_names(&layers) .enabled_extension_names(&extensions) - .enabled_features(&features); + .push_next(&mut features2) + .push_next(&mut features_14); let device = unsafe { instance.create_device(physical_device, &device_info, None) @@ -564,8 +608,8 @@ fn init_vulkan_device(instance: &Instance, surface: &vk::SurfaceKHR, #[allow(unsafe_code)] -fn init_descriptor_set_layout(device: &Device) - -> Result<vk::DescriptorSetLayout> +fn init_descriptor_set_layouts(device: &Device) + -> Result<(vk::DescriptorSetLayout, vk::DescriptorSetLayout)> { let uniform_block_binding = vk::DescriptorSetLayoutBinding::builder() .binding(0) @@ -579,21 +623,32 @@ fn init_descriptor_set_layout(device: &Device) .descriptor_count(1) .stage_flags(vk::ShaderStageFlags::FRAGMENT); + let primary_bindings = [uniform_block_binding, sampler_binding]; + let primary_descriptor_set_layout_info + = vk::DescriptorSetLayoutCreateInfo::builder() + .bindings(&primary_bindings); + let primary_descriptor_set_layout = unsafe { + device.create_descriptor_set_layout(&primary_descriptor_set_layout_info, + None) + }?; + let texture_binding = vk::DescriptorSetLayoutBinding::builder() - .binding(2) + .binding(0) .descriptor_type(vk::DescriptorType::SAMPLED_IMAGE) .descriptor_count(1) .stage_flags(vk::ShaderStageFlags::FRAGMENT); - let bindings = [uniform_block_binding, sampler_binding, texture_binding]; - let descriptor_set_layout_info + let push_bindings = [texture_binding]; + let push_descriptor_set_layout_info = vk::DescriptorSetLayoutCreateInfo::builder() - .bindings(&bindings); - let descriptor_set_layout = unsafe { - device.create_descriptor_set_layout(&descriptor_set_layout_info, None) + .bindings(&push_bindings) + .flags(vk::DescriptorSetLayoutCreateFlags::PUSH_DESCRIPTOR); + let push_descriptor_set_layout = unsafe { + device.create_descriptor_set_layout(&push_descriptor_set_layout_info, + None) }?; - Ok(descriptor_set_layout) + Ok((primary_descriptor_set_layout, push_descriptor_set_layout)) } @@ -770,10 +825,15 @@ fn score_vulkan_device(instance: &Instance, surface: &vk::SurfaceKHR, // selected. } - let features = unsafe { - instance.get_physical_device_features(*physical_device) + let mut features_14 + = vk::PhysicalDeviceVulkan14Features::default(); + let mut features = vk::PhysicalDeviceFeatures2::builder() + .push_next(&mut features_14); + unsafe { + instance.get_physical_device_features2(*physical_device, &mut features) }; - if features.sampler_anisotropy == vk::TRUE { + + if features.features.sampler_anisotropy == vk::TRUE { score += 1; } @@ -786,7 +846,17 @@ fn score_vulkan_device(instance: &Instance, surface: &vk::SurfaceKHR, score += shift; let sample_count = vk::SampleCountFlags::from_bits(1 << shift).unwrap(); - Ok(Acceptable::Accepted((score, indices, sample_count))) + // We prefer to report the most important reason, rather than + // less-fundamental ones. To make that easy, we try to keep this logic + // together at the end. Note that, before we get here, we may have already + // rejected the device thanks to find_device_queue_family_indices(), called + // above, but that's okay because all those reasons are in fact more + // important than the ones tested here. + if features_14.push_descriptor != vk::TRUE { + Ok(Acceptable::Rejected("Doesn't support push descriptors.".to_string())) + } else { + Ok(Acceptable::Accepted((score, indices, sample_count))) + } } @@ -819,6 +889,9 @@ fn find_device_queue_family_indices(instance: &Instance, } } + // We prefer to report the most important reason, rather than + // less-fundamental ones. To make that easy, we keep all this logic together + // at the end. if let Some(graphics) = graphics { if let Some(presentation) = presentation { Ok(Acceptable::Accepted(QueueFamilyIndices { @@ -885,3 +958,4 @@ extern "system" fn debug_messager_callback( // test so anything it does is fine with us. vk::FALSE } + |