aboutsummaryrefslogtreecommitdiff
path: root/adapters/fparkan-render-vulkan/src/policy.rs
diff options
context:
space:
mode:
Diffstat (limited to 'adapters/fparkan-render-vulkan/src/policy.rs')
-rw-r--r--adapters/fparkan-render-vulkan/src/policy.rs72
1 files changed, 70 insertions, 2 deletions
diff --git a/adapters/fparkan-render-vulkan/src/policy.rs b/adapters/fparkan-render-vulkan/src/policy.rs
index ef9f0c4..040cefb 100644
--- a/adapters/fparkan-render-vulkan/src/policy.rs
+++ b/adapters/fparkan-render-vulkan/src/policy.rs
@@ -1,4 +1,5 @@
use ash::vk;
+use fparkan_platform::{DepthStencilSupport, RenderRequest};
use fparkan_render::{validate_command_list, RenderCommand, RenderCommandList, RenderError};
use serde::Serialize;
@@ -182,6 +183,8 @@ pub struct VulkanPhysicalDeviceRecord {
pub present_modes: Vec<i32>,
/// Surface capabilities accepted by the target surface.
pub surface_capabilities: VulkanSwapchainSurfaceCapabilities,
+ /// Depth/stencil attachment formats supported by the device.
+ pub supported_depth_stencil_formats: Vec<i32>,
}
impl VulkanPhysicalDeviceRecord {
@@ -270,6 +273,13 @@ pub enum VulkanCapabilityError {
/// Device name that failed validation.
device: String,
},
+ /// No compatible depth/stencil attachment format exists for the render request.
+ MissingDepthStencilFormat {
+ /// Device name that failed validation.
+ device: String,
+ /// Requested depth/stencil profile.
+ requested: DepthStencilSupport,
+ },
}
impl std::fmt::Display for VulkanCapabilityError {
@@ -301,6 +311,12 @@ impl std::fmt::Display for VulkanCapabilityError {
f,
"Vulkan device {device} surface does not support COLOR_ATTACHMENT usage"
),
+ Self::MissingDepthStencilFormat { device, requested } => write!(
+ f,
+ "Vulkan device {device} lacks a depth/stencil attachment format for {}-bit depth and {}-bit stencil",
+ requested.depth_bits,
+ requested.stencil_bits
+ ),
}
}
}
@@ -316,6 +332,20 @@ impl std::error::Error for VulkanCapabilityError {}
pub fn select_physical_device(
devices: &[VulkanPhysicalDeviceRecord],
) -> Result<VulkanCapabilityReport, VulkanCapabilityError> {
+ select_physical_device_for_request(devices, &RenderRequest::conservative())
+}
+
+/// Selects a Vulkan physical device for a specific Stage 0 render request.
+///
+/// # Errors
+///
+/// Returns [`VulkanCapabilityError`] when no candidate satisfies the minimum
+/// API version, queue, swapchain-extension, surface-format or depth/stencil
+/// requirements for the requested profile.
+pub fn select_physical_device_for_request(
+ devices: &[VulkanPhysicalDeviceRecord],
+ render_request: &RenderRequest,
+) -> Result<VulkanCapabilityReport, VulkanCapabilityError> {
if devices.is_empty() {
return Err(VulkanCapabilityError::NoPhysicalDevice);
}
@@ -324,7 +354,7 @@ pub fn select_physical_device(
let mut rejected_devices = Vec::new();
let mut last_error = None;
for device in devices {
- let report = match validate_device(device) {
+ let report = match validate_device_for_request(device, render_request) {
Ok(report) => report,
Err(err) => {
rejected_devices.push(rejected_device_report(device, &err));
@@ -611,8 +641,9 @@ fn select_image_count(capabilities: VulkanSwapchainSurfaceCapabilities) -> u32 {
}
}
-pub(crate) fn validate_device(
+pub(crate) fn validate_device_for_request(
device: &VulkanPhysicalDeviceRecord,
+ render_request: &RenderRequest,
) -> Result<VulkanCapabilityReport, VulkanCapabilityError> {
if device.api_version < MIN_VULKAN_API_VERSION {
return Err(VulkanCapabilityError::ApiVersionTooLow {
@@ -640,6 +671,12 @@ pub(crate) fn validate_device(
device: device.name.clone(),
});
}
+ if !supports_depth_stencil_request(device, render_request.depth) {
+ return Err(VulkanCapabilityError::MissingDepthStencilFormat {
+ device: device.name.clone(),
+ requested: render_request.depth,
+ });
+ }
let (graphics_queue_family, present_queue_family) = select_queue_families(device)?;
let portability_subset = device.supports_extension(KHR_PORTABILITY_SUBSET_EXTENSION);
@@ -684,6 +721,7 @@ const fn capability_error_code(error: &VulkanCapabilityError) -> &'static str {
VulkanCapabilityError::MissingColorAttachmentUsage { .. } => {
"missing_color_attachment_usage"
}
+ VulkanCapabilityError::MissingDepthStencilFormat { .. } => "missing_depth_stencil_format",
}
}
@@ -728,6 +766,36 @@ fn supports_color_attachment_usage(capabilities: VulkanSwapchainSurfaceCapabilit
capabilities.supported_usage_flags & vk::ImageUsageFlags::COLOR_ATTACHMENT.as_raw() != 0
}
+fn supports_depth_stencil_request(
+ device: &VulkanPhysicalDeviceRecord,
+ depth: DepthStencilSupport,
+) -> bool {
+ if depth.depth_bits == 0 && depth.stencil_bits == 0 {
+ return true;
+ }
+ required_depth_stencil_formats(depth).iter().any(|format| {
+ device
+ .supported_depth_stencil_formats
+ .contains(&format.as_raw())
+ })
+}
+
+fn required_depth_stencil_formats(depth: DepthStencilSupport) -> &'static [vk::Format] {
+ match (depth.depth_bits, depth.stencil_bits) {
+ (0, 0) => &[],
+ (16, 0) => &[vk::Format::D16_UNORM, vk::Format::D32_SFLOAT],
+ (24, 0) => &[vk::Format::X8_D24_UNORM_PACK32, vk::Format::D32_SFLOAT],
+ (32, 0) => &[vk::Format::D32_SFLOAT],
+ (16, 8) => &[vk::Format::D16_UNORM_S8_UINT, vk::Format::D24_UNORM_S8_UINT],
+ (24, 8) => &[
+ vk::Format::D24_UNORM_S8_UINT,
+ vk::Format::D32_SFLOAT_S8_UINT,
+ ],
+ (32, 8) => &[vk::Format::D32_SFLOAT_S8_UINT],
+ _ => &[],
+ }
+}
+
fn score_device(
device: &VulkanPhysicalDeviceRecord,
graphics_queue_family: u32,