aboutsummaryrefslogtreecommitdiff
path: root/adapters/fparkan-render-vulkan/src/ffi
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2026-06-25 07:23:41 +0300
committerValentin Popov <valentin@popov.link>2026-06-25 10:45:40 +0300
commit5a60671bd6e437a728f2805dc94d14128723de90 (patch)
tree61c8af0dbf97a69f9e1b13853310c66738b2734b /adapters/fparkan-render-vulkan/src/ffi
parent5aff0b64e820728c9a3469445c496c38b63ec523 (diff)
downloadfparkan-5a60671bd6e437a728f2805dc94d14128723de90.tar.xz
fparkan-5a60671bd6e437a728f2805dc94d14128723de90.zip
fix(vulkan-policy): report sampled formats and limits
Diffstat (limited to 'adapters/fparkan-render-vulkan/src/ffi')
-rw-r--r--adapters/fparkan-render-vulkan/src/ffi/capabilities.rs44
-rw-r--r--adapters/fparkan-render-vulkan/src/ffi/tests.rs42
2 files changed, 82 insertions, 4 deletions
diff --git a/adapters/fparkan-render-vulkan/src/ffi/capabilities.rs b/adapters/fparkan-render-vulkan/src/ffi/capabilities.rs
index c0de225..40cd232 100644
--- a/adapters/fparkan-render-vulkan/src/ffi/capabilities.rs
+++ b/adapters/fparkan-render-vulkan/src/ffi/capabilities.rs
@@ -7,9 +7,9 @@ use std::ffi::CStr;
use super::{VulkanInstanceProbe, VulkanSurfaceProbe};
use crate::policy::{
compare_reports, plan_vulkan_swapchain, validate_device_for_request, VulkanCapabilityError,
- VulkanCapabilityReport, VulkanDeviceType, VulkanPhysicalDeviceRecord, VulkanQueueFamily,
- VulkanSurfaceFormat, VulkanSwapchainError, VulkanSwapchainPlan, VulkanSwapchainRequest,
- VulkanSwapchainSurfaceCapabilities,
+ VulkanCapabilityReport, VulkanDeviceLimits, VulkanDeviceType, VulkanPhysicalDeviceRecord,
+ VulkanQueueFamily, VulkanSurfaceFormat, VulkanSwapchainError, VulkanSwapchainPlan,
+ VulkanSwapchainRequest, VulkanSwapchainSurfaceCapabilities,
};
/// Live Vulkan device/surface capability probe.
@@ -242,6 +242,7 @@ fn live_device_candidate(
let present_modes = live_present_modes(surface, device, &name)?;
let surface_capabilities = live_surface_capabilities(surface, device, &name)?;
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
.iter()
.enumerate()
@@ -284,6 +285,13 @@ fn live_device_candidate(
present_modes: present_modes.clone(),
surface_capabilities,
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)
.map_err(VulkanRuntimeCapabilityError::Capability)?;
@@ -468,3 +476,33 @@ fn live_depth_stencil_formats(
.map(vk::Format::as_raw)
.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()
+}
diff --git a/adapters/fparkan-render-vulkan/src/ffi/tests.rs b/adapters/fparkan-render-vulkan/src/ffi/tests.rs
index 891789d..d472a28 100644
--- a/adapters/fparkan-render-vulkan/src/ffi/tests.rs
+++ b/adapters/fparkan-render-vulkan/src/ffi/tests.rs
@@ -318,6 +318,36 @@ fn capability_gate_respects_request_specific_depth_profiles() {
}
#[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]
fn capability_report_json_is_stable() {
let mut rejected = device("Rejected", VulkanDeviceType::IntegratedGpu, 0, true, false);
rejected.present_modes.clear();
@@ -329,7 +359,7 @@ fn capability_report_json_is_stable() {
assert_eq!(
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.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,
+ },
}
}