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,
|
take_runtime_children_with_validation_snapshot, take_runtime_owners_in_dependency_order,
|
||||||
validate_geometry_upload, world_material_pipeline_states, RollbackOnDrop,
|
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::cell::RefCell;
|
||||||
use std::rc::Rc;
|
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]
|
#[test]
|
||||||
fn material_category_and_transparency_preserve_world_state_in_either_order() {
|
fn material_category_and_transparency_preserve_world_state_in_either_order() {
|
||||||
let original = LegacyPipelineState {
|
let original = LegacyPipelineState {
|
||||||
@@ -3151,6 +3214,7 @@ mod tests {
|
|||||||
depth: LegacyDepthMode::TestWrite,
|
depth: LegacyDepthMode::TestWrite,
|
||||||
cull: LegacyCullMode::FrontFace,
|
cull: LegacyCullMode::FrontFace,
|
||||||
alpha_test: false,
|
alpha_test: false,
|
||||||
|
depth_bias: LegacyDepthBias::ProjectedDecal,
|
||||||
};
|
};
|
||||||
let (base, category_first) =
|
let (base, category_first) =
|
||||||
world_material_pipeline_states(original, 1, Some(true)).expect("category 1");
|
world_material_pipeline_states(original, 1, Some(true)).expect("category 1");
|
||||||
@@ -3162,14 +3226,17 @@ mod tests {
|
|||||||
assert!(base.alpha_test);
|
assert!(base.alpha_test);
|
||||||
assert_eq!(base.depth, LegacyDepthMode::TestWrite);
|
assert_eq!(base.depth, LegacyDepthMode::TestWrite);
|
||||||
assert_eq!(base.cull, LegacyCullMode::FrontFace);
|
assert_eq!(base.cull, LegacyCullMode::FrontFace);
|
||||||
|
assert_eq!(base.depth_bias, LegacyDepthBias::ProjectedDecal);
|
||||||
assert_eq!(category_first.depth, LegacyDepthMode::TestReadOnly);
|
assert_eq!(category_first.depth, LegacyDepthMode::TestReadOnly);
|
||||||
assert_eq!(category_first.cull, LegacyCullMode::FrontFace);
|
assert_eq!(category_first.cull, LegacyCullMode::FrontFace);
|
||||||
|
assert_eq!(category_first.depth_bias, LegacyDepthBias::ProjectedDecal);
|
||||||
|
|
||||||
let fixed_state = LegacyPipelineState {
|
let fixed_state = LegacyPipelineState {
|
||||||
blend: LegacyBlendMode::Additive,
|
blend: LegacyBlendMode::Additive,
|
||||||
depth: LegacyDepthMode::Disabled,
|
depth: LegacyDepthMode::Disabled,
|
||||||
cull: LegacyCullMode::Disabled,
|
cull: LegacyCullMode::Disabled,
|
||||||
alpha_test: false,
|
alpha_test: false,
|
||||||
|
depth_bias: LegacyDepthBias::Disabled,
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
world_material_pipeline_states(fixed_state, 1, None),
|
world_material_pipeline_states(fixed_state, 1, None),
|
||||||
|
|||||||
@@ -756,8 +756,8 @@ impl VulkanStaticMesh {
|
|||||||
material_index: 0,
|
material_index: 0,
|
||||||
lightmap_index: u8::MAX,
|
lightmap_index: u8::MAX,
|
||||||
batch_flags: 0,
|
batch_flags: 0,
|
||||||
terrain_base_only: false,
|
|
||||||
pipeline_state: LegacyPipelineState::default(),
|
pipeline_state: LegacyPipelineState::default(),
|
||||||
|
terrain_base_only: false,
|
||||||
alpha_test_reference: 0,
|
alpha_test_reference: 0,
|
||||||
}],
|
}],
|
||||||
}
|
}
|
||||||
@@ -992,8 +992,8 @@ mod static_mesh_tests {
|
|||||||
material_index: 0,
|
material_index: 0,
|
||||||
lightmap_index: u8::MAX,
|
lightmap_index: u8::MAX,
|
||||||
batch_flags: 0,
|
batch_flags: 0,
|
||||||
terrain_base_only: false,
|
|
||||||
pipeline_state: LegacyPipelineState::default(),
|
pipeline_state: LegacyPipelineState::default(),
|
||||||
|
terrain_base_only: false,
|
||||||
alpha_test_reference: 0,
|
alpha_test_reference: 0,
|
||||||
}],
|
}],
|
||||||
};
|
};
|
||||||
@@ -1023,8 +1023,8 @@ mod static_mesh_tests {
|
|||||||
material_index: 7,
|
material_index: 7,
|
||||||
lightmap_index: u8::MAX,
|
lightmap_index: u8::MAX,
|
||||||
batch_flags: 0,
|
batch_flags: 0,
|
||||||
terrain_base_only: false,
|
|
||||||
pipeline_state: LegacyPipelineState::default(),
|
pipeline_state: LegacyPipelineState::default(),
|
||||||
|
terrain_base_only: false,
|
||||||
alpha_test_reference: 0,
|
alpha_test_reference: 0,
|
||||||
},
|
},
|
||||||
VulkanStaticDrawRange {
|
VulkanStaticDrawRange {
|
||||||
@@ -1033,8 +1033,8 @@ mod static_mesh_tests {
|
|||||||
material_index: 2,
|
material_index: 2,
|
||||||
lightmap_index: u8::MAX,
|
lightmap_index: u8::MAX,
|
||||||
batch_flags: 0,
|
batch_flags: 0,
|
||||||
terrain_base_only: false,
|
|
||||||
pipeline_state: LegacyPipelineState::default(),
|
pipeline_state: LegacyPipelineState::default(),
|
||||||
|
terrain_base_only: false,
|
||||||
alpha_test_reference: 0,
|
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();
|
let mut screen_tl = materials[0].clone();
|
||||||
screen_tl.screen_tl = true;
|
screen_tl.screen_tl = true;
|
||||||
screen_tl.sky_far_depth = true;
|
screen_tl.sky_far_depth = true;
|
||||||
@@ -1109,11 +1114,9 @@ mod static_mesh_tests {
|
|||||||
far_sky.unlit = true;
|
far_sky.unlit = true;
|
||||||
far_sky.sky_far_depth = true;
|
far_sky.sky_far_depth = true;
|
||||||
assert_eq!(far_sky.encoded_material_mode(), 5.0);
|
assert_eq!(far_sky.encoded_material_mode(), 5.0);
|
||||||
|
let mut nebula_with_stars = far_sky.clone();
|
||||||
assert_eq!(
|
nebula_with_stars.sky_nebula_stars = true;
|
||||||
resolve_draw_texture_indices(&ranges, &materials),
|
assert_eq!(nebula_with_stars.encoded_material_mode(), 6.0);
|
||||||
Ok(vec![1, 0])
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut non_finite_base = materials.clone();
|
let mut non_finite_base = materials.clone();
|
||||||
non_finite_base[0].specular_rgb[0] = f32::NAN;
|
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() {
|
fn alpha_cutoff_is_dynamic_and_disabled_outside_alpha_test_pipeline() {
|
||||||
let base = VulkanStaticMesh::smoke_triangle().draw_ranges[0];
|
let base = VulkanStaticMesh::smoke_triangle().draw_ranges[0];
|
||||||
let disabled = VulkanStaticDrawRange {
|
let disabled = VulkanStaticDrawRange {
|
||||||
|
terrain_base_only: false,
|
||||||
alpha_test_reference: 200,
|
alpha_test_reference: 200,
|
||||||
..base
|
..base
|
||||||
};
|
};
|
||||||
@@ -1157,6 +1161,7 @@ mod static_mesh_tests {
|
|||||||
alpha_test: true,
|
alpha_test: true,
|
||||||
..LegacyPipelineState::default()
|
..LegacyPipelineState::default()
|
||||||
},
|
},
|
||||||
|
terrain_base_only: false,
|
||||||
alpha_test_reference: 128,
|
alpha_test_reference: 128,
|
||||||
..base
|
..base
|
||||||
};
|
};
|
||||||
@@ -1167,6 +1172,7 @@ mod static_mesh_tests {
|
|||||||
alpha_test: true,
|
alpha_test: true,
|
||||||
..LegacyPipelineState::default()
|
..LegacyPipelineState::default()
|
||||||
},
|
},
|
||||||
|
terrain_base_only: false,
|
||||||
alpha_test_reference: 0,
|
alpha_test_reference: 0,
|
||||||
..base
|
..base
|
||||||
};
|
};
|
||||||
@@ -1176,6 +1182,7 @@ mod static_mesh_tests {
|
|||||||
alpha_test: true,
|
alpha_test: true,
|
||||||
..LegacyPipelineState::default()
|
..LegacyPipelineState::default()
|
||||||
},
|
},
|
||||||
|
terrain_base_only: false,
|
||||||
alpha_test_reference: VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE,
|
alpha_test_reference: VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE,
|
||||||
..base
|
..base
|
||||||
};
|
};
|
||||||
@@ -1472,8 +1479,8 @@ pub struct VulkanSmokeRenderer {
|
|||||||
pub(super) material_selectors: Vec<u16>,
|
pub(super) material_selectors: Vec<u16>,
|
||||||
/// Whether the host-side specular records need a fence-safe GPU upload.
|
/// Whether the host-side specular records need a fence-safe GPU upload.
|
||||||
pub(super) material_specular_dirty: bool,
|
pub(super) material_specular_dirty: bool,
|
||||||
/// Encoded material mode pushed at offset 124: 0 lit, 1 unlit, 2 native
|
/// Encoded material mode pushed at offset 124: low bits select the
|
||||||
/// sky nebula/stars texture composite, 3 native lightmap composite.
|
/// combiner, bit 4 selects sky far-depth, and bit 8 selects screen/TL.
|
||||||
pub(super) material_unlit: Vec<f32>,
|
pub(super) material_unlit: Vec<f32>,
|
||||||
pub(super) readback_enabled: bool,
|
pub(super) readback_enabled: bool,
|
||||||
pub(super) camera: VulkanStaticCamera,
|
pub(super) camera: VulkanStaticCamera,
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
use ash::vk;
|
use ash::vk;
|
||||||
use fparkan_platform::DepthStencilSupport;
|
use fparkan_platform::DepthStencilSupport;
|
||||||
use fparkan_render::{
|
use fparkan_render::{
|
||||||
LegacyBlendMode, LegacyCullMode, LegacyDepthMode, LegacyPipelineState, PipelineKey,
|
LegacyBlendMode, LegacyCullMode, LegacyDepthBias, LegacyDepthMode, LegacyPipelineState,
|
||||||
|
PipelineKey,
|
||||||
};
|
};
|
||||||
use std::collections::BTreeMap;
|
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(
|
fn create_graphics_pipeline_cache(
|
||||||
device: &VulkanLogicalDeviceProbe,
|
device: &VulkanLogicalDeviceProbe,
|
||||||
render_pass: vk::RenderPass,
|
render_pass: vk::RenderPass,
|
||||||
@@ -1053,6 +1062,8 @@ fn create_graphics_pipeline(
|
|||||||
let viewport_state = vk::PipelineViewportStateCreateInfo::default()
|
let viewport_state = vk::PipelineViewportStateCreateInfo::default()
|
||||||
.viewports(&viewports)
|
.viewports(&viewports)
|
||||||
.scissors(&scissors);
|
.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()
|
let rasterization_state = vk::PipelineRasterizationStateCreateInfo::default()
|
||||||
.depth_clamp_enable(false)
|
.depth_clamp_enable(false)
|
||||||
.rasterizer_discard_enable(false)
|
.rasterizer_discard_enable(false)
|
||||||
@@ -1064,7 +1075,10 @@ fn create_graphics_pipeline(
|
|||||||
LegacyCullMode::FrontFace => vk::CullModeFlags::FRONT,
|
LegacyCullMode::FrontFace => vk::CullModeFlags::FRONT,
|
||||||
})
|
})
|
||||||
.front_face(vk::FrontFace::CLOCKWISE)
|
.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()
|
let multisample_state = vk::PipelineMultisampleStateCreateInfo::default()
|
||||||
.sample_shading_enable(false)
|
.sample_shading_enable(false)
|
||||||
.rasterization_samples(vk::SampleCountFlags::TYPE_1);
|
.rasterization_samples(vk::SampleCountFlags::TYPE_1);
|
||||||
@@ -1337,7 +1351,20 @@ fn destroy_partial_swapchain_resources(
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
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]
|
#[test]
|
||||||
fn world_viewport_depth_keeps_distant_geometry_in_front_of_screen_sun() {
|
fn world_viewport_depth_keeps_distant_geometry_in_front_of_screen_sun() {
|
||||||
|
|||||||
@@ -361,6 +361,17 @@ pub enum LegacyCullMode {
|
|||||||
FrontFace,
|
FrontFace,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Raster depth adjustment applied to one pipeline variant.
|
||||||
|
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||||
|
pub enum LegacyDepthBias {
|
||||||
|
/// Preserve the interpolated depth exactly.
|
||||||
|
#[default]
|
||||||
|
Disabled,
|
||||||
|
/// Move projected decals toward the camera so they pass against their
|
||||||
|
/// coplanar receiver under a less-or-equal depth test.
|
||||||
|
ProjectedDecal,
|
||||||
|
}
|
||||||
|
|
||||||
/// Legacy fixed-function state that changes graphics-pipeline structure.
|
/// Legacy fixed-function state that changes graphics-pipeline structure.
|
||||||
///
|
///
|
||||||
/// Alpha reference is deliberately not present: it is dynamic material data,
|
/// Alpha reference is deliberately not present: it is dynamic material data,
|
||||||
@@ -375,6 +386,8 @@ pub struct LegacyPipelineState {
|
|||||||
pub cull: LegacyCullMode,
|
pub cull: LegacyCullMode,
|
||||||
/// Whether alpha-test shader logic is enabled.
|
/// Whether alpha-test shader logic is enabled.
|
||||||
pub alpha_test: bool,
|
pub alpha_test: bool,
|
||||||
|
/// Raster depth bias for projected decals.
|
||||||
|
pub depth_bias: LegacyDepthBias,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LegacyPipelineState {
|
impl LegacyPipelineState {
|
||||||
@@ -405,15 +418,16 @@ impl LegacyPipelineState {
|
|||||||
/// Canonical, backend-neutral key for a graphics-pipeline variant.
|
/// Canonical, backend-neutral key for a graphics-pipeline variant.
|
||||||
///
|
///
|
||||||
/// The value is explicitly packed rather than hashed, so captures and caches
|
/// The value is explicitly packed rather than hashed, so captures and caches
|
||||||
/// remain stable across processes and Rust toolchain updates. Three bits are
|
/// remain stable across processes and Rust toolchain updates. Bits 0..7 encode
|
||||||
/// reserved for the five native material blend modes.
|
/// blend, depth, cull and alpha-test state; bit 8 distinguishes projected
|
||||||
|
/// decal depth bias.
|
||||||
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||||
pub struct PipelineKey(u8);
|
pub struct PipelineKey(u16);
|
||||||
|
|
||||||
impl PipelineKey {
|
impl PipelineKey {
|
||||||
/// Returns the canonical packed representation.
|
/// Returns the canonical packed representation.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn packed(self) -> u8 {
|
pub const fn packed(self) -> u16 {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -437,7 +451,11 @@ impl From<LegacyPipelineState> for PipelineKey {
|
|||||||
LegacyCullMode::BackFace => 1,
|
LegacyCullMode::BackFace => 1,
|
||||||
LegacyCullMode::FrontFace => 2,
|
LegacyCullMode::FrontFace => 2,
|
||||||
};
|
};
|
||||||
Self(blend | (depth << 3) | (cull << 5) | (u8::from(state.alpha_test) << 7))
|
let depth_bias = match state.depth_bias {
|
||||||
|
LegacyDepthBias::Disabled => 0,
|
||||||
|
LegacyDepthBias::ProjectedDecal => 1 << 8,
|
||||||
|
};
|
||||||
|
Self(blend | (depth << 3) | (cull << 5) | (u16::from(state.alpha_test) << 7) | depth_bias)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -613,6 +631,24 @@ mod tests {
|
|||||||
assert_eq!(base.with_material_category(5), None);
|
assert_eq!(base.with_material_category(5), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn projected_decal_bias_is_a_distinct_preserved_pipeline_state() {
|
||||||
|
let ordinary = LegacyPipelineState::default();
|
||||||
|
let decal = LegacyPipelineState {
|
||||||
|
depth_bias: LegacyDepthBias::ProjectedDecal,
|
||||||
|
..ordinary
|
||||||
|
};
|
||||||
|
assert_eq!(ordinary.depth_bias, LegacyDepthBias::Disabled);
|
||||||
|
assert_ne!(PipelineKey::from(ordinary), PipelineKey::from(decal));
|
||||||
|
assert_eq!(
|
||||||
|
decal
|
||||||
|
.with_material_category(1)
|
||||||
|
.expect("native category is represented")
|
||||||
|
.depth_bias,
|
||||||
|
LegacyDepthBias::ProjectedDecal
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn native_material_categories_have_distinct_pipeline_keys() {
|
fn native_material_categories_have_distinct_pipeline_keys() {
|
||||||
let base = LegacyPipelineState {
|
let base = LegacyPipelineState {
|
||||||
|
|||||||
Reference in new issue
Block a user