fix(render): preserve projected shadow depth bias in Vulkan pipelines
This commit is contained in:
4 files changed
+157
-20
No files matched your search
@@ -2577,7 +2577,9 @@ mod tests {
|
||||
take_runtime_children_with_validation_snapshot, take_runtime_owners_in_dependency_order,
|
||||
validate_geometry_upload, world_material_pipeline_states, RollbackOnDrop,
|
||||
};
|
||||
use fparkan_render::{LegacyBlendMode, LegacyCullMode, LegacyDepthMode, LegacyPipelineState};
|
||||
use fparkan_render::{
|
||||
LegacyBlendMode, LegacyCullMode, LegacyDepthBias, LegacyDepthMode, LegacyPipelineState,
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
@@ -3144,6 +3146,67 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn control_fx_queue_follows_opaque_and_sky_without_reactivating_empty_ranges() {
|
||||
const SCREEN_GRADIENT: usize = 0;
|
||||
const CONTROL_FX: usize = 1;
|
||||
const TERRAIN: usize = 2;
|
||||
const BUILDING: usize = 3;
|
||||
const SHADOW: usize = 4;
|
||||
const NEBULA: usize = 5;
|
||||
const DOME: usize = 6;
|
||||
const CLOUDS: usize = 7;
|
||||
const EMPTY_CONTROL_FX: usize = 8;
|
||||
const SUN: usize = 9;
|
||||
const WEATHER: usize = 10;
|
||||
let mut ranges = (0..11)
|
||||
.map(|index| VulkanStaticDrawRange {
|
||||
first_index: index * 3,
|
||||
index_count: 3,
|
||||
material_index: 0,
|
||||
lightmap_index: u8::MAX,
|
||||
batch_flags: 0,
|
||||
pipeline_state: LegacyPipelineState::default(),
|
||||
terrain_base_only: false,
|
||||
alpha_test_reference: 0,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
ranges[EMPTY_CONTROL_FX].index_count = 0;
|
||||
let mut world_queue = vec![None; ranges.len()];
|
||||
world_queue[TERRAIN] = Some(false);
|
||||
world_queue[BUILDING] = Some(false);
|
||||
world_queue[CONTROL_FX] = Some(true);
|
||||
world_queue[EMPTY_CONTROL_FX] = Some(true);
|
||||
let mut sort_keys = vec![None; ranges.len()];
|
||||
sort_keys[CONTROL_FX] = Some(20.0);
|
||||
sort_keys[EMPTY_CONTROL_FX] = Some(30.0);
|
||||
|
||||
let order = sorted_world_draw_order(
|
||||
ranges.len(),
|
||||
&ranges,
|
||||
&world_queue,
|
||||
&sort_keys,
|
||||
&[NEBULA, DOME, CLOUDS],
|
||||
);
|
||||
assert_eq!(
|
||||
order,
|
||||
vec![
|
||||
SCREEN_GRADIENT,
|
||||
TERRAIN,
|
||||
BUILDING,
|
||||
SHADOW,
|
||||
NEBULA,
|
||||
DOME,
|
||||
CLOUDS,
|
||||
CONTROL_FX,
|
||||
EMPTY_CONTROL_FX,
|
||||
SUN,
|
||||
WEATHER,
|
||||
]
|
||||
);
|
||||
assert_eq!(ranges[EMPTY_CONTROL_FX].index_count, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn material_category_and_transparency_preserve_world_state_in_either_order() {
|
||||
let original = LegacyPipelineState {
|
||||
@@ -3151,6 +3214,7 @@ mod tests {
|
||||
depth: LegacyDepthMode::TestWrite,
|
||||
cull: LegacyCullMode::FrontFace,
|
||||
alpha_test: false,
|
||||
depth_bias: LegacyDepthBias::ProjectedDecal,
|
||||
};
|
||||
let (base, category_first) =
|
||||
world_material_pipeline_states(original, 1, Some(true)).expect("category 1");
|
||||
@@ -3162,14 +3226,17 @@ mod tests {
|
||||
assert!(base.alpha_test);
|
||||
assert_eq!(base.depth, LegacyDepthMode::TestWrite);
|
||||
assert_eq!(base.cull, LegacyCullMode::FrontFace);
|
||||
assert_eq!(base.depth_bias, LegacyDepthBias::ProjectedDecal);
|
||||
assert_eq!(category_first.depth, LegacyDepthMode::TestReadOnly);
|
||||
assert_eq!(category_first.cull, LegacyCullMode::FrontFace);
|
||||
assert_eq!(category_first.depth_bias, LegacyDepthBias::ProjectedDecal);
|
||||
|
||||
let fixed_state = LegacyPipelineState {
|
||||
blend: LegacyBlendMode::Additive,
|
||||
depth: LegacyDepthMode::Disabled,
|
||||
cull: LegacyCullMode::Disabled,
|
||||
alpha_test: false,
|
||||
depth_bias: LegacyDepthBias::Disabled,
|
||||
};
|
||||
assert_eq!(
|
||||
world_material_pipeline_states(fixed_state, 1, None),
|
||||
|
||||
@@ -756,8 +756,8 @@ impl VulkanStaticMesh {
|
||||
material_index: 0,
|
||||
lightmap_index: u8::MAX,
|
||||
batch_flags: 0,
|
||||
terrain_base_only: false,
|
||||
pipeline_state: LegacyPipelineState::default(),
|
||||
terrain_base_only: false,
|
||||
alpha_test_reference: 0,
|
||||
}],
|
||||
}
|
||||
@@ -992,8 +992,8 @@ mod static_mesh_tests {
|
||||
material_index: 0,
|
||||
lightmap_index: u8::MAX,
|
||||
batch_flags: 0,
|
||||
terrain_base_only: false,
|
||||
pipeline_state: LegacyPipelineState::default(),
|
||||
terrain_base_only: false,
|
||||
alpha_test_reference: 0,
|
||||
}],
|
||||
};
|
||||
@@ -1023,8 +1023,8 @@ mod static_mesh_tests {
|
||||
material_index: 7,
|
||||
lightmap_index: u8::MAX,
|
||||
batch_flags: 0,
|
||||
terrain_base_only: false,
|
||||
pipeline_state: LegacyPipelineState::default(),
|
||||
terrain_base_only: false,
|
||||
alpha_test_reference: 0,
|
||||
},
|
||||
VulkanStaticDrawRange {
|
||||
@@ -1033,8 +1033,8 @@ mod static_mesh_tests {
|
||||
material_index: 2,
|
||||
lightmap_index: u8::MAX,
|
||||
batch_flags: 0,
|
||||
terrain_base_only: false,
|
||||
pipeline_state: LegacyPipelineState::default(),
|
||||
terrain_base_only: false,
|
||||
alpha_test_reference: 0,
|
||||
},
|
||||
];
|
||||
@@ -1101,6 +1101,11 @@ mod static_mesh_tests {
|
||||
},
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
resolve_draw_texture_indices(&ranges, &materials),
|
||||
Ok(vec![1, 0])
|
||||
);
|
||||
|
||||
let mut screen_tl = materials[0].clone();
|
||||
screen_tl.screen_tl = true;
|
||||
screen_tl.sky_far_depth = true;
|
||||
@@ -1109,11 +1114,9 @@ mod static_mesh_tests {
|
||||
far_sky.unlit = true;
|
||||
far_sky.sky_far_depth = true;
|
||||
assert_eq!(far_sky.encoded_material_mode(), 5.0);
|
||||
|
||||
assert_eq!(
|
||||
resolve_draw_texture_indices(&ranges, &materials),
|
||||
Ok(vec![1, 0])
|
||||
);
|
||||
let mut nebula_with_stars = far_sky.clone();
|
||||
nebula_with_stars.sky_nebula_stars = true;
|
||||
assert_eq!(nebula_with_stars.encoded_material_mode(), 6.0);
|
||||
|
||||
let mut non_finite_base = materials.clone();
|
||||
non_finite_base[0].specular_rgb[0] = f32::NAN;
|
||||
@@ -1149,6 +1152,7 @@ mod static_mesh_tests {
|
||||
fn alpha_cutoff_is_dynamic_and_disabled_outside_alpha_test_pipeline() {
|
||||
let base = VulkanStaticMesh::smoke_triangle().draw_ranges[0];
|
||||
let disabled = VulkanStaticDrawRange {
|
||||
terrain_base_only: false,
|
||||
alpha_test_reference: 200,
|
||||
..base
|
||||
};
|
||||
@@ -1157,6 +1161,7 @@ mod static_mesh_tests {
|
||||
alpha_test: true,
|
||||
..LegacyPipelineState::default()
|
||||
},
|
||||
terrain_base_only: false,
|
||||
alpha_test_reference: 128,
|
||||
..base
|
||||
};
|
||||
@@ -1167,6 +1172,7 @@ mod static_mesh_tests {
|
||||
alpha_test: true,
|
||||
..LegacyPipelineState::default()
|
||||
},
|
||||
terrain_base_only: false,
|
||||
alpha_test_reference: 0,
|
||||
..base
|
||||
};
|
||||
@@ -1176,6 +1182,7 @@ mod static_mesh_tests {
|
||||
alpha_test: true,
|
||||
..LegacyPipelineState::default()
|
||||
},
|
||||
terrain_base_only: false,
|
||||
alpha_test_reference: VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE,
|
||||
..base
|
||||
};
|
||||
@@ -1472,8 +1479,8 @@ pub struct VulkanSmokeRenderer {
|
||||
pub(super) material_selectors: Vec<u16>,
|
||||
/// Whether the host-side specular records need a fence-safe GPU upload.
|
||||
pub(super) material_specular_dirty: bool,
|
||||
/// Encoded material mode pushed at offset 124: 0 lit, 1 unlit, 2 native
|
||||
/// sky nebula/stars texture composite, 3 native lightmap composite.
|
||||
/// Encoded material mode pushed at offset 124: low bits select the
|
||||
/// combiner, bit 4 selects sky far-depth, and bit 8 selects screen/TL.
|
||||
pub(super) material_unlit: Vec<f32>,
|
||||
pub(super) readback_enabled: bool,
|
||||
pub(super) camera: VulkanStaticCamera,
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
use ash::vk;
|
||||
use fparkan_platform::DepthStencilSupport;
|
||||
use fparkan_render::{
|
||||
LegacyBlendMode, LegacyCullMode, LegacyDepthMode, LegacyPipelineState, PipelineKey,
|
||||
LegacyBlendMode, LegacyCullMode, LegacyDepthBias, LegacyDepthMode, LegacyPipelineState,
|
||||
PipelineKey,
|
||||
};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
@@ -935,6 +936,14 @@ pub(super) fn draw_viewport(extent: (u32, u32), material_mode: f32) -> vk::Viewp
|
||||
}
|
||||
}
|
||||
|
||||
fn depth_bias_parameters(depth_bias: LegacyDepthBias) -> (bool, f32, f32) {
|
||||
match depth_bias {
|
||||
LegacyDepthBias::Disabled => (false, 0.0, 0.0),
|
||||
// shortcut: Vulkan constantFactor=-1.0/slopeFactor=0.0 is empirical; verify native raster state before claiming parity.
|
||||
LegacyDepthBias::ProjectedDecal => (true, -1.0, 0.0),
|
||||
}
|
||||
}
|
||||
|
||||
fn create_graphics_pipeline_cache(
|
||||
device: &VulkanLogicalDeviceProbe,
|
||||
render_pass: vk::RenderPass,
|
||||
@@ -1053,6 +1062,8 @@ fn create_graphics_pipeline(
|
||||
let viewport_state = vk::PipelineViewportStateCreateInfo::default()
|
||||
.viewports(&viewports)
|
||||
.scissors(&scissors);
|
||||
let (depth_bias_enable, depth_bias_constant_factor, depth_bias_slope_factor) =
|
||||
depth_bias_parameters(state.depth_bias);
|
||||
let rasterization_state = vk::PipelineRasterizationStateCreateInfo::default()
|
||||
.depth_clamp_enable(false)
|
||||
.rasterizer_discard_enable(false)
|
||||
@@ -1064,7 +1075,10 @@ fn create_graphics_pipeline(
|
||||
LegacyCullMode::FrontFace => vk::CullModeFlags::FRONT,
|
||||
})
|
||||
.front_face(vk::FrontFace::CLOCKWISE)
|
||||
.depth_bias_enable(false);
|
||||
.depth_bias_enable(depth_bias_enable)
|
||||
.depth_bias_constant_factor(depth_bias_constant_factor)
|
||||
.depth_bias_slope_factor(depth_bias_slope_factor)
|
||||
.depth_bias_clamp(0.0);
|
||||
let multisample_state = vk::PipelineMultisampleStateCreateInfo::default()
|
||||
.sample_shading_enable(false)
|
||||
.rasterization_samples(vk::SampleCountFlags::TYPE_1);
|
||||
@@ -1337,7 +1351,20 @@ fn destroy_partial_swapchain_resources(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::draw_viewport;
|
||||
use super::{depth_bias_parameters, draw_viewport};
|
||||
use fparkan_render::LegacyDepthBias;
|
||||
|
||||
#[test]
|
||||
fn projected_decal_bias_parameters_use_empirical_vulkan_factors() {
|
||||
assert_eq!(
|
||||
depth_bias_parameters(LegacyDepthBias::Disabled),
|
||||
(false, 0.0, 0.0)
|
||||
);
|
||||
assert_eq!(
|
||||
depth_bias_parameters(LegacyDepthBias::ProjectedDecal),
|
||||
(true, -1.0, 0.0)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn world_viewport_depth_keeps_distant_geometry_in_front_of_screen_sun() {
|
||||
|
||||
Reference in new issue
Block a user