fix(vulkan-policy): report sampled formats and limits
This commit is contained in:
@@ -7,9 +7,9 @@ use std::ffi::CStr;
|
|||||||
use super::{VulkanInstanceProbe, VulkanSurfaceProbe};
|
use super::{VulkanInstanceProbe, VulkanSurfaceProbe};
|
||||||
use crate::policy::{
|
use crate::policy::{
|
||||||
compare_reports, plan_vulkan_swapchain, validate_device_for_request, VulkanCapabilityError,
|
compare_reports, plan_vulkan_swapchain, validate_device_for_request, VulkanCapabilityError,
|
||||||
VulkanCapabilityReport, VulkanDeviceType, VulkanPhysicalDeviceRecord, VulkanQueueFamily,
|
VulkanCapabilityReport, VulkanDeviceLimits, VulkanDeviceType, VulkanPhysicalDeviceRecord,
|
||||||
VulkanSurfaceFormat, VulkanSwapchainError, VulkanSwapchainPlan, VulkanSwapchainRequest,
|
VulkanQueueFamily, VulkanSurfaceFormat, VulkanSwapchainError, VulkanSwapchainPlan,
|
||||||
VulkanSwapchainSurfaceCapabilities,
|
VulkanSwapchainRequest, VulkanSwapchainSurfaceCapabilities,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Live Vulkan device/surface capability probe.
|
/// Live Vulkan device/surface capability probe.
|
||||||
@@ -242,6 +242,7 @@ fn live_device_candidate(
|
|||||||
let present_modes = live_present_modes(surface, device, &name)?;
|
let present_modes = live_present_modes(surface, device, &name)?;
|
||||||
let surface_capabilities = live_surface_capabilities(surface, device, &name)?;
|
let surface_capabilities = live_surface_capabilities(surface, device, &name)?;
|
||||||
let supported_depth_stencil_formats = live_depth_stencil_formats(instance, device);
|
let supported_depth_stencil_formats = live_depth_stencil_formats(instance, device);
|
||||||
|
let sampled_image_formats = live_sampled_image_formats(instance, device);
|
||||||
let queue_families = queue_properties
|
let queue_families = queue_properties
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
@@ -284,6 +285,13 @@ fn live_device_candidate(
|
|||||||
present_modes: present_modes.clone(),
|
present_modes: present_modes.clone(),
|
||||||
surface_capabilities,
|
surface_capabilities,
|
||||||
supported_depth_stencil_formats,
|
supported_depth_stencil_formats,
|
||||||
|
sampled_image_formats,
|
||||||
|
limits: VulkanDeviceLimits {
|
||||||
|
max_image_dimension_2d: properties.limits.max_image_dimension2_d,
|
||||||
|
max_sampler_allocation_count: properties.limits.max_sampler_allocation_count,
|
||||||
|
max_per_stage_descriptor_samplers: properties.limits.max_per_stage_descriptor_samplers,
|
||||||
|
max_bound_descriptor_sets: properties.limits.max_bound_descriptor_sets,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
let capability = validate_device_for_request(&record, render_request)
|
let capability = validate_device_for_request(&record, render_request)
|
||||||
.map_err(VulkanRuntimeCapabilityError::Capability)?;
|
.map_err(VulkanRuntimeCapabilityError::Capability)?;
|
||||||
@@ -468,3 +476,33 @@ fn live_depth_stencil_formats(
|
|||||||
.map(vk::Format::as_raw)
|
.map(vk::Format::as_raw)
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn live_sampled_image_formats(
|
||||||
|
instance: &VulkanInstanceProbe,
|
||||||
|
device: vk::PhysicalDevice,
|
||||||
|
) -> Vec<i32> {
|
||||||
|
[
|
||||||
|
vk::Format::R8G8B8A8_SRGB,
|
||||||
|
vk::Format::B8G8R8A8_SRGB,
|
||||||
|
vk::Format::D16_UNORM,
|
||||||
|
vk::Format::D32_SFLOAT,
|
||||||
|
vk::Format::D24_UNORM_S8_UINT,
|
||||||
|
vk::Format::D32_SFLOAT_S8_UINT,
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.filter(|format| {
|
||||||
|
let properties = {
|
||||||
|
// SAFETY: `device` belongs to `instance`; format-property queries copy data by value.
|
||||||
|
unsafe {
|
||||||
|
instance
|
||||||
|
.instance
|
||||||
|
.get_physical_device_format_properties(device, *format)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
properties
|
||||||
|
.optimal_tiling_features
|
||||||
|
.contains(vk::FormatFeatureFlags::SAMPLED_IMAGE)
|
||||||
|
})
|
||||||
|
.map(vk::Format::as_raw)
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|||||||
@@ -317,6 +317,36 @@ fn capability_gate_respects_request_specific_depth_profiles() {
|
|||||||
assert!(report.rejected_devices.is_empty());
|
assert!(report.rejected_devices.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn capability_report_preserves_informational_sampled_formats_and_limits() {
|
||||||
|
let report = select_physical_device(&[device(
|
||||||
|
"Telemetry GPU",
|
||||||
|
VulkanDeviceType::DiscreteGpu,
|
||||||
|
0,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
)])
|
||||||
|
.expect("selected device");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
report.informational_capabilities.sampled_color_formats,
|
||||||
|
vec![vk::Format::B8G8R8A8_SRGB.as_raw()]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
report.informational_capabilities.sampled_depth_formats,
|
||||||
|
vec![vk::Format::D32_SFLOAT.as_raw()]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
report.informational_capabilities.limits,
|
||||||
|
VulkanDeviceLimits {
|
||||||
|
max_image_dimension_2d: 4096,
|
||||||
|
max_sampler_allocation_count: 4096,
|
||||||
|
max_per_stage_descriptor_samplers: 16,
|
||||||
|
max_bound_descriptor_sets: 4,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn capability_report_json_is_stable() {
|
fn capability_report_json_is_stable() {
|
||||||
let mut rejected = device("Rejected", VulkanDeviceType::IntegratedGpu, 0, true, false);
|
let mut rejected = device("Rejected", VulkanDeviceType::IntegratedGpu, 0, true, false);
|
||||||
@@ -329,7 +359,7 @@ fn capability_report_json_is_stable() {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
render_capability_report_json(&report),
|
render_capability_report_json(&report),
|
||||||
"{\"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\"}]}"
|
"{\"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\"],\"informational_capabilities\":{\"sampled_color_formats\":[50],\"sampled_depth_formats\":[126],\"limits\":{\"max_image_dimension_2d\":4096,\"max_sampler_allocation_count\":4096,\"max_per_stage_descriptor_samplers\":16,\"max_bound_descriptor_sets\":4}},\"rejected_devices\":[{\"device_name\":\"Rejected\",\"reason_code\":\"missing_present_mode\",\"reason\":\"Vulkan device Rejected has no supported present mode\"}]}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -695,6 +725,16 @@ fn device(
|
|||||||
vk::Format::D32_SFLOAT_S8_UINT.as_raw(),
|
vk::Format::D32_SFLOAT_S8_UINT.as_raw(),
|
||||||
vk::Format::D32_SFLOAT.as_raw(),
|
vk::Format::D32_SFLOAT.as_raw(),
|
||||||
],
|
],
|
||||||
|
sampled_image_formats: vec![
|
||||||
|
vk::Format::B8G8R8A8_SRGB.as_raw(),
|
||||||
|
vk::Format::D32_SFLOAT.as_raw(),
|
||||||
|
],
|
||||||
|
limits: VulkanDeviceLimits {
|
||||||
|
max_image_dimension_2d: 4096,
|
||||||
|
max_sampler_allocation_count: 4096,
|
||||||
|
max_per_stage_descriptor_samplers: 16,
|
||||||
|
max_bound_descriptor_sets: 4,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -185,6 +185,10 @@ pub struct VulkanPhysicalDeviceRecord {
|
|||||||
pub surface_capabilities: VulkanSwapchainSurfaceCapabilities,
|
pub surface_capabilities: VulkanSwapchainSurfaceCapabilities,
|
||||||
/// Depth/stencil attachment formats supported by the device.
|
/// Depth/stencil attachment formats supported by the device.
|
||||||
pub supported_depth_stencil_formats: Vec<i32>,
|
pub supported_depth_stencil_formats: Vec<i32>,
|
||||||
|
/// Formats that can be used as sampled images.
|
||||||
|
pub sampled_image_formats: Vec<i32>,
|
||||||
|
/// Informational device limits relevant to the future Stage 0 baseline.
|
||||||
|
pub limits: VulkanDeviceLimits,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VulkanPhysicalDeviceRecord {
|
impl VulkanPhysicalDeviceRecord {
|
||||||
@@ -197,6 +201,30 @@ impl VulkanPhysicalDeviceRecord {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Informational device limits relevant to future Stage 0 capability growth.
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
|
||||||
|
pub struct VulkanDeviceLimits {
|
||||||
|
/// Maximum 2D image dimension supported by the device.
|
||||||
|
pub max_image_dimension_2d: u32,
|
||||||
|
/// Maximum number of live samplers supported by the device.
|
||||||
|
pub max_sampler_allocation_count: u32,
|
||||||
|
/// Maximum number of sampler descriptors per stage.
|
||||||
|
pub max_per_stage_descriptor_samplers: u32,
|
||||||
|
/// Maximum number of bound descriptor sets.
|
||||||
|
pub max_bound_descriptor_sets: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Informational capabilities preserved in deterministic Stage 0 reports.
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||||
|
pub struct VulkanInformationalCapabilities {
|
||||||
|
/// Color formats that support sampled-image usage.
|
||||||
|
pub sampled_color_formats: Vec<i32>,
|
||||||
|
/// Depth/stencil formats that support sampled-image usage.
|
||||||
|
pub sampled_depth_formats: Vec<i32>,
|
||||||
|
/// Future-baseline device limits.
|
||||||
|
pub limits: VulkanDeviceLimits,
|
||||||
|
}
|
||||||
|
|
||||||
/// Selected device and queue capability report.
|
/// Selected device and queue capability report.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct VulkanCapabilityReport {
|
pub struct VulkanCapabilityReport {
|
||||||
@@ -216,6 +244,8 @@ pub struct VulkanCapabilityReport {
|
|||||||
pub portability_subset: bool,
|
pub portability_subset: bool,
|
||||||
/// Enabled device extensions.
|
/// Enabled device extensions.
|
||||||
pub enabled_extensions: Vec<String>,
|
pub enabled_extensions: Vec<String>,
|
||||||
|
/// Informational capabilities retained for future baseline planning.
|
||||||
|
pub informational_capabilities: VulkanInformationalCapabilities,
|
||||||
/// Devices rejected by deterministic Stage 0 capability validation.
|
/// Devices rejected by deterministic Stage 0 capability validation.
|
||||||
pub rejected_devices: Vec<VulkanRejectedDeviceReport>,
|
pub rejected_devices: Vec<VulkanRejectedDeviceReport>,
|
||||||
}
|
}
|
||||||
@@ -459,6 +489,7 @@ pub fn render_capability_report_json(report: &VulkanCapabilityReport) -> String
|
|||||||
present_queue_family: u32,
|
present_queue_family: u32,
|
||||||
portability_subset: bool,
|
portability_subset: bool,
|
||||||
enabled_extensions: &'a [String],
|
enabled_extensions: &'a [String],
|
||||||
|
informational_capabilities: &'a VulkanInformationalCapabilities,
|
||||||
rejected_devices: &'a [VulkanRejectedDeviceReport],
|
rejected_devices: &'a [VulkanRejectedDeviceReport],
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,9 +503,10 @@ pub fn render_capability_report_json(report: &VulkanCapabilityReport) -> String
|
|||||||
present_queue_family: report.present_queue_family,
|
present_queue_family: report.present_queue_family,
|
||||||
portability_subset: report.portability_subset,
|
portability_subset: report.portability_subset,
|
||||||
enabled_extensions: &report.enabled_extensions,
|
enabled_extensions: &report.enabled_extensions,
|
||||||
|
informational_capabilities: &report.informational_capabilities,
|
||||||
rejected_devices: &report.rejected_devices,
|
rejected_devices: &report.rejected_devices,
|
||||||
},
|
},
|
||||||
"{\"schema\":0,\"vulkan_api\":\"0.0.0\",\"device_name\":\"unknown\",\"score\":0,\"graphics_queue_family\":0,\"present_queue_family\":0,\"portability_subset\":false,\"enabled_extensions\":[],\"rejected_devices\":[]}",
|
"{\"schema\":0,\"vulkan_api\":\"0.0.0\",\"device_name\":\"unknown\",\"score\":0,\"graphics_queue_family\":0,\"present_queue_family\":0,\"portability_subset\":false,\"enabled_extensions\":[],\"informational_capabilities\":{\"sampled_color_formats\":[],\"sampled_depth_formats\":[],\"limits\":{\"max_image_dimension_2d\":0,\"max_sampler_allocation_count\":0,\"max_per_stage_descriptor_samplers\":0,\"max_bound_descriptor_sets\":0}},\"rejected_devices\":[]}",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -694,6 +726,7 @@ pub(crate) fn validate_device_for_request(
|
|||||||
present_queue_family,
|
present_queue_family,
|
||||||
portability_subset,
|
portability_subset,
|
||||||
enabled_extensions,
|
enabled_extensions,
|
||||||
|
informational_capabilities: informational_capabilities(device),
|
||||||
rejected_devices: Vec::new(),
|
rejected_devices: Vec::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -780,6 +813,21 @@ fn supports_depth_stencil_request(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn informational_capabilities(
|
||||||
|
device: &VulkanPhysicalDeviceRecord,
|
||||||
|
) -> VulkanInformationalCapabilities {
|
||||||
|
let (sampled_depth_formats, sampled_color_formats): (Vec<_>, Vec<_>) = device
|
||||||
|
.sampled_image_formats
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.partition(|format| is_depth_stencil_format(*format));
|
||||||
|
VulkanInformationalCapabilities {
|
||||||
|
sampled_color_formats,
|
||||||
|
sampled_depth_formats,
|
||||||
|
limits: device.limits,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn required_depth_stencil_formats(depth: DepthStencilSupport) -> &'static [vk::Format] {
|
fn required_depth_stencil_formats(depth: DepthStencilSupport) -> &'static [vk::Format] {
|
||||||
match (depth.depth_bits, depth.stencil_bits) {
|
match (depth.depth_bits, depth.stencil_bits) {
|
||||||
(0, 0) => &[],
|
(0, 0) => &[],
|
||||||
@@ -796,6 +844,19 @@ fn required_depth_stencil_formats(depth: DepthStencilSupport) -> &'static [vk::F
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_depth_stencil_format(format: i32) -> bool {
|
||||||
|
matches!(
|
||||||
|
vk::Format::from_raw(format),
|
||||||
|
vk::Format::D16_UNORM
|
||||||
|
| vk::Format::X8_D24_UNORM_PACK32
|
||||||
|
| vk::Format::D32_SFLOAT
|
||||||
|
| vk::Format::S8_UINT
|
||||||
|
| vk::Format::D16_UNORM_S8_UINT
|
||||||
|
| vk::Format::D24_UNORM_S8_UINT
|
||||||
|
| vk::Format::D32_SFLOAT_S8_UINT
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn score_device(
|
fn score_device(
|
||||||
device: &VulkanPhysicalDeviceRecord,
|
device: &VulkanPhysicalDeviceRecord,
|
||||||
graphics_queue_family: u32,
|
graphics_queue_family: u32,
|
||||||
|
|||||||
Reference in New Issue
Block a user