feat(vulkan): add alpha test shader path
This commit is contained in:
@@ -678,6 +678,14 @@ impl VulkanSmokeRenderer {
|
||||
std::slice::from_ref(descriptor_set),
|
||||
&[],
|
||||
);
|
||||
let alpha_cutoff = range.alpha_test_cutoff().to_ne_bytes();
|
||||
device.device().cmd_push_constants(
|
||||
command_buffer,
|
||||
resources.pipeline_layout,
|
||||
vk::ShaderStageFlags::FRAGMENT,
|
||||
0,
|
||||
&alpha_cutoff,
|
||||
);
|
||||
device.device().cmd_draw_indexed(
|
||||
command_buffer,
|
||||
range.index_count,
|
||||
|
||||
@@ -73,6 +73,8 @@ pub struct VulkanStaticDrawRange {
|
||||
pub material_index: u16,
|
||||
/// Backend-neutral fixed-function state for this source range.
|
||||
pub pipeline_state: LegacyPipelineState,
|
||||
/// Alpha-test reference in legacy 0..=255 units; dynamic material data.
|
||||
pub alpha_test_reference: u8,
|
||||
}
|
||||
|
||||
impl VulkanStaticDrawRange {
|
||||
@@ -81,6 +83,16 @@ impl VulkanStaticDrawRange {
|
||||
pub fn pipeline_key(self) -> PipelineKey {
|
||||
self.pipeline_state.into()
|
||||
}
|
||||
|
||||
/// Returns the normalized cutoff consumed by the fragment shader.
|
||||
#[must_use]
|
||||
pub fn alpha_test_cutoff(self) -> f32 {
|
||||
if self.pipeline_state.alpha_test {
|
||||
f32::from(self.alpha_test_reference) / 255.0
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// One diffuse material texture keyed by an original MSH batch selector.
|
||||
@@ -185,6 +197,7 @@ impl VulkanStaticMesh {
|
||||
index_count: 3,
|
||||
material_index: 0,
|
||||
pipeline_state: LegacyPipelineState::default(),
|
||||
alpha_test_reference: 0,
|
||||
}],
|
||||
}
|
||||
}
|
||||
@@ -252,6 +265,7 @@ mod static_mesh_tests {
|
||||
index_count: 2,
|
||||
material_index: 0,
|
||||
pipeline_state: LegacyPipelineState::default(),
|
||||
alpha_test_reference: 0,
|
||||
}],
|
||||
};
|
||||
let out_of_range_index = VulkanStaticMesh {
|
||||
@@ -279,12 +293,14 @@ mod static_mesh_tests {
|
||||
index_count: 3,
|
||||
material_index: 7,
|
||||
pipeline_state: LegacyPipelineState::default(),
|
||||
alpha_test_reference: 0,
|
||||
},
|
||||
VulkanStaticDrawRange {
|
||||
first_index: 3,
|
||||
index_count: 3,
|
||||
material_index: 2,
|
||||
pipeline_state: LegacyPipelineState::default(),
|
||||
alpha_test_reference: 0,
|
||||
},
|
||||
];
|
||||
let texture = || VulkanStaticTexture {
|
||||
@@ -323,6 +339,25 @@ mod static_mesh_tests {
|
||||
assert_eq!(base.pipeline_key().packed(), 0);
|
||||
assert_ne!(base.pipeline_key(), blended.pipeline_key());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn alpha_cutoff_is_dynamic_and_disabled_outside_alpha_test_pipeline() {
|
||||
let base = VulkanStaticMesh::smoke_triangle().draw_ranges[0];
|
||||
let disabled = VulkanStaticDrawRange {
|
||||
alpha_test_reference: 200,
|
||||
..base
|
||||
};
|
||||
let enabled = VulkanStaticDrawRange {
|
||||
pipeline_state: LegacyPipelineState {
|
||||
alpha_test: true,
|
||||
..LegacyPipelineState::default()
|
||||
},
|
||||
alpha_test_reference: 128,
|
||||
..base
|
||||
};
|
||||
assert_eq!(disabled.alpha_test_cutoff(), 0.0);
|
||||
assert_eq!(enabled.alpha_test_cutoff(), 128.0 / 255.0);
|
||||
}
|
||||
}
|
||||
|
||||
/// Shared bootstrap progress used to report partial renderer startup evidence.
|
||||
|
||||
@@ -381,7 +381,13 @@ fn create_pipeline_layout(
|
||||
descriptor_set_layout: vk::DescriptorSetLayout,
|
||||
) -> Result<vk::PipelineLayout, VulkanSmokeRendererError> {
|
||||
let set_layouts = [descriptor_set_layout];
|
||||
let create_info = vk::PipelineLayoutCreateInfo::default().set_layouts(&set_layouts);
|
||||
let push_constant_ranges = [vk::PushConstantRange::default()
|
||||
.stage_flags(vk::ShaderStageFlags::FRAGMENT)
|
||||
.offset(0)
|
||||
.size(u32::try_from(std::mem::size_of::<f32>()).unwrap_or(u32::MAX))];
|
||||
let create_info = vk::PipelineLayoutCreateInfo::default()
|
||||
.set_layouts(&set_layouts)
|
||||
.push_constant_ranges(&push_constant_ranges);
|
||||
// SAFETY: The descriptor-set layout belongs to this live logical device.
|
||||
unsafe { device.device().create_pipeline_layout(&create_info, None) }.map_err(|error| {
|
||||
VulkanSmokeRendererError::VulkanOperation {
|
||||
@@ -562,12 +568,6 @@ fn create_graphics_pipeline(
|
||||
extent: (u32, u32),
|
||||
state: LegacyPipelineState,
|
||||
) -> Result<vk::Pipeline, VulkanSmokeRendererError> {
|
||||
if state.alpha_test {
|
||||
return Err(VulkanSmokeRendererError::InvalidStaticMesh {
|
||||
context:
|
||||
"static renderer has no alpha-test shader variant for requested pipeline state",
|
||||
});
|
||||
}
|
||||
let vertex_shader = create_shader_module(device, TRIANGLE_VERTEX_SHADER_WORDS)?;
|
||||
let fragment_shader = match create_shader_module(device, TRIANGLE_FRAGMENT_SHADER_WORDS) {
|
||||
Ok(module) => module,
|
||||
|
||||
@@ -669,11 +669,11 @@ fn triangle_shader_manifest_hashes_are_stable() {
|
||||
assert!(!report.modules[0].interface_hash.is_empty());
|
||||
assert_eq!(
|
||||
report.modules[1].sha256,
|
||||
"49dae3e1c46d5d23cccf3b161c36ea0b3a606e89c2289dbfed3e4fe991eb8556"
|
||||
"536a5c9a4389f9d34ca11a25f20d0acbc53d3eb0782c18375326647319336a85"
|
||||
);
|
||||
assert_eq!(
|
||||
report.manifest_hash,
|
||||
"038ecdb57832ac2d45a1ca6da5ec058b34f4f31b7170aa68fa612ac9d0ae7565"
|
||||
"5a16fb791e86bb790cd2d85151627e0d39193c5c073a9294130f149d4ff5ba58"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user