2026-06-25 06:53:16 +04:00
use super ::* ;
use crate ::policy ::{ KHR_PORTABILITY_SUBSET_EXTENSION , KHR_SWAPCHAIN_EXTENSION } ;
use crate ::shader_manifest ::{
SHADER_COMPILER_BINARY_SHA256 , SHADER_COMPILER_NAME , SHADER_COMPILER_VERSION ,
SHADER_MANIFEST_SCHEMA , SHADER_TARGET_ENV , SPIRV_MAGIC , SPIRV_VALIDATOR_BINARY_SHA256 ,
SPIRV_VALIDATOR_NAME , SPIRV_VALIDATOR_VERSION , SPIRV_VERSION_1_0 ,
TRIANGLE_VERTEX_COMPILE_COMMAND , TRIANGLE_VERTEX_SOURCE_PATH , TRIANGLE_VERTEX_SOURCE_SHA256 ,
TRIANGLE_VERTEX_SPIRV_PATH , TRIANGLE_VERTEX_VALIDATE_COMMAND ,
} ;
use crate ::* ;
use fparkan_platform ::RenderRequest ;
use fparkan_render ::{
DrawCommand , DrawId , GpuMaterialId , GpuMeshId , IndexRange , RenderCommand , RenderPhase ,
} ;
use fparkan_render ::{ RenderBackend , RenderError } ;
#[ test ]
fn planning_backend_tracks_render_request_and_simulated_present ( ) -> Result < ( ) , RenderError > {
let mut backend = VulkanPlanningBackend ::new ( ) ;
let request = RenderRequest {
presentation : fparkan_platform ::PresentationMode ::Immediate ,
.. RenderRequest ::conservative ( )
} ;
backend . set_render_request ( request ) ;
assert_eq! ( backend . render_request ( ) , request ) ;
assert_eq! ( backend . report ( ) . request . current_request , request ) ;
assert_eq! ( backend . report ( ) . request . request_updates , 1 ) ;
let commands = fparkan_render ::RenderCommandList {
commands : vec ! [
RenderCommand ::BeginFrame ,
RenderCommand ::Draw ( DrawCommand {
id : DrawId ( 11 ) ,
phase : RenderPhase ::Opaque ,
object_id : None ,
mesh : GpuMeshId ( 1 ) ,
material : GpuMaterialId ( 2 ) ,
transform : [ 1.0 ; 16 ] ,
range : IndexRange { start : 0 , count : 3 } ,
stable_order : 7 ,
} ) ,
RenderCommand ::EndFrame ,
] ,
} ;
backend . execute ( & commands ) ? ;
assert_eq! ( backend . state ( ) , VulkanPlanningBackendState ::Configured ) ;
assert_eq! ( backend . report ( ) . execution . planned_frames , 1 ) ;
assert_eq! ( backend . report ( ) . execution . submission_plans , 1 ) ;
assert_eq! ( backend . report ( ) . execution . simulated_presents , 1 ) ;
assert! ( backend . report ( ) . execution . last_capture_size > 0 ) ;
assert_eq! (
backend . report ( ) . last_frame_submission ,
Some ( VulkanFrameSubmissionPlan {
schema : 1 ,
frames_in_flight : 2 ,
command_buffers : 2 ,
semaphores_per_frame : 2 ,
fences_per_frame : 1 ,
draw_count : 1 ,
indexed_vertex_count : 3 ,
} )
) ;
Ok ( ( ) )
}
#[ test ]
fn frame_submission_plan_json_is_stable ( ) -> Result < ( ) , RenderError > {
let commands = fparkan_render ::RenderCommandList {
commands : vec ! [
RenderCommand ::BeginFrame ,
RenderCommand ::Draw ( DrawCommand {
id : DrawId ( 11 ) ,
phase : RenderPhase ::Opaque ,
object_id : None ,
mesh : GpuMeshId ( 1 ) ,
material : GpuMaterialId ( 2 ) ,
transform : [ 1.0 ; 16 ] ,
range : IndexRange { start : 0 , count : 3 } ,
stable_order : 7 ,
} ) ,
RenderCommand ::EndFrame ,
] ,
} ;
let swapchain = VulkanSwapchainPlan {
schema : 1 ,
extent : ( 1 , 1 ) ,
format : VulkanSurfaceFormat {
format : vk ::Format ::B8G8R8A8_SRGB . as_raw ( ) ,
color_space : vk ::ColorSpaceKHR ::SRGB_NONLINEAR . as_raw ( ) ,
} ,
present_mode : vk ::PresentModeKHR ::FIFO . as_raw ( ) ,
image_count : 3 ,
} ;
let plan = plan_vulkan_frame_submission ( & swapchain , & commands ) ? ;
assert_eq! ( plan . frames_in_flight , 2 ) ;
assert_eq! ( plan . command_buffers , 3 ) ;
assert_eq! ( plan . draw_count , 1 ) ;
assert_eq! ( plan . indexed_vertex_count , 3 ) ;
assert_eq! (
render_frame_submission_plan_json ( & plan ) ,
" { \" schema \" :1, \" frames_in_flight \" :2, \" command_buffers \" :3, \" semaphores_per_frame \" :2, \" fences_per_frame \" :1, \" draw_count \" :1, \" indexed_vertex_count \" :3} "
) ;
Ok ( ( ) )
}
#[ test ]
fn device_scoring_is_deterministic_and_prefers_discrete_unified_queue ( ) {
let devices = vec! [
device ( " SwiftShader " , VulkanDeviceType ::Cpu , 0 , true , false ) ,
device ( " Discrete " , VulkanDeviceType ::DiscreteGpu , 1 , true , false ) ,
device (
" Integrated " ,
VulkanDeviceType ::IntegratedGpu ,
2 ,
true ,
false ,
) ,
] ;
let report = select_physical_device ( & devices ) . expect ( " selected device " ) ;
assert_eq! ( report . device_name , " Discrete " ) ;
assert_eq! ( report . graphics_queue_family , 1 ) ;
assert_eq! ( report . present_queue_family , 1 ) ;
assert! ( ! report . portability_subset ) ;
assert_eq! ( report . enabled_extensions , vec! [ KHR_SWAPCHAIN_EXTENSION ] ) ;
}
#[ test ]
fn device_selection_skips_rejected_candidates_before_accepting_valid_gpu ( ) {
let mut rejected = device ( " Rejected " , VulkanDeviceType ::DiscreteGpu , 0 , true , false ) ;
rejected . queue_families [ 0 ] . present = false ;
let accepted = device ( " Accepted " , VulkanDeviceType ::IntegratedGpu , 2 , true , false ) ;
let report = select_physical_device ( & [ rejected , accepted ] ) . expect ( " selected fallback device " ) ;
assert_eq! ( report . device_name , " Accepted " ) ;
assert_eq! ( report . graphics_queue_family , 2 ) ;
assert_eq! ( report . present_queue_family , 2 ) ;
2026-06-25 07:55:08 +04:00
assert_eq! (
report . rejected_devices ,
vec! [ VulkanRejectedDeviceReport {
device_name : " Rejected " . to_string ( ) ,
reason_code : " no_present_queue " ,
reason : " Vulkan device Rejected has no present queue " . to_string ( ) ,
} ]
) ;
2026-06-25 06:53:16 +04:00
}
#[ test ]
fn queue_family_selection_prefers_lowest_index_unified_family ( ) {
let mut candidate = device (
" Unified later in list " ,
VulkanDeviceType ::DiscreteGpu ,
7 ,
true ,
false ,
) ;
candidate . queue_families = vec! [
VulkanQueueFamily {
index : 9 ,
graphics : true ,
present : true ,
} ,
VulkanQueueFamily {
index : 3 ,
graphics : true ,
present : true ,
} ,
VulkanQueueFamily {
index : 1 ,
graphics : true ,
present : false ,
} ,
] ;
let report = select_physical_device ( & [ candidate ] ) . expect ( " selected unified queue " ) ;
assert_eq! ( report . graphics_queue_family , 3 ) ;
assert_eq! ( report . present_queue_family , 3 ) ;
}
#[ test ]
fn portability_subset_is_reported_and_enabled_when_exposed ( ) {
let report = select_physical_device ( & [ device (
" MoltenVK " ,
VulkanDeviceType ::IntegratedGpu ,
0 ,
true ,
true ,
) ] )
. expect ( " selected device " ) ;
assert! ( report . portability_subset ) ;
assert_eq! (
report . enabled_extensions ,
vec! [
KHR_SWAPCHAIN_EXTENSION . to_string ( ) ,
KHR_PORTABILITY_SUBSET_EXTENSION . to_string ( )
]
) ;
}
#[ test ]
fn missing_loader_candidates_are_reported ( ) {
assert_eq! (
select_physical_device ( & [ ] ) ,
Err ( VulkanCapabilityError ::NoPhysicalDevice )
) ;
}
#[ test ]
fn rejects_low_api_version ( ) {
let mut candidate = device ( " Old GPU " , VulkanDeviceType ::DiscreteGpu , 0 , true , false ) ;
candidate . api_version = vk ::API_VERSION_1_0 ;
assert! ( matches! (
select_physical_device ( & [ candidate ] ) ,
Err ( VulkanCapabilityError ::ApiVersionTooLow { .. } )
) ) ;
}
#[ test ]
fn rejects_missing_graphics_present_swapchain_and_format ( ) {
let mut no_graphics = device ( " No graphics " , VulkanDeviceType ::DiscreteGpu , 0 , true , false ) ;
no_graphics . queue_families [ 0 ] . graphics = false ;
assert! ( matches! (
select_physical_device ( & [ no_graphics ] ) ,
Err ( VulkanCapabilityError ::NoGraphicsQueue { .. } )
) ) ;
let mut no_present = device ( " No present " , VulkanDeviceType ::DiscreteGpu , 0 , true , false ) ;
no_present . queue_families [ 0 ] . present = false ;
assert! ( matches! (
select_physical_device ( & [ no_present ] ) ,
Err ( VulkanCapabilityError ::NoPresentQueue { .. } )
) ) ;
let no_swapchain = device (
" No swapchain " ,
VulkanDeviceType ::DiscreteGpu ,
0 ,
false ,
false ,
) ;
assert! ( matches! (
select_physical_device ( & [ no_swapchain ] ) ,
Err ( VulkanCapabilityError ::MissingSwapchainExtension { .. } )
) ) ;
let mut no_format = device ( " No format " , VulkanDeviceType ::DiscreteGpu , 0 , true , false ) ;
no_format . surface_formats . clear ( ) ;
assert! ( matches! (
select_physical_device ( & [ no_format ] ) ,
Err ( VulkanCapabilityError ::MissingSurfaceFormat { .. } )
) ) ;
let mut no_present_mode = device (
" No present mode " ,
VulkanDeviceType ::DiscreteGpu ,
0 ,
true ,
false ,
) ;
no_present_mode . present_modes . clear ( ) ;
assert! ( matches! (
select_physical_device ( & [ no_present_mode ] ) ,
Err ( VulkanCapabilityError ::MissingPresentMode { .. } )
) ) ;
let mut no_color_attachment = device (
" No color attachment " ,
VulkanDeviceType ::DiscreteGpu ,
0 ,
true ,
false ,
) ;
no_color_attachment
. surface_capabilities
. supported_usage_flags = vk ::ImageUsageFlags ::TRANSFER_DST . as_raw ( ) ;
assert! ( matches! (
select_physical_device ( & [ no_color_attachment ] ) ,
Err ( VulkanCapabilityError ::MissingColorAttachmentUsage { .. } )
) ) ;
}
#[ test ]
fn capability_report_json_is_stable ( ) {
2026-06-25 07:55:08 +04:00
let mut rejected = device ( " Rejected " , VulkanDeviceType ::IntegratedGpu , 0 , true , false ) ;
rejected . present_modes . clear ( ) ;
let report = select_physical_device ( & [
rejected ,
device ( " GPU \" A \" " , VulkanDeviceType ::DiscreteGpu , 3 , true , false ) ,
] )
2026-06-25 06:53:16 +04:00
. expect ( " selected device " ) ;
assert_eq! (
render_capability_report_json ( & report ) ,
2026-06-25 07:55:08 +04:00
" { \" schema \" :1, \" vulkan_api \" : \" 1.1.0 \" , \" device_name \" : \" GPU \\ \" A \\ \" \" , \" score \" :1101, \" graphics_queue_family \" :3, \" present_queue_family \" :3, \" portability_subset \" :false, \" enabled_extensions \" :[ \" VK_KHR_swapchain \" ], \" rejected_devices \" :[{ \" device_name \" : \" Rejected \" , \" reason_code \" : \" missing_present_mode \" , \" reason \" : \" Vulkan device Rejected has no supported present mode \" }]} "
2026-06-25 06:53:16 +04:00
) ;
}
#[ test ]
fn loader_probe_report_json_is_stable ( ) {
assert_eq! (
vulkan_entry_symbol_name ( ) . to_bytes ( ) ,
b " vkGetInstanceProcAddr "
) ;
assert_eq! (
render_loader_probe_report_json ( & VulkanLoaderProbeReport {
schema : 1 ,
loader_available : true ,
instance_api_version : vk ::API_VERSION_1_2 ,
} ) ,
" { \" schema \" :1, \" loader_available \" :true, \" instance_api \" : \" 1.2.0 \" } "
) ;
}
#[ test ]
fn loader_error_display_is_actionable ( ) {
assert_eq! (
VulkanLoaderError ::Unavailable {
message : " dlopen failed " . to_string ( ) ,
}
. to_string ( ) ,
" Vulkan loader is unavailable: dlopen failed "
) ;
}
#[ test ]
fn instance_plan_is_sorted_deduplicated_and_portability_aware ( ) {
let plan = plan_vulkan_instance ( & VulkanInstanceConfig {
application_name : " FParkan " . to_string ( ) ,
required_extensions : vec ! [
" VK_KHR_surface " . to_string ( ) ,
KHR_PORTABILITY_ENUMERATION_EXTENSION . to_string ( ) ,
" VK_KHR_surface " . to_string ( ) ,
] ,
enable_portability_enumeration : true ,
enable_validation : true ,
} ) ;
assert_eq! (
render_instance_plan_json ( & plan ) ,
" { \" schema \" :1, \" create_flags \" :1, \" validation_requested \" :true, \" enabled_extensions \" :[ \" VK_EXT_debug_utils \" , \" VK_KHR_portability_enumeration \" , \" VK_KHR_surface \" ]} "
) ;
}
#[ test ]
fn instance_plan_adds_portability_extension_when_requested ( ) {
let plan = plan_vulkan_instance ( & VulkanInstanceConfig {
application_name : " FParkan " . to_string ( ) ,
required_extensions : vec ! [ " VK_KHR_surface " . to_string ( ) ] ,
enable_portability_enumeration : true ,
enable_validation : false ,
} ) ;
assert_eq! (
plan . enabled_extensions ,
vec! [
KHR_PORTABILITY_ENUMERATION_EXTENSION . to_string ( ) ,
" VK_KHR_surface " . to_string ( )
]
) ;
assert_eq! ( plan . create_flags , 1 ) ;
}
#[ test ]
fn invalid_instance_extension_name_is_reported_before_loader_use ( ) {
assert_eq! (
cstring_vec ( & [ " bad \0 extension " . to_string ( ) ] ) ,
Err ( VulkanInstanceError ::InvalidExtensionName {
extension : " bad \0 extension " . to_string ( )
} )
) ;
}
#[ test ]
fn missing_instance_extension_is_reported_before_create_instance ( ) {
assert_eq! (
ensure_instance_extensions_available (
& [
" VK_EXT_debug_utils " . to_string ( ) ,
" VK_KHR_surface " . to_string ( ) ,
] ,
& [ " VK_KHR_surface " . to_string ( ) ] ,
) ,
Err ( VulkanInstanceError ::MissingInstanceExtension {
extension : " VK_EXT_debug_utils " . to_string ( ) ,
} )
) ;
}
#[ test ]
fn surface_plan_requires_native_handles ( ) {
assert_eq! (
plan_vulkan_surface ( None ) ,
Err ( VulkanSurfaceError ::MissingNativeHandles )
) ;
assert_eq! (
VulkanSurfaceError ::MissingNativeHandles . to_string ( ) ,
" native window/display handles are required for Vulkan surface creation "
) ;
}
#[ test ]
fn surface_plan_json_is_stable ( ) {
assert_eq! (
render_surface_plan_json ( & VulkanSurfacePlan {
schema : 1 ,
required_instance_extensions : vec ! [
" VK_KHR_surface " . to_string ( ) ,
" VK_EXT_metal_surface " . to_string ( ) ,
] ,
} ) ,
" { \" schema \" :1, \" required_instance_extensions \" :[ \" VK_KHR_surface \" , \" VK_EXT_metal_surface \" ]} "
) ;
}
#[ test ]
fn static_surface_extension_name_is_decoded ( ) {
let name = extension_name ( ash ::khr ::surface ::NAME . as_ptr ( ) ) . expect ( " extension name " ) ;
assert_eq! ( name , " VK_KHR_surface " ) ;
}
#[ test ]
fn swapchain_plan_prefers_srgb_mailbox_and_clamps_extent ( ) {
let plan = plan_vulkan_swapchain ( & swapchain_request ( ) ) . expect ( " swapchain plan " ) ;
assert_eq! (
plan . format ,
VulkanSurfaceFormat {
format : vk ::Format ::B8G8R8A8_SRGB . as_raw ( ) ,
color_space : vk ::ColorSpaceKHR ::SRGB_NONLINEAR . as_raw ( ) ,
}
) ;
assert_eq! ( plan . present_mode , vk ::PresentModeKHR ::MAILBOX . as_raw ( ) ) ;
assert_eq! ( plan . extent , ( 1024 , 720 ) ) ;
assert_eq! ( plan . image_count , 3 ) ;
}
#[ test ]
fn swapchain_plan_uses_fifo_and_current_extent_fallbacks ( ) {
let mut request = swapchain_request ( ) ;
request . preferred_present_mode = vk ::PresentModeKHR ::IMMEDIATE . as_raw ( ) ;
request . present_modes = vec! [ vk ::PresentModeKHR ::FIFO . as_raw ( ) ] ;
request . capabilities . current_extent = Some ( ( 800 , 600 ) ) ;
let plan = plan_vulkan_swapchain ( & request ) . expect ( " swapchain plan " ) ;
assert_eq! ( plan . present_mode , vk ::PresentModeKHR ::FIFO . as_raw ( ) ) ;
assert_eq! ( plan . extent , ( 800 , 600 ) ) ;
}
#[ test ]
fn swapchain_plan_accepts_undefined_surface_format_by_picking_stage0_default ( ) {
let mut request = swapchain_request ( ) ;
request . formats = vec! [ VulkanSurfaceFormat {
format : vk ::Format ::UNDEFINED . as_raw ( ) ,
color_space : vk ::ColorSpaceKHR ::SRGB_NONLINEAR . as_raw ( ) ,
} ] ;
let plan = plan_vulkan_swapchain ( & request ) . expect ( " swapchain plan " ) ;
assert_eq! (
plan . format ,
VulkanSurfaceFormat {
format : vk ::Format ::B8G8R8A8_SRGB . as_raw ( ) ,
color_space : vk ::ColorSpaceKHR ::SRGB_NONLINEAR . as_raw ( ) ,
}
) ;
}
#[ test ]
fn swapchain_plan_rejects_missing_surface_data_and_empty_extent ( ) {
let mut request = swapchain_request ( ) ;
request . formats . clear ( ) ;
assert_eq! (
plan_vulkan_swapchain ( & request ) ,
Err ( VulkanSwapchainError ::MissingSurfaceFormat )
) ;
let mut request = swapchain_request ( ) ;
request . present_modes . clear ( ) ;
assert_eq! (
plan_vulkan_swapchain ( & request ) ,
Err ( VulkanSwapchainError ::MissingPresentMode )
) ;
let mut request = swapchain_request ( ) ;
request . capabilities . current_extent = Some ( ( 0 , 600 ) ) ;
assert_eq! (
plan_vulkan_swapchain ( & request ) ,
Err ( VulkanSwapchainError ::EmptyExtent )
) ;
}
#[ test ]
fn swapchain_plan_json_and_recreation_reports_are_stable ( ) {
let plan = plan_vulkan_swapchain ( & swapchain_request ( ) ) . expect ( " swapchain plan " ) ;
assert_eq! (
render_swapchain_plan_json ( & plan ) ,
" { \" schema \" :1, \" extent \" :[1024,720], \" format \" :50, \" color_space \" :0, \" present_mode \" :1, \" image_count \" :3} "
) ;
let report = swapchain_recreation_report (
VulkanSwapchainRecreationReason ::OutOfDate ,
( 1024 , 720 ) ,
( 1280 , 720 ) ,
) ;
assert_eq! (
render_swapchain_recreation_report_json ( & report ) ,
" { \" schema \" :1, \" reason \" : \" out_of_date \" , \" previous_extent \" :[1024,720], \" next_extent \" :[1280,720]} "
) ;
}
#[ test ]
fn triangle_shader_manifest_hashes_are_stable ( ) {
let report = validate_shader_manifest ( & triangle_shader_manifest ( ) ) . expect ( " shader manifest " ) ;
assert_eq! ( report . schema , SHADER_MANIFEST_SCHEMA ) ;
assert_eq! ( report . target_env , SHADER_TARGET_ENV ) ;
assert_eq! (
report . compiler ,
VulkanShaderToolManifest {
name : SHADER_COMPILER_NAME ,
version : SHADER_COMPILER_VERSION ,
binary_sha256 : SHADER_COMPILER_BINARY_SHA256 ,
}
) ;
assert_eq! (
report . validator ,
VulkanShaderToolManifest {
name : SPIRV_VALIDATOR_NAME ,
version : SPIRV_VALIDATOR_VERSION ,
binary_sha256 : SPIRV_VALIDATOR_BINARY_SHA256 ,
}
) ;
assert_eq! ( report . modules . len ( ) , 2 ) ;
assert_eq! ( report . modules [ 0 ] . name , " triangle.vert " ) ;
assert_eq! ( report . modules [ 0 ] . stage , VulkanShaderStage ::Vertex ) ;
assert_eq! ( report . modules [ 0 ] . source_path , TRIANGLE_VERTEX_SOURCE_PATH ) ;
assert_eq! (
report . modules [ 0 ] . source_sha256 ,
TRIANGLE_VERTEX_SOURCE_SHA256
) ;
assert_eq! ( report . modules [ 0 ] . spirv_path , TRIANGLE_VERTEX_SPIRV_PATH ) ;
assert_eq! ( report . modules [ 0 ] . word_count , 253 ) ;
assert_eq! (
report . modules [ 0 ] . sha256 ,
" 9023b1cc856c98ecd21755596c4e9d1e62cc63e1787f8c43ada2101544e8d0d1 "
) ;
assert_eq! ( report . modules [ 0 ] . descriptor_sets , 0 ) ;
assert_eq! ( report . modules [ 0 ] . push_constant_bytes , 0 ) ;
assert_eq! (
report . modules [ 0 ] . compile_command ,
TRIANGLE_VERTEX_COMPILE_COMMAND
) ;
assert_eq! (
report . modules [ 0 ] . validate_command ,
TRIANGLE_VERTEX_VALIDATE_COMMAND
) ;
assert! ( ! report . modules [ 0 ] . interface_hash . is_empty ( ) ) ;
assert_eq! (
report . modules [ 1 ] . sha256 ,
" 6efe2c9716ae845c471ecbaac2c83e56a17a37dc017dd63f0a05f0d9161f44ba "
) ;
assert_eq! (
report . manifest_hash ,
2026-06-25 07:47:20 +04:00
" 20fb84fb6edbd6897e2ea3c2ec3a6db3826a84b46c4efb69027c1cfc0119ccf2 "
2026-06-25 06:53:16 +04:00
) ;
}
#[ test ]
fn shader_manifest_report_json_is_stable ( ) {
let report = validate_shader_manifest ( & triangle_shader_manifest ( ) ) . expect ( " shader manifest " ) ;
let json = render_shader_manifest_report_json ( & report ) ;
assert! ( json . contains ( SHADER_COMPILER_NAME ) ) ;
assert! ( json . contains ( SPIRV_VALIDATOR_NAME ) ) ;
assert! ( json . contains ( TRIANGLE_VERTEX_SOURCE_PATH ) ) ;
assert! ( json . contains ( TRIANGLE_VERTEX_COMPILE_COMMAND ) ) ;
}
#[ test ]
fn checked_in_shader_manifest_matches_generated_report ( ) {
let report = validate_shader_manifest ( & triangle_shader_manifest ( ) ) . expect ( " shader manifest " ) ;
assert_eq! (
render_shader_manifest_report_json ( & report ) ,
include_str! ( " ../../shaders/manifest.json " ) . trim ( )
) ;
}
#[ test ]
fn shader_manifest_rejects_invalid_spirv_containers ( ) {
let mut module = triangle_shader_manifest ( ) . remove ( 0 ) ;
module . words = & [ 0xFFFF_FFFF , SPIRV_VERSION_1_0 , 0 , 1 , 0 ] ;
assert_eq! (
validate_shader_manifest ( & [ module ] ) ,
Err ( VulkanShaderManifestError ::InvalidMagic {
name : " triangle.vert " ,
found : 0xFFFF_FFFF ,
} )
) ;
let mut module = triangle_shader_manifest ( ) . remove ( 0 ) ;
module . words = & [ SPIRV_MAGIC , 0 , 0 , 1 , 0 ] ;
assert_eq! (
validate_shader_manifest ( & [ module ] ) ,
Err ( VulkanShaderManifestError ::UnsupportedVersion {
name : " triangle.vert " ,
found : 0 ,
} )
) ;
let mut module = triangle_shader_manifest ( ) . remove ( 0 ) ;
module . words = & [ SPIRV_MAGIC , SPIRV_VERSION_1_0 , 0 , 0 , 0 ] ;
assert_eq! (
validate_shader_manifest ( & [ module ] ) ,
Err ( VulkanShaderManifestError ::InvalidBound {
name : " triangle.vert " ,
} )
) ;
}
fn device (
name : & str ,
device_type : VulkanDeviceType ,
queue_index : u32 ,
swapchain : bool ,
portability_subset : bool ,
) -> VulkanPhysicalDeviceRecord {
let mut extensions = Vec ::new ( ) ;
if swapchain {
extensions . push ( KHR_SWAPCHAIN_EXTENSION . to_string ( ) ) ;
}
if portability_subset {
extensions . push ( KHR_PORTABILITY_SUBSET_EXTENSION . to_string ( ) ) ;
}
VulkanPhysicalDeviceRecord {
name : name . to_string ( ) ,
api_version : MIN_VULKAN_API_VERSION ,
device_type ,
extensions ,
queue_families : vec ! [ VulkanQueueFamily {
index : queue_index ,
graphics : true ,
present : true ,
} ] ,
surface_formats : vec ! [ VulkanSurfaceFormat {
format : vk ::Format ::B8G8R8A8_SRGB . as_raw ( ) ,
color_space : vk ::ColorSpaceKHR ::SRGB_NONLINEAR . as_raw ( ) ,
} ] ,
present_modes : vec ! [
vk ::PresentModeKHR ::FIFO . as_raw ( ) ,
vk ::PresentModeKHR ::MAILBOX . as_raw ( ) ,
] ,
surface_capabilities : default_surface_capabilities ( ) ,
}
}
fn swapchain_request ( ) -> VulkanSwapchainRequest {
VulkanSwapchainRequest {
drawable_extent : ( 1280 , 720 ) ,
formats : vec ! [
VulkanSurfaceFormat {
format : vk ::Format ::R8G8B8A8_UNORM . as_raw ( ) ,
color_space : vk ::ColorSpaceKHR ::SRGB_NONLINEAR . as_raw ( ) ,
} ,
VulkanSurfaceFormat {
format : vk ::Format ::B8G8R8A8_SRGB . as_raw ( ) ,
color_space : vk ::ColorSpaceKHR ::SRGB_NONLINEAR . as_raw ( ) ,
} ,
] ,
present_modes : vec ! [
vk ::PresentModeKHR ::FIFO . as_raw ( ) ,
vk ::PresentModeKHR ::MAILBOX . as_raw ( ) ,
] ,
capabilities : default_surface_capabilities ( ) ,
preferred_present_mode : vk ::PresentModeKHR ::MAILBOX . as_raw ( ) ,
}
}
fn default_surface_capabilities ( ) -> VulkanSwapchainSurfaceCapabilities {
VulkanSwapchainSurfaceCapabilities {
current_extent : None ,
min_extent : ( 320 , 240 ) ,
max_extent : ( 1024 , 768 ) ,
min_image_count : 2 ,
max_image_count : 3 ,
supported_usage_flags : vk ::ImageUsageFlags ::COLOR_ATTACHMENT . as_raw ( ) ,
}
}