From f22873a99085d1e9c4dedba59273b688272749ff Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 25 Mar 2026 23:43:41 +0000 Subject: [PATCH] Enable VK_KHR_unified_image_layouts when supported Blade already uses VK_IMAGE_LAYOUT_GENERAL everywhere, but without this extension the driver isn't told that GENERAL is intentional and optimal. Enabling it lets the driver skip any internal layout optimization heuristics. Uses raw Vulkan structs since ash 0.38 predates the extension. Marked with TODO comments for cleanup once ash catches up. https://claude.ai/code/session_01W9jSvpnbXEXmoHFuUVFdUN --- blade-graphics/src/vulkan/init.rs | 55 ++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/blade-graphics/src/vulkan/init.rs b/blade-graphics/src/vulkan/init.rs index 3f20da24..6dff3517 100644 --- a/blade-graphics/src/vulkan/init.rs +++ b/blade-graphics/src/vulkan/init.rs @@ -5,6 +5,39 @@ use std::{ffi, sync::Mutex}; use crate::NotSupportedError; +// TODO: Remove once `ash` includes VK_KHR_unified_image_layouts bindings. +// See https://registry.khronos.org/vulkan/specs/latest/man/html/VK_KHR_unified_image_layouts.html +mod unified_image_layouts { + use ash::vk; + use std::ffi; + + pub const NAME: &ffi::CStr = c"VK_KHR_unified_image_layouts"; + const STRUCTURE_TYPE: i32 = 1000466000; + + #[repr(C)] + pub struct PhysicalDeviceFeatures { + pub s_type: vk::StructureType, + pub p_next: *mut ffi::c_void, + pub unified_image_layouts: vk::Bool32, + pub unified_image_layouts_video: vk::Bool32, + } + impl Default for PhysicalDeviceFeatures { + fn default() -> Self { + Self { + s_type: vk::StructureType::from_raw(STRUCTURE_TYPE), + p_next: std::ptr::null_mut(), + unified_image_layouts: vk::FALSE, + unified_image_layouts_video: vk::FALSE, + } + } + } + unsafe impl vk::TaggedStructure for PhysicalDeviceFeatures { + const STRUCTURE_TYPE: vk::StructureType = vk::StructureType::from_raw(STRUCTURE_TYPE); + } + unsafe impl vk::ExtendsPhysicalDeviceFeatures2 for PhysicalDeviceFeatures {} + unsafe impl vk::ExtendsDeviceCreateInfo for PhysicalDeviceFeatures {} +} + mod db { pub mod intel { pub const VENDOR: u32 = 0x8086; @@ -73,6 +106,7 @@ struct AdapterCapabilities { dual_source_blending: bool, shader_float16: bool, cooperative_matrix: crate::CooperativeMatrix, + unified_image_layouts: bool, memory_budget: bool, bugs: SystemBugs, } @@ -263,6 +297,8 @@ fn inspect_adapter( let mut vulkan_memory_model_features = vk::PhysicalDeviceVulkanMemoryModelFeatures::default(); let mut float16_int8_features = vk::PhysicalDeviceShaderFloat16Int8Features::default(); let mut storage_16bit_features = vk::PhysicalDevice16BitStorageFeatures::default(); + let mut unified_image_layouts_features = + unified_image_layouts::PhysicalDeviceFeatures::default(); let mut features2_khr = vk::PhysicalDeviceFeatures2::default() .push_next(&mut inline_uniform_block_features) .push_next(&mut timeline_semaphore_features) @@ -274,7 +310,8 @@ fn inspect_adapter( .push_next(&mut cooperative_matrix_features) .push_next(&mut vulkan_memory_model_features) .push_next(&mut float16_int8_features) - .push_next(&mut storage_16bit_features); + .push_next(&mut storage_16bit_features) + .push_next(&mut unified_image_layouts_features); unsafe { instance .get_physical_device_properties2 @@ -499,6 +536,8 @@ fn inspect_adapter( dual_source_blending, shader_float16, cooperative_matrix, + unified_image_layouts: supported_extensions.contains(&unified_image_layouts::NAME) + && unified_image_layouts_features.unified_image_layouts == vk::TRUE, memory_budget, bugs, }) @@ -808,6 +847,10 @@ impl super::Context { if capabilities.memory_budget { device_extensions.push(vk::EXT_MEMORY_BUDGET_NAME); } + if capabilities.unified_image_layouts { + // TODO: Replace with ash constant once available. + device_extensions.push(unified_image_layouts::NAME); + } let str_pointers = device_extensions .iter() @@ -905,6 +948,16 @@ impl super::Context { .push_next(&mut vulkan_memory_model); } + // TODO: Replace with ash typed struct once available. + let mut khr_unified_image_layouts; + if capabilities.unified_image_layouts { + khr_unified_image_layouts = unified_image_layouts::PhysicalDeviceFeatures { + unified_image_layouts: vk::TRUE, + ..Default::default() + }; + device_create_info = device_create_info.push_next(&mut khr_unified_image_layouts); + } + let mut core_features = vk::PhysicalDeviceFeatures::default(); if capabilities.dual_source_blending { core_features.dual_src_blend = vk::TRUE;