#![cfg_attr( test, allow( clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::cast_precision_loss, clippy::expect_used, clippy::float_cmp, clippy::identity_op, clippy::too_many_lines, clippy::uninlined_format_args, clippy::map_unwrap_or, clippy::needless_raw_string_hashes, clippy::semicolon_if_nothing_returned, clippy::type_complexity, clippy::panic, clippy::unwrap_used ) )] #![deny(unsafe_op_in_unsafe_fn)] //! Vulkan adapter facade and migration-ready backend surface contract. //! //! This module intentionally keeps backend-agnostic command validation in the //! shared render crate while exposing deterministic lifecycle telemetry used by //! Stage 0 acceptance evidence. //! //! This crate is the declared low-level Vulkan boundary. #[path = "asset_mesh.rs"] mod asset_mesh; mod capabilities; mod instance; mod resources; mod runtime; mod smoke; mod smoke_types; mod surface; mod swapchain; mod swapchain_resources; mod validation; pub use self::asset_mesh::{ project_land_msh_to_static_mesh, project_land_msh_to_static_mesh_in_legacy_world_space, project_land_msh_to_static_mesh_in_world_space, project_land_msh_to_static_mesh_in_xy_frame, project_msh_to_static_mesh, project_msh_to_static_mesh_in_world_space, project_msh_to_static_mesh_in_world_space_with_node_fallback_poses, project_msh_to_static_mesh_in_world_space_with_transform, project_msh_to_static_mesh_in_xy_frame, project_msh_to_static_mesh_in_xy_frame_with_node_fallback_poses, VulkanAssetMeshError, VulkanStaticXyFrame, }; pub use self::capabilities::{ probe_vulkan_runtime_capabilities, probe_vulkan_runtime_capabilities_for_request, VulkanRuntimeCapabilityError, VulkanRuntimeCapabilityProbe, }; pub use self::instance::{ create_vulkan_instance_probe, plan_vulkan_instance, probe_vulkan_loader, render_instance_plan_json, render_loader_probe_report_json, vulkan_entry_symbol_name, VulkanInstanceConfig, VulkanInstanceError, VulkanInstancePlan, VulkanInstanceProbe, VulkanLoaderError, VulkanLoaderProbeReport, }; #[cfg(test)] use self::instance::{cstring_vec, ensure_instance_extensions_available}; use self::resources::{ color_subresource_range, create_command_pool, create_depth_attachment, create_frame_sync, create_readback_buffer, create_static_mesh_index_buffer, create_static_mesh_vertex_buffer, create_static_texture_image, destroy_allocated_buffer, destroy_allocated_image, destroy_depth_attachment, readback_buffer_bytes, VulkanAllocatedBuffer, VulkanAllocatedImage, VulkanDepthAttachment, VulkanFrameSync, }; pub use self::runtime::{ create_vulkan_logical_device_probe, create_vulkan_logical_device_probe_for_request, VulkanLogicalDeviceError, VulkanLogicalDeviceProbe, VulkanLogicalDeviceReport, }; pub use self::smoke_types::{ VulkanReadbackArtifact, VulkanSmokeBootstrapProgress, VulkanSmokeBootstrapSnapshot, VulkanSmokeFrameOutcome, VulkanSmokeRenderer, VulkanSmokeRendererCreateInfo, VulkanSmokeRendererError, VulkanSmokeRendererReport, VulkanSmokeShutdownReport, VulkanStaticCamera, VulkanStaticDrawRange, VulkanStaticMaterial, VulkanStaticMesh, VulkanStaticTexture, VulkanStaticVertex, VulkanValidationReport, }; #[cfg(test)] use self::surface::extension_name; pub use self::surface::{ create_vulkan_surface_probe, plan_vulkan_surface, render_surface_plan_json, VulkanSurfaceError, VulkanSurfacePlan, VulkanSurfaceProbe, }; pub use self::swapchain::{ create_vulkan_swapchain_probe, create_vulkan_swapchain_probe_for_extent, VulkanSwapchainProbe, VulkanSwapchainProbeError, VulkanSwapchainReport, }; use self::swapchain_resources::{ create_swapchain_resources, destroy_swapchain_resources, VulkanSwapchainResources, }; use self::validation::{create_validation_messenger, VulkanValidationMessenger}; use ash::vk; /// Minimum Vulkan API version accepted by the Stage 0 backend. pub const MIN_VULKAN_API_VERSION: u32 = vk::API_VERSION_1_1; const KHR_PORTABILITY_ENUMERATION_EXTENSION: &str = "VK_KHR_portability_enumeration"; const EXT_DEBUG_UTILS_EXTENSION: &str = "VK_EXT_debug_utils"; const VALIDATION_LAYER_NAME: &str = "VK_LAYER_KHRONOS_validation"; pub(crate) const SPIRV_MAGIC: u32 = 0x0723_0203; pub(crate) const SPIRV_VERSION_1_0: u32 = 0x0001_0000; #[allow(dead_code)] const LEGACY_TRIANGLE_VERTEX_SHADER_WORDS: &[u32] = &[ 0x0723_0203, 0x0001_0300, 0x0008_000b, 0x0000_0021, 0x0000_0000, 0x0002_0011, 0x0000_0001, 0x0006_000b, 0x0000_0001, 0x4c53_4c47, 0x6474_732e, 0x3035_342e, 0x0000_0000, 0x0003_000e, 0x0000_0000, 0x0000_0001, 0x0009_000f, 0x0000_0000, 0x0000_0004, 0x6e69_616d, 0x0000_0000, 0x0000_0009, 0x0000_000b, 0x0000_0013, 0x0000_0018, 0x0003_0003, 0x0000_0002, 0x0000_01c2, 0x0004_0005, 0x0000_0004, 0x6e69_616d, 0x0000_0000, 0x0005_0005, 0x0000_0009, 0x5f74_756f, 0x6f6c_6f63, 0x0000_0072, 0x0005_0005, 0x0000_000b, 0x635f_6e69, 0x726f_6c6f, 0x0000_0000, 0x0006_0005, 0x0000_0011, 0x505f_6c67, 0x6556_7265, 0x7865_7472, 0x0000_0000, 0x0006_0006, 0x0000_0011, 0x0000_0000, 0x505f_6c67, 0x7469_736f, 0x006e_6f69, 0x0007_0006, 0x0000_0011, 0x0000_0001, 0x505f_6c67, 0x746e_696f, 0x657a_6953, 0x0000_0000, 0x0007_0006, 0x0000_0011, 0x0000_0002, 0x435f_6c67, 0x4470_696c, 0x6174_7369, 0x0065_636e, 0x0007_0006, 0x0000_0011, 0x0000_0003, 0x435f_6c67, 0x446c_6c75, 0x6174_7369, 0x0065_636e, 0x0003_0005, 0x0000_0013, 0x0000_0000, 0x0005_0005, 0x0000_0018, 0x705f_6e69, 0x7469_736f, 0x006e_6f69, 0x0004_0047, 0x0000_0009, 0x0000_001e, 0x0000_0000, 0x0004_0047, 0x0000_000b, 0x0000_001e, 0x0000_0001, 0x0003_0047, 0x0000_0011, 0x0000_0002, 0x0005_0048, 0x0000_0011, 0x0000_0000, 0x0000_000b, 0x0000_0000, 0x0005_0048, 0x0000_0011, 0x0000_0001, 0x0000_000b, 0x0000_0001, 0x0005_0048, 0x0000_0011, 0x0000_0002, 0x0000_000b, 0x0000_0003, 0x0005_0048, 0x0000_0011, 0x0000_0003, 0x0000_000b, 0x0000_0004, 0x0004_0047, 0x0000_0018, 0x0000_001e, 0x0000_0000, 0x0002_0013, 0x0000_0002, 0x0003_0021, 0x0000_0003, 0x0000_0002, 0x0003_0016, 0x0000_0006, 0x0000_0020, 0x0004_0017, 0x0000_0007, 0x0000_0006, 0x0000_0003, 0x0004_0020, 0x0000_0008, 0x0000_0003, 0x0000_0007, 0x0004_003b, 0x0000_0008, 0x0000_0009, 0x0000_0003, 0x0004_0020, 0x0000_000a, 0x0000_0001, 0x0000_0007, 0x0004_003b, 0x0000_000a, 0x0000_000b, 0x0000_0001, 0x0004_0017, 0x0000_000d, 0x0000_0006, 0x0000_0004, 0x0004_0015, 0x0000_000e, 0x0000_0020, 0x0000_0000, 0x0004_002b, 0x0000_000e, 0x0000_000f, 0x0000_0001, 0x0004_001c, 0x0000_0010, 0x0000_0006, 0x0000_000f, 0x0006_001e, 0x0000_0011, 0x0000_000d, 0x0000_0006, 0x0000_0010, 0x0000_0010, 0x0004_0020, 0x0000_0012, 0x0000_0003, 0x0000_0011, 0x0004_003b, 0x0000_0012, 0x0000_0013, 0x0000_0003, 0x0004_0015, 0x0000_0014, 0x0000_0020, 0x0000_0001, 0x0004_002b, 0x0000_0014, 0x0000_0015, 0x0000_0000, 0x0004_0017, 0x0000_0016, 0x0000_0006, 0x0000_0002, 0x0004_0020, 0x0000_0017, 0x0000_0001, 0x0000_0016, 0x0004_003b, 0x0000_0017, 0x0000_0018, 0x0000_0001, 0x0004_002b, 0x0000_0006, 0x0000_001a, 0x0000_0000, 0x0004_002b, 0x0000_0006, 0x0000_001b, 0x3f80_0000, 0x0004_0020, 0x0000_001f, 0x0000_0003, 0x0000_000d, 0x0005_0036, 0x0000_0002, 0x0000_0004, 0x0000_0000, 0x0000_0003, 0x0002_00f8, 0x0000_0005, 0x0004_003d, 0x0000_0007, 0x0000_000c, 0x0000_000b, 0x0003_003e, 0x0000_0009, 0x0000_000c, 0x0004_003d, 0x0000_0016, 0x0000_0019, 0x0000_0018, 0x0005_0051, 0x0000_0006, 0x0000_001c, 0x0000_0019, 0x0000_0000, 0x0005_0051, 0x0000_0006, 0x0000_001d, 0x0000_0019, 0x0000_0001, 0x0007_0050, 0x0000_000d, 0x0000_001e, 0x0000_001c, 0x0000_001d, 0x0000_001a, 0x0000_001b, 0x0005_0041, 0x0000_001f, 0x0000_0020, 0x0000_0013, 0x0000_0015, 0x0003_003e, 0x0000_0020, 0x0000_001e, 0x0001_00fd, 0x0001_0038, ]; #[allow(dead_code)] const LEGACY_TRIANGLE_FRAGMENT_SHADER_WORDS: &[u32] = &[ 0x0723_0203, 0x0001_0300, 0x0008_000b, 0x0000_0013, 0x0000_0000, 0x0002_0011, 0x0000_0001, 0x0006_000b, 0x0000_0001, 0x4c53_4c47, 0x6474_732e, 0x3035_342e, 0x0000_0000, 0x0003_000e, 0x0000_0000, 0x0000_0001, 0x0007_000f, 0x0000_0004, 0x0000_0004, 0x6e69_616d, 0x0000_0000, 0x0000_0009, 0x0000_000c, 0x0003_0010, 0x0000_0004, 0x0000_0007, 0x0003_0003, 0x0000_0002, 0x0000_01c2, 0x0004_0005, 0x0000_0004, 0x6e69_616d, 0x0000_0000, 0x0005_0005, 0x0000_0009, 0x5f74_756f, 0x6f6c_6f63, 0x0000_0072, 0x0005_0005, 0x0000_000c, 0x635f_6e69, 0x726f_6c6f, 0x0000_0000, 0x0004_0047, 0x0000_0009, 0x0000_001e, 0x0000_0000, 0x0004_0047, 0x0000_000c, 0x0000_001e, 0x0000_0000, 0x0002_0013, 0x0000_0002, 0x0003_0021, 0x0000_0003, 0x0000_0002, 0x0003_0016, 0x0000_0006, 0x0000_0020, 0x0004_0017, 0x0000_0007, 0x0000_0006, 0x0000_0004, 0x0004_0020, 0x0000_0008, 0x0000_0003, 0x0000_0007, 0x0004_003b, 0x0000_0008, 0x0000_0009, 0x0000_0003, 0x0004_0017, 0x0000_000a, 0x0000_0006, 0x0000_0003, 0x0004_0020, 0x0000_000b, 0x0000_0001, 0x0000_000a, 0x0004_003b, 0x0000_000b, 0x0000_000c, 0x0000_0001, 0x0004_002b, 0x0000_0006, 0x0000_000e, 0x3f80_0000, 0x0005_0036, 0x0000_0002, 0x0000_0004, 0x0000_0000, 0x0000_0003, 0x0002_00f8, 0x0000_0005, 0x0004_003d, 0x0000_000a, 0x0000_000d, 0x0000_000c, 0x0005_0051, 0x0000_0006, 0x0000_000f, 0x0000_000d, 0x0000_0000, 0x0005_0051, 0x0000_0006, 0x0000_0010, 0x0000_000d, 0x0000_0001, 0x0005_0051, 0x0000_0006, 0x0000_0011, 0x0000_000d, 0x0000_0002, 0x0007_0050, 0x0000_0007, 0x0000_0012, 0x0000_000f, 0x0000_0010, 0x0000_0011, 0x0000_000e, 0x0003_003e, 0x0000_0009, 0x0000_0012, 0x0001_00fd, 0x0001_0038, ]; const fn spirv_words(bytes: &[u8]) -> [u32; WORD_COUNT] { let mut words = [0_u32; WORD_COUNT]; let mut index = 0; while index < WORD_COUNT { let offset = index * 4; words[index] = u32::from_le_bytes([ bytes[offset], bytes[offset + 1], bytes[offset + 2], bytes[offset + 3], ]); index += 1; } words } static TRIANGLE_VERTEX_SHADER_DATA: [u32; 358] = spirv_words(include_bytes!("../shaders/triangle.vert.spv")); static TRIANGLE_FRAGMENT_SHADER_DATA: [u32; 296] = spirv_words(include_bytes!("../shaders/triangle.frag.spv")); pub(crate) const TRIANGLE_VERTEX_SHADER_WORDS: &[u32] = &TRIANGLE_VERTEX_SHADER_DATA; pub(crate) const TRIANGLE_FRAGMENT_SHADER_WORDS: &[u32] = &TRIANGLE_FRAGMENT_SHADER_DATA; #[cfg(test)] mod tests;