feat(render): sample original TEXM in Vulkan
This commit is contained in:
@@ -1 +1 @@
|
|||||||
{"schema":2,"target_env":"vulkan1.1","compiler":{"name":"glslangValidator","version":"11:16.3.0","binary_sha256":"9bcd69d830b350aaa6e2254915ff74e46070e217b67f38daad27c1fc1f22910f"},"validator":{"name":"spirv-val","version":"SPIRV-Tools v2026.2 unknown hash, 2026-04-29T17:02:58+00:00","binary_sha256":"f6d5b96ff19f073f3af0c0bcfa0c18702d288d3ec598efc242d01cd104d8354f"},"modules":[{"name":"triangle.vert","stage":"vertex","entry_point":"main","source_path":"adapters/fparkan-render-vulkan/shaders/triangle.vert","source_sha256":"1e57f14d193fc61457c0749081c452ad25669998913107df12f3ccc3c33e0341","spirv_path":"adapters/fparkan-render-vulkan/shaders/triangle.vert.spv","word_count":253,"sha256":"4d3ceca7b42ebc971d831b0a0d816457397bd9aeda47fb8d44c4b1aeaa5e7ba0","descriptor_sets":0,"push_constant_bytes":0,"compile_command":"glslangValidator -V --target-env vulkan1.1 -S vert -e main adapters/fparkan-render-vulkan/shaders/triangle.vert -o adapters/fparkan-render-vulkan/shaders/triangle.vert.spv","validate_command":"spirv-val --target-env vulkan1.1 adapters/fparkan-render-vulkan/shaders/triangle.vert.spv","interface_hash":"23e1d3d9d32e7f7ec0b9ca87f8b86be8f8363c7eb5d745fc5a157cb8433eb138"},{"name":"triangle.frag","stage":"fragment","entry_point":"main","source_path":"adapters/fparkan-render-vulkan/shaders/triangle.frag","source_sha256":"f19e74d001d07fb537d4b0f9e621f9b8bc40eeb68816130220853abea6bd4445","spirv_path":"adapters/fparkan-render-vulkan/shaders/triangle.frag.spv","word_count":125,"sha256":"5a7441be03cd3c25d557268b2e58d5aa50504c87bffcb4c3fd7cbcf007db0b96","descriptor_sets":0,"push_constant_bytes":0,"compile_command":"glslangValidator -V --target-env vulkan1.1 -S frag -e main adapters/fparkan-render-vulkan/shaders/triangle.frag -o adapters/fparkan-render-vulkan/shaders/triangle.frag.spv","validate_command":"spirv-val --target-env vulkan1.1 adapters/fparkan-render-vulkan/shaders/triangle.frag.spv","interface_hash":"f09342c22d58c8768151ab8579e54e49af586434a4005d16a24e816d881a64f0"}],"manifest_hash":"11e3feb65200ebd2ac87b7e776e9c6433a5da9d71a651bfadea89a51be17ff05"}
|
{"schema":2,"target_env":"vulkan1.1","compiler":{"name":"glslangValidator","version":"11:16.3.0","binary_sha256":"9bcd69d830b350aaa6e2254915ff74e46070e217b67f38daad27c1fc1f22910f"},"validator":{"name":"spirv-val","version":"SPIRV-Tools v2026.2 unknown hash, 2026-04-29T17:02:58+00:00","binary_sha256":"f6d5b96ff19f073f3af0c0bcfa0c18702d288d3ec598efc242d01cd104d8354f"},"modules":[{"name":"triangle.vert","stage":"vertex","entry_point":"main","source_path":"adapters/fparkan-render-vulkan/shaders/triangle.vert","source_sha256":"82f9ee39a30b094203041205954576ca820d75771421bb27ddd300359e4e9043","spirv_path":"adapters/fparkan-render-vulkan/shaders/triangle.vert.spv","word_count":290,"sha256":"1984662f78873b70135ec444ccd86d86fa66dfca3f615d19ddaf0cda1587d4cf","descriptor_sets":0,"push_constant_bytes":0,"compile_command":"glslangValidator -V --target-env vulkan1.1 -S vert -e main adapters/fparkan-render-vulkan/shaders/triangle.vert -o adapters/fparkan-render-vulkan/shaders/triangle.vert.spv","validate_command":"spirv-val --target-env vulkan1.1 adapters/fparkan-render-vulkan/shaders/triangle.vert.spv","interface_hash":"23e1d3d9d32e7f7ec0b9ca87f8b86be8f8363c7eb5d745fc5a157cb8433eb138"},{"name":"triangle.frag","stage":"fragment","entry_point":"main","source_path":"adapters/fparkan-render-vulkan/shaders/triangle.frag","source_sha256":"70b600a0c79b6cdee1747a47caf7854bbe0bb9a693b3fe29345e659df549d96f","spirv_path":"adapters/fparkan-render-vulkan/shaders/triangle.frag.spv","word_count":197,"sha256":"49dae3e1c46d5d23cccf3b161c36ea0b3a606e89c2289dbfed3e4fe991eb8556","descriptor_sets":1,"push_constant_bytes":0,"compile_command":"glslangValidator -V --target-env vulkan1.1 -S frag -e main adapters/fparkan-render-vulkan/shaders/triangle.frag -o adapters/fparkan-render-vulkan/shaders/triangle.frag.spv","validate_command":"spirv-val --target-env vulkan1.1 adapters/fparkan-render-vulkan/shaders/triangle.frag.spv","interface_hash":"446615153811b02f05622dc3cdeae998461a6a225a3d2098bba0e0d158a21027"}],"manifest_hash":"038ecdb57832ac2d45a1ca6da5ec058b34f4f31b7170aa68fa612ac9d0ae7565"}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
layout(location = 0) in vec3 in_color;
|
layout(location = 0) in vec3 in_color;
|
||||||
|
layout(location = 1) in vec2 in_uv;
|
||||||
layout(location = 0) out vec4 out_color;
|
layout(location = 0) out vec4 out_color;
|
||||||
|
|
||||||
|
layout(set = 0, binding = 0) uniform sampler2D base_color;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
out_color = vec4(in_color, 1.0);
|
out_color = texture(base_color, in_uv) * vec4(in_color, 1.0);
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@@ -2,10 +2,13 @@
|
|||||||
|
|
||||||
layout(location = 0) in vec2 in_position;
|
layout(location = 0) in vec2 in_position;
|
||||||
layout(location = 1) in vec3 in_color;
|
layout(location = 1) in vec3 in_color;
|
||||||
|
layout(location = 2) in vec2 in_uv;
|
||||||
|
|
||||||
layout(location = 0) out vec3 out_color;
|
layout(location = 0) out vec3 out_color;
|
||||||
|
layout(location = 1) out vec2 out_uv;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
out_color = in_color;
|
out_color = in_color;
|
||||||
|
out_uv = in_uv;
|
||||||
gl_Position = vec4(in_position, 0.0, 1.0);
|
gl_Position = vec4(in_position, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@@ -100,6 +100,13 @@ pub fn project_msh_to_static_mesh(
|
|||||||
(position[2] - center_z) * scale,
|
(position[2] - center_z) * scale,
|
||||||
],
|
],
|
||||||
color: [0.82, 0.72, 0.31],
|
color: [0.82, 0.72, 0.31],
|
||||||
|
// The exact fixed-point normalization of Res5 is still under
|
||||||
|
// disassembly. Until then the asset viewer uses its documented XZ
|
||||||
|
// planar projection, rather than inventing a scale for raw i16 UV0.
|
||||||
|
uv: [
|
||||||
|
(position[0] - center_x) / extent + 0.5,
|
||||||
|
(position[2] - center_z) / extent + 0.5,
|
||||||
|
],
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,8 @@ const EXT_DEBUG_UTILS_EXTENSION: &str = "VK_EXT_debug_utils";
|
|||||||
const VALIDATION_LAYER_NAME: &str = "VK_LAYER_KHRONOS_validation";
|
const VALIDATION_LAYER_NAME: &str = "VK_LAYER_KHRONOS_validation";
|
||||||
pub(crate) const SPIRV_MAGIC: u32 = 0x0723_0203;
|
pub(crate) const SPIRV_MAGIC: u32 = 0x0723_0203;
|
||||||
pub(crate) const SPIRV_VERSION_1_0: u32 = 0x0001_0000;
|
pub(crate) const SPIRV_VERSION_1_0: u32 = 0x0001_0000;
|
||||||
pub(crate) const TRIANGLE_VERTEX_SHADER_WORDS: &[u32] = &[
|
#[allow(dead_code)]
|
||||||
|
const LEGACY_TRIANGLE_VERTEX_SHADER_WORDS: &[u32] = &[
|
||||||
0x0723_0203,
|
0x0723_0203,
|
||||||
0x0001_0300,
|
0x0001_0300,
|
||||||
0x0008_000b,
|
0x0008_000b,
|
||||||
@@ -345,7 +346,8 @@ pub(crate) const TRIANGLE_VERTEX_SHADER_WORDS: &[u32] = &[
|
|||||||
0x0001_00fd,
|
0x0001_00fd,
|
||||||
0x0001_0038,
|
0x0001_0038,
|
||||||
];
|
];
|
||||||
pub(crate) const TRIANGLE_FRAGMENT_SHADER_WORDS: &[u32] = &[
|
#[allow(dead_code)]
|
||||||
|
const LEGACY_TRIANGLE_FRAGMENT_SHADER_WORDS: &[u32] = &[
|
||||||
0x0723_0203,
|
0x0723_0203,
|
||||||
0x0001_0300,
|
0x0001_0300,
|
||||||
0x0008_000b,
|
0x0008_000b,
|
||||||
@@ -473,5 +475,28 @@ pub(crate) const TRIANGLE_FRAGMENT_SHADER_WORDS: &[u32] = &[
|
|||||||
0x0001_0038,
|
0x0001_0038,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const fn spirv_words<const WORD_COUNT: usize>(bytes: &[u8]) -> [u32; WORD_COUNT] {
|
||||||
|
let mut words = [0_u32; WORD_COUNT];
|
||||||
|
let mut index = 0;
|
||||||
|
while index < WORD_COUNT {
|
||||||
|
let offset = index * 4;
|
||||||
|
words[index] = u32::from_le_bytes([
|
||||||
|
bytes[offset],
|
||||||
|
bytes[offset + 1],
|
||||||
|
bytes[offset + 2],
|
||||||
|
bytes[offset + 3],
|
||||||
|
]);
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
words
|
||||||
|
}
|
||||||
|
|
||||||
|
static TRIANGLE_VERTEX_SHADER_DATA: [u32; 290] =
|
||||||
|
spirv_words(include_bytes!("../shaders/triangle.vert.spv"));
|
||||||
|
static TRIANGLE_FRAGMENT_SHADER_DATA: [u32; 197] =
|
||||||
|
spirv_words(include_bytes!("../shaders/triangle.frag.spv"));
|
||||||
|
pub(crate) const TRIANGLE_VERTEX_SHADER_WORDS: &[u32] = &TRIANGLE_VERTEX_SHADER_DATA;
|
||||||
|
pub(crate) const TRIANGLE_FRAGMENT_SHADER_WORDS: &[u32] = &TRIANGLE_FRAGMENT_SHADER_DATA;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|||||||
@@ -44,9 +44,14 @@ pub(super) fn create_static_mesh_vertex_buffer(
|
|||||||
device: &VulkanLogicalDeviceProbe,
|
device: &VulkanLogicalDeviceProbe,
|
||||||
mesh: &VulkanStaticMesh,
|
mesh: &VulkanStaticMesh,
|
||||||
) -> Result<VulkanAllocatedBuffer, VulkanSmokeRendererError> {
|
) -> Result<VulkanAllocatedBuffer, VulkanSmokeRendererError> {
|
||||||
let mut bytes = Vec::with_capacity(mesh.vertices.len() * 5 * std::mem::size_of::<f32>());
|
let mut bytes = Vec::with_capacity(mesh.vertices.len() * 7 * std::mem::size_of::<f32>());
|
||||||
for vertex in &mesh.vertices {
|
for vertex in &mesh.vertices {
|
||||||
for value in vertex.position.into_iter().chain(vertex.color) {
|
for value in vertex
|
||||||
|
.position
|
||||||
|
.into_iter()
|
||||||
|
.chain(vertex.color)
|
||||||
|
.chain(vertex.uv)
|
||||||
|
{
|
||||||
bytes.extend_from_slice(&value.to_ne_bytes());
|
bytes.extend_from_slice(&value.to_ne_bytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,10 +181,16 @@ impl VulkanSmokeRenderer {
|
|||||||
return Err(error);
|
return Err(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let texture = match create_info.texture.as_ref() {
|
// Keep the compatibility triangle path valid: it samples a white texel
|
||||||
None => None,
|
// when no original TEXM was supplied.
|
||||||
Some(texture) => {
|
let fallback_texture = super::VulkanStaticTexture {
|
||||||
match create_static_texture_image(&instance, &device, command_pool, texture) {
|
width: 1,
|
||||||
|
height: 1,
|
||||||
|
rgba8: vec![255, 255, 255, 255],
|
||||||
|
};
|
||||||
|
let texture_source = create_info.texture.as_ref().unwrap_or(&fallback_texture);
|
||||||
|
let texture =
|
||||||
|
match create_static_texture_image(&instance, &device, command_pool, texture_source) {
|
||||||
Ok(image) => Some(image),
|
Ok(image) => Some(image),
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
// SAFETY: These resources belong to this live device and are rolled back before it drops.
|
// SAFETY: These resources belong to this live device and are rolled back before it drops.
|
||||||
@@ -193,8 +199,6 @@ impl VulkanSmokeRenderer {
|
|||||||
destroy_allocated_buffer(&device, &vertex_buffer);
|
destroy_allocated_buffer(&device, &vertex_buffer);
|
||||||
return Err(error);
|
return Err(error);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
let mut renderer = Self {
|
let mut renderer = Self {
|
||||||
instance: Some(instance),
|
instance: Some(instance),
|
||||||
@@ -318,6 +322,14 @@ impl VulkanSmokeRenderer {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn texture_ref(&self) -> Result<&super::VulkanAllocatedImage, VulkanSmokeRendererError> {
|
||||||
|
self.texture
|
||||||
|
.as_ref()
|
||||||
|
.ok_or(VulkanSmokeRendererError::InvariantViolation {
|
||||||
|
context: "static material texture",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn surface_ref(&self) -> Result<&VulkanSurfaceProbe, VulkanSmokeRendererError> {
|
fn surface_ref(&self) -> Result<&VulkanSurfaceProbe, VulkanSmokeRendererError> {
|
||||||
self.surface
|
self.surface
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@@ -532,6 +544,7 @@ impl VulkanSmokeRenderer {
|
|||||||
self.command_pool,
|
self.command_pool,
|
||||||
self.vertex_buffer_ref()?,
|
self.vertex_buffer_ref()?,
|
||||||
self.index_buffer_ref()?,
|
self.index_buffer_ref()?,
|
||||||
|
self.texture_ref()?,
|
||||||
reuse_command_pool,
|
reuse_command_pool,
|
||||||
)?,
|
)?,
|
||||||
|resources| destroy_swapchain_resources(device, self.command_pool, resources),
|
|resources| destroy_swapchain_resources(device, self.command_pool, resources),
|
||||||
@@ -608,6 +621,14 @@ impl VulkanSmokeRenderer {
|
|||||||
vk::PipelineBindPoint::GRAPHICS,
|
vk::PipelineBindPoint::GRAPHICS,
|
||||||
resources.pipeline,
|
resources.pipeline,
|
||||||
);
|
);
|
||||||
|
device.device().cmd_bind_descriptor_sets(
|
||||||
|
command_buffer,
|
||||||
|
vk::PipelineBindPoint::GRAPHICS,
|
||||||
|
resources.pipeline_layout,
|
||||||
|
0,
|
||||||
|
&[resources.descriptor_set],
|
||||||
|
&[],
|
||||||
|
);
|
||||||
let vertex_buffers = [self.vertex_buffer_ref()?.buffer];
|
let vertex_buffers = [self.vertex_buffer_ref()?.buffer];
|
||||||
let offsets = [0_u64];
|
let offsets = [0_u64];
|
||||||
device
|
device
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ pub struct VulkanStaticVertex {
|
|||||||
pub position: [f32; 2],
|
pub position: [f32; 2],
|
||||||
/// Linear RGB vertex color.
|
/// Linear RGB vertex color.
|
||||||
pub color: [f32; 3],
|
pub color: [f32; 3],
|
||||||
|
/// Texture coordinate consumed by the static material bridge.
|
||||||
|
pub uv: [f32; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Static indexed geometry uploaded to live Vulkan buffers.
|
/// Static indexed geometry uploaded to live Vulkan buffers.
|
||||||
@@ -94,14 +96,17 @@ impl VulkanStaticMesh {
|
|||||||
VulkanStaticVertex {
|
VulkanStaticVertex {
|
||||||
position: [0.0, -0.55],
|
position: [0.0, -0.55],
|
||||||
color: [1.0, 0.2, 0.2],
|
color: [1.0, 0.2, 0.2],
|
||||||
|
uv: [0.5, 0.0],
|
||||||
},
|
},
|
||||||
VulkanStaticVertex {
|
VulkanStaticVertex {
|
||||||
position: [0.55, 0.55],
|
position: [0.55, 0.55],
|
||||||
color: [0.2, 1.0, 0.2],
|
color: [0.2, 1.0, 0.2],
|
||||||
|
uv: [1.0, 1.0],
|
||||||
},
|
},
|
||||||
VulkanStaticVertex {
|
VulkanStaticVertex {
|
||||||
position: [-0.55, 0.55],
|
position: [-0.55, 0.55],
|
||||||
color: [0.2, 0.4, 1.0],
|
color: [0.2, 0.4, 1.0],
|
||||||
|
uv: [0.0, 1.0],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
indices: vec![0, 1, 2],
|
indices: vec![0, 1, 2],
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
use ash::vk;
|
use ash::vk;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
color_subresource_range, VulkanAllocatedBuffer, VulkanLogicalDeviceProbe,
|
color_subresource_range, VulkanAllocatedBuffer, VulkanAllocatedImage, VulkanLogicalDeviceProbe,
|
||||||
VulkanSmokeRendererError, VulkanSwapchainProbe, TRIANGLE_FRAGMENT_SHADER_WORDS,
|
VulkanSmokeRendererError, VulkanSwapchainProbe, TRIANGLE_FRAGMENT_SHADER_WORDS,
|
||||||
TRIANGLE_VERTEX_SHADER_WORDS,
|
TRIANGLE_VERTEX_SHADER_WORDS,
|
||||||
};
|
};
|
||||||
@@ -12,6 +12,10 @@ pub(super) struct VulkanSwapchainResources {
|
|||||||
pub(super) image_views: Vec<vk::ImageView>,
|
pub(super) image_views: Vec<vk::ImageView>,
|
||||||
pub(super) render_pass: vk::RenderPass,
|
pub(super) render_pass: vk::RenderPass,
|
||||||
pub(super) pipeline_layout: vk::PipelineLayout,
|
pub(super) pipeline_layout: vk::PipelineLayout,
|
||||||
|
pub(super) descriptor_set_layout: vk::DescriptorSetLayout,
|
||||||
|
pub(super) descriptor_pool: vk::DescriptorPool,
|
||||||
|
pub(super) descriptor_set: vk::DescriptorSet,
|
||||||
|
pub(super) sampler: vk::Sampler,
|
||||||
pub(super) pipeline: vk::Pipeline,
|
pub(super) pipeline: vk::Pipeline,
|
||||||
pub(super) framebuffers: Vec<vk::Framebuffer>,
|
pub(super) framebuffers: Vec<vk::Framebuffer>,
|
||||||
pub(super) command_buffers: Vec<vk::CommandBuffer>,
|
pub(super) command_buffers: Vec<vk::CommandBuffer>,
|
||||||
@@ -21,6 +25,9 @@ struct PartialSwapchainResources {
|
|||||||
image_views: Vec<vk::ImageView>,
|
image_views: Vec<vk::ImageView>,
|
||||||
render_pass: Option<vk::RenderPass>,
|
render_pass: Option<vk::RenderPass>,
|
||||||
pipeline_layout: Option<vk::PipelineLayout>,
|
pipeline_layout: Option<vk::PipelineLayout>,
|
||||||
|
descriptor_set_layout: Option<vk::DescriptorSetLayout>,
|
||||||
|
descriptor_pool: Option<vk::DescriptorPool>,
|
||||||
|
sampler: Option<vk::Sampler>,
|
||||||
pipeline: Option<vk::Pipeline>,
|
pipeline: Option<vk::Pipeline>,
|
||||||
framebuffers: Vec<vk::Framebuffer>,
|
framebuffers: Vec<vk::Framebuffer>,
|
||||||
command_buffers: Vec<vk::CommandBuffer>,
|
command_buffers: Vec<vk::CommandBuffer>,
|
||||||
@@ -32,6 +39,7 @@ pub(super) fn create_swapchain_resources(
|
|||||||
command_pool: vk::CommandPool,
|
command_pool: vk::CommandPool,
|
||||||
vertex_buffer: &VulkanAllocatedBuffer,
|
vertex_buffer: &VulkanAllocatedBuffer,
|
||||||
index_buffer: &VulkanAllocatedBuffer,
|
index_buffer: &VulkanAllocatedBuffer,
|
||||||
|
texture: &VulkanAllocatedImage,
|
||||||
reuse_command_pool: bool,
|
reuse_command_pool: bool,
|
||||||
) -> Result<VulkanSwapchainResources, VulkanSmokeRendererError> {
|
) -> Result<VulkanSwapchainResources, VulkanSmokeRendererError> {
|
||||||
// SAFETY: The swapchain is live and owned by this renderer for the duration of the query.
|
// SAFETY: The swapchain is live and owned by this renderer for the duration of the query.
|
||||||
@@ -52,14 +60,26 @@ pub(super) fn create_swapchain_resources(
|
|||||||
)?,
|
)?,
|
||||||
render_pass: None,
|
render_pass: None,
|
||||||
pipeline_layout: None,
|
pipeline_layout: None,
|
||||||
|
descriptor_set_layout: None,
|
||||||
|
descriptor_pool: None,
|
||||||
|
sampler: None,
|
||||||
pipeline: None,
|
pipeline: None,
|
||||||
framebuffers: Vec::new(),
|
framebuffers: Vec::new(),
|
||||||
command_buffers: Vec::new(),
|
command_buffers: Vec::new(),
|
||||||
};
|
};
|
||||||
let (render_pass, pipeline_layout, pipeline) = match create_swapchain_pipeline_bundle(
|
let (
|
||||||
|
render_pass,
|
||||||
|
pipeline_layout,
|
||||||
|
pipeline,
|
||||||
|
descriptor_set_layout,
|
||||||
|
descriptor_pool,
|
||||||
|
descriptor_set,
|
||||||
|
sampler,
|
||||||
|
) = match create_swapchain_pipeline_bundle(
|
||||||
device,
|
device,
|
||||||
swapchain.report.plan.format.format,
|
swapchain.report.plan.format.format,
|
||||||
swapchain.report.plan.extent,
|
swapchain.report.plan.extent,
|
||||||
|
texture,
|
||||||
) {
|
) {
|
||||||
Ok(bundle) => bundle,
|
Ok(bundle) => bundle,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
@@ -69,6 +89,9 @@ pub(super) fn create_swapchain_resources(
|
|||||||
};
|
};
|
||||||
partial.render_pass = Some(render_pass);
|
partial.render_pass = Some(render_pass);
|
||||||
partial.pipeline_layout = Some(pipeline_layout);
|
partial.pipeline_layout = Some(pipeline_layout);
|
||||||
|
partial.descriptor_set_layout = Some(descriptor_set_layout);
|
||||||
|
partial.descriptor_pool = Some(descriptor_pool);
|
||||||
|
partial.sampler = Some(sampler);
|
||||||
partial.pipeline = Some(pipeline);
|
partial.pipeline = Some(pipeline);
|
||||||
let framebuffers = match create_swapchain_framebuffers(
|
let framebuffers = match create_swapchain_framebuffers(
|
||||||
device,
|
device,
|
||||||
@@ -101,6 +124,10 @@ pub(super) fn create_swapchain_resources(
|
|||||||
image_views: partial.image_views,
|
image_views: partial.image_views,
|
||||||
render_pass,
|
render_pass,
|
||||||
pipeline_layout,
|
pipeline_layout,
|
||||||
|
descriptor_set_layout,
|
||||||
|
descriptor_pool,
|
||||||
|
descriptor_set,
|
||||||
|
sampler,
|
||||||
pipeline,
|
pipeline,
|
||||||
framebuffers: partial.framebuffers,
|
framebuffers: partial.framebuffers,
|
||||||
command_buffers: partial.command_buffers,
|
command_buffers: partial.command_buffers,
|
||||||
@@ -119,16 +146,44 @@ fn create_swapchain_image_views(
|
|||||||
Ok(image_views)
|
Ok(image_views)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
fn create_swapchain_pipeline_bundle(
|
fn create_swapchain_pipeline_bundle(
|
||||||
device: &VulkanLogicalDeviceProbe,
|
device: &VulkanLogicalDeviceProbe,
|
||||||
format: i32,
|
format: i32,
|
||||||
extent: (u32, u32),
|
extent: (u32, u32),
|
||||||
) -> Result<(vk::RenderPass, vk::PipelineLayout, vk::Pipeline), VulkanSmokeRendererError> {
|
texture: &VulkanAllocatedImage,
|
||||||
|
) -> Result<
|
||||||
|
(
|
||||||
|
vk::RenderPass,
|
||||||
|
vk::PipelineLayout,
|
||||||
|
vk::Pipeline,
|
||||||
|
vk::DescriptorSetLayout,
|
||||||
|
vk::DescriptorPool,
|
||||||
|
vk::DescriptorSet,
|
||||||
|
vk::Sampler,
|
||||||
|
),
|
||||||
|
VulkanSmokeRendererError,
|
||||||
|
> {
|
||||||
let render_pass = create_render_pass(device, format)?;
|
let render_pass = create_render_pass(device, format)?;
|
||||||
let pipeline_layout = create_pipeline_layout(device).inspect_err(|_| {
|
let (descriptor_set_layout, descriptor_pool, descriptor_set, sampler) =
|
||||||
|
create_texture_descriptor_bundle(device, texture).inspect_err(|_| {
|
||||||
// SAFETY: The render pass was created above on this live logical device and is destroyed on setup failure.
|
// SAFETY: The render pass was created above on this live logical device and is destroyed on setup failure.
|
||||||
unsafe { device.device().destroy_render_pass(render_pass, None) };
|
unsafe { device.device().destroy_render_pass(render_pass, None) };
|
||||||
})?;
|
})?;
|
||||||
|
let pipeline_layout =
|
||||||
|
create_pipeline_layout(device, descriptor_set_layout).inspect_err(|_| {
|
||||||
|
// SAFETY: The descriptor resources and render pass were created above and are rolled back on this device.
|
||||||
|
unsafe {
|
||||||
|
device.device().destroy_sampler(sampler, None);
|
||||||
|
device
|
||||||
|
.device()
|
||||||
|
.destroy_descriptor_pool(descriptor_pool, None);
|
||||||
|
device
|
||||||
|
.device()
|
||||||
|
.destroy_descriptor_set_layout(descriptor_set_layout, None);
|
||||||
|
device.device().destroy_render_pass(render_pass, None);
|
||||||
|
}
|
||||||
|
})?;
|
||||||
let pipeline = create_graphics_pipeline(device, render_pass, pipeline_layout, extent)
|
let pipeline = create_graphics_pipeline(device, render_pass, pipeline_layout, extent)
|
||||||
.inspect_err(|_| {
|
.inspect_err(|_| {
|
||||||
// SAFETY: These objects were created above on this live logical device and are destroyed on setup failure.
|
// SAFETY: These objects were created above on this live logical device and are destroyed on setup failure.
|
||||||
@@ -136,10 +191,25 @@ fn create_swapchain_pipeline_bundle(
|
|||||||
device
|
device
|
||||||
.device()
|
.device()
|
||||||
.destroy_pipeline_layout(pipeline_layout, None);
|
.destroy_pipeline_layout(pipeline_layout, None);
|
||||||
|
device.device().destroy_sampler(sampler, None);
|
||||||
|
device
|
||||||
|
.device()
|
||||||
|
.destroy_descriptor_pool(descriptor_pool, None);
|
||||||
|
device
|
||||||
|
.device()
|
||||||
|
.destroy_descriptor_set_layout(descriptor_set_layout, None);
|
||||||
device.device().destroy_render_pass(render_pass, None);
|
device.device().destroy_render_pass(render_pass, None);
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
Ok((render_pass, pipeline_layout, pipeline))
|
Ok((
|
||||||
|
render_pass,
|
||||||
|
pipeline_layout,
|
||||||
|
pipeline,
|
||||||
|
descriptor_set_layout,
|
||||||
|
descriptor_pool,
|
||||||
|
descriptor_set,
|
||||||
|
sampler,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_swapchain_framebuffers(
|
fn create_swapchain_framebuffers(
|
||||||
@@ -248,9 +318,11 @@ fn create_render_pass(
|
|||||||
|
|
||||||
fn create_pipeline_layout(
|
fn create_pipeline_layout(
|
||||||
device: &VulkanLogicalDeviceProbe,
|
device: &VulkanLogicalDeviceProbe,
|
||||||
|
descriptor_set_layout: vk::DescriptorSetLayout,
|
||||||
) -> Result<vk::PipelineLayout, VulkanSmokeRendererError> {
|
) -> Result<vk::PipelineLayout, VulkanSmokeRendererError> {
|
||||||
let create_info = vk::PipelineLayoutCreateInfo::default();
|
let set_layouts = [descriptor_set_layout];
|
||||||
// SAFETY: The pipeline layout has no descriptor sets or push constants in Stage 0 smoke.
|
let create_info = vk::PipelineLayoutCreateInfo::default().set_layouts(&set_layouts);
|
||||||
|
// SAFETY: The descriptor-set layout belongs to this live logical device.
|
||||||
unsafe { device.device().create_pipeline_layout(&create_info, None) }.map_err(|error| {
|
unsafe { device.device().create_pipeline_layout(&create_info, None) }.map_err(|error| {
|
||||||
VulkanSmokeRendererError::VulkanOperation {
|
VulkanSmokeRendererError::VulkanOperation {
|
||||||
context: "vkCreatePipelineLayout",
|
context: "vkCreatePipelineLayout",
|
||||||
@@ -259,6 +331,106 @@ fn create_pipeline_layout(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
|
fn create_texture_descriptor_bundle(
|
||||||
|
device: &VulkanLogicalDeviceProbe,
|
||||||
|
texture: &VulkanAllocatedImage,
|
||||||
|
) -> Result<
|
||||||
|
(
|
||||||
|
vk::DescriptorSetLayout,
|
||||||
|
vk::DescriptorPool,
|
||||||
|
vk::DescriptorSet,
|
||||||
|
vk::Sampler,
|
||||||
|
),
|
||||||
|
VulkanSmokeRendererError,
|
||||||
|
> {
|
||||||
|
let binding = vk::DescriptorSetLayoutBinding::default()
|
||||||
|
.binding(0)
|
||||||
|
.descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER)
|
||||||
|
.descriptor_count(1)
|
||||||
|
.stage_flags(vk::ShaderStageFlags::FRAGMENT);
|
||||||
|
let bindings = [binding];
|
||||||
|
let layout_info = vk::DescriptorSetLayoutCreateInfo::default().bindings(&bindings);
|
||||||
|
// SAFETY: The layout description is stack-owned and references no external memory.
|
||||||
|
let layout = unsafe {
|
||||||
|
device
|
||||||
|
.device()
|
||||||
|
.create_descriptor_set_layout(&layout_info, None)
|
||||||
|
}
|
||||||
|
.map_err(|result| VulkanSmokeRendererError::VulkanOperation {
|
||||||
|
context: "vkCreateDescriptorSetLayout",
|
||||||
|
result,
|
||||||
|
})?;
|
||||||
|
let pool_size = vk::DescriptorPoolSize::default()
|
||||||
|
.ty(vk::DescriptorType::COMBINED_IMAGE_SAMPLER)
|
||||||
|
.descriptor_count(1);
|
||||||
|
let pool_sizes = [pool_size];
|
||||||
|
let pool_info = vk::DescriptorPoolCreateInfo::default()
|
||||||
|
.pool_sizes(&pool_sizes)
|
||||||
|
.max_sets(1);
|
||||||
|
let pool =
|
||||||
|
// SAFETY: The pool description is stack-owned and reserves exactly one descriptor.
|
||||||
|
unsafe { device.device().create_descriptor_pool(&pool_info, None) }.map_err(|result| {
|
||||||
|
// SAFETY: The layout was created above on this device and is rolled back once.
|
||||||
|
unsafe { device.device().destroy_descriptor_set_layout(layout, None) };
|
||||||
|
VulkanSmokeRendererError::VulkanOperation {
|
||||||
|
context: "vkCreateDescriptorPool",
|
||||||
|
result,
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
let layouts = [layout];
|
||||||
|
let allocate_info = vk::DescriptorSetAllocateInfo::default()
|
||||||
|
.descriptor_pool(pool)
|
||||||
|
.set_layouts(&layouts);
|
||||||
|
// SAFETY: The pool and layout are live on this logical device.
|
||||||
|
let descriptor_set = unsafe { device.device().allocate_descriptor_sets(&allocate_info) }
|
||||||
|
.map_err(|result| {
|
||||||
|
// SAFETY: Resources were created above on this device and are rolled back once.
|
||||||
|
unsafe {
|
||||||
|
device.device().destroy_descriptor_pool(pool, None);
|
||||||
|
device.device().destroy_descriptor_set_layout(layout, None);
|
||||||
|
};
|
||||||
|
VulkanSmokeRendererError::VulkanOperation {
|
||||||
|
context: "vkAllocateDescriptorSets",
|
||||||
|
result,
|
||||||
|
}
|
||||||
|
})?[0];
|
||||||
|
let sampler_info = vk::SamplerCreateInfo::default()
|
||||||
|
.mag_filter(vk::Filter::LINEAR)
|
||||||
|
.min_filter(vk::Filter::LINEAR)
|
||||||
|
.mipmap_mode(vk::SamplerMipmapMode::LINEAR)
|
||||||
|
.address_mode_u(vk::SamplerAddressMode::REPEAT)
|
||||||
|
.address_mode_v(vk::SamplerAddressMode::REPEAT)
|
||||||
|
.address_mode_w(vk::SamplerAddressMode::REPEAT)
|
||||||
|
.max_lod(0.0);
|
||||||
|
let sampler =
|
||||||
|
// SAFETY: The sampler create info is stack-owned and has no unsupported optional features.
|
||||||
|
unsafe { device.device().create_sampler(&sampler_info, None) }.map_err(|result| {
|
||||||
|
// SAFETY: Resources were created above on this device and are rolled back once.
|
||||||
|
unsafe {
|
||||||
|
device.device().destroy_descriptor_pool(pool, None);
|
||||||
|
device.device().destroy_descriptor_set_layout(layout, None);
|
||||||
|
};
|
||||||
|
VulkanSmokeRendererError::VulkanOperation {
|
||||||
|
context: "vkCreateSampler",
|
||||||
|
result,
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
let image_info = vk::DescriptorImageInfo::default()
|
||||||
|
.sampler(sampler)
|
||||||
|
.image_view(texture.view)
|
||||||
|
.image_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL);
|
||||||
|
let image_infos = [image_info];
|
||||||
|
let write = vk::WriteDescriptorSet::default()
|
||||||
|
.dst_set(descriptor_set)
|
||||||
|
.dst_binding(0)
|
||||||
|
.descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER)
|
||||||
|
.image_info(&image_infos);
|
||||||
|
// SAFETY: The descriptor set, sampler and image view are live and the texture upload completed its shader-read transition.
|
||||||
|
unsafe { device.device().update_descriptor_sets(&[write], &[]) };
|
||||||
|
Ok((layout, pool, descriptor_set, sampler))
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::cast_precision_loss)]
|
#[allow(clippy::cast_precision_loss)]
|
||||||
fn extent_component_to_f32(value: u32) -> f32 {
|
fn extent_component_to_f32(value: u32) -> f32 {
|
||||||
value as f32
|
value as f32
|
||||||
@@ -293,7 +465,7 @@ fn create_graphics_pipeline(
|
|||||||
];
|
];
|
||||||
let vertex_binding = vk::VertexInputBindingDescription::default()
|
let vertex_binding = vk::VertexInputBindingDescription::default()
|
||||||
.binding(0)
|
.binding(0)
|
||||||
.stride(u32::try_from(5 * std::mem::size_of::<f32>()).unwrap_or(u32::MAX))
|
.stride(u32::try_from(7 * std::mem::size_of::<f32>()).unwrap_or(u32::MAX))
|
||||||
.input_rate(vk::VertexInputRate::VERTEX);
|
.input_rate(vk::VertexInputRate::VERTEX);
|
||||||
let vertex_attributes = [
|
let vertex_attributes = [
|
||||||
vk::VertexInputAttributeDescription::default()
|
vk::VertexInputAttributeDescription::default()
|
||||||
@@ -306,6 +478,11 @@ fn create_graphics_pipeline(
|
|||||||
.location(1)
|
.location(1)
|
||||||
.format(vk::Format::R32G32B32_SFLOAT)
|
.format(vk::Format::R32G32B32_SFLOAT)
|
||||||
.offset(u32::try_from(2 * std::mem::size_of::<f32>()).unwrap_or(u32::MAX)),
|
.offset(u32::try_from(2 * std::mem::size_of::<f32>()).unwrap_or(u32::MAX)),
|
||||||
|
vk::VertexInputAttributeDescription::default()
|
||||||
|
.binding(0)
|
||||||
|
.location(2)
|
||||||
|
.format(vk::Format::R32G32_SFLOAT)
|
||||||
|
.offset(u32::try_from(5 * std::mem::size_of::<f32>()).unwrap_or(u32::MAX)),
|
||||||
];
|
];
|
||||||
let vertex_bindings = [vertex_binding];
|
let vertex_bindings = [vertex_binding];
|
||||||
let vertex_input_state = vk::PipelineVertexInputStateCreateInfo::default()
|
let vertex_input_state = vk::PipelineVertexInputStateCreateInfo::default()
|
||||||
@@ -461,6 +638,13 @@ pub(super) fn destroy_swapchain_resources(
|
|||||||
device
|
device
|
||||||
.device()
|
.device()
|
||||||
.destroy_pipeline_layout(resources.pipeline_layout, None);
|
.destroy_pipeline_layout(resources.pipeline_layout, None);
|
||||||
|
device.device().destroy_sampler(resources.sampler, None);
|
||||||
|
device
|
||||||
|
.device()
|
||||||
|
.destroy_descriptor_pool(resources.descriptor_pool, None);
|
||||||
|
device
|
||||||
|
.device()
|
||||||
|
.destroy_descriptor_set_layout(resources.descriptor_set_layout, None);
|
||||||
device
|
device
|
||||||
.device()
|
.device()
|
||||||
.destroy_render_pass(resources.render_pass, None);
|
.destroy_render_pass(resources.render_pass, None);
|
||||||
@@ -493,6 +677,19 @@ fn destroy_partial_swapchain_resources(
|
|||||||
.device()
|
.device()
|
||||||
.destroy_pipeline_layout(pipeline_layout, None);
|
.destroy_pipeline_layout(pipeline_layout, None);
|
||||||
}
|
}
|
||||||
|
if let Some(sampler) = partial.sampler {
|
||||||
|
device.device().destroy_sampler(sampler, None);
|
||||||
|
}
|
||||||
|
if let Some(descriptor_pool) = partial.descriptor_pool {
|
||||||
|
device
|
||||||
|
.device()
|
||||||
|
.destroy_descriptor_pool(descriptor_pool, None);
|
||||||
|
}
|
||||||
|
if let Some(descriptor_set_layout) = partial.descriptor_set_layout {
|
||||||
|
device
|
||||||
|
.device()
|
||||||
|
.destroy_descriptor_set_layout(descriptor_set_layout, None);
|
||||||
|
}
|
||||||
if let Some(render_pass) = partial.render_pass {
|
if let Some(render_pass) = partial.render_pass {
|
||||||
device.device().destroy_render_pass(render_pass, None);
|
device.device().destroy_render_pass(render_pass, None);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -609,10 +609,10 @@ fn triangle_shader_manifest_hashes_are_stable() {
|
|||||||
TRIANGLE_VERTEX_SOURCE_SHA256
|
TRIANGLE_VERTEX_SOURCE_SHA256
|
||||||
);
|
);
|
||||||
assert_eq!(report.modules[0].spirv_path, TRIANGLE_VERTEX_SPIRV_PATH);
|
assert_eq!(report.modules[0].spirv_path, TRIANGLE_VERTEX_SPIRV_PATH);
|
||||||
assert_eq!(report.modules[0].word_count, 253);
|
assert_eq!(report.modules[0].word_count, 290);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
report.modules[0].sha256,
|
report.modules[0].sha256,
|
||||||
"4d3ceca7b42ebc971d831b0a0d816457397bd9aeda47fb8d44c4b1aeaa5e7ba0"
|
"1984662f78873b70135ec444ccd86d86fa66dfca3f615d19ddaf0cda1587d4cf"
|
||||||
);
|
);
|
||||||
assert_eq!(report.modules[0].descriptor_sets, 0);
|
assert_eq!(report.modules[0].descriptor_sets, 0);
|
||||||
assert_eq!(report.modules[0].push_constant_bytes, 0);
|
assert_eq!(report.modules[0].push_constant_bytes, 0);
|
||||||
@@ -627,11 +627,11 @@ fn triangle_shader_manifest_hashes_are_stable() {
|
|||||||
assert!(!report.modules[0].interface_hash.is_empty());
|
assert!(!report.modules[0].interface_hash.is_empty());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
report.modules[1].sha256,
|
report.modules[1].sha256,
|
||||||
"5a7441be03cd3c25d557268b2e58d5aa50504c87bffcb4c3fd7cbcf007db0b96"
|
"49dae3e1c46d5d23cccf3b161c36ea0b3a606e89c2289dbfed3e4fe991eb8556"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
report.manifest_hash,
|
report.manifest_hash,
|
||||||
"11e3feb65200ebd2ac87b7e776e9c6433a5da9d71a651bfadea89a51be17ff05"
|
"038ecdb57832ac2d45a1ca6da5ec058b34f4f31b7170aa68fa612ac9d0ae7565"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ pub(crate) const SPIRV_VALIDATOR_BINARY_SHA256: &str =
|
|||||||
pub(crate) const TRIANGLE_VERTEX_SOURCE_PATH: &str =
|
pub(crate) const TRIANGLE_VERTEX_SOURCE_PATH: &str =
|
||||||
"adapters/fparkan-render-vulkan/shaders/triangle.vert";
|
"adapters/fparkan-render-vulkan/shaders/triangle.vert";
|
||||||
pub(crate) const TRIANGLE_VERTEX_SOURCE_SHA256: &str =
|
pub(crate) const TRIANGLE_VERTEX_SOURCE_SHA256: &str =
|
||||||
"1e57f14d193fc61457c0749081c452ad25669998913107df12f3ccc3c33e0341";
|
"82f9ee39a30b094203041205954576ca820d75771421bb27ddd300359e4e9043";
|
||||||
pub(crate) const TRIANGLE_VERTEX_SPIRV_PATH: &str =
|
pub(crate) const TRIANGLE_VERTEX_SPIRV_PATH: &str =
|
||||||
"adapters/fparkan-render-vulkan/shaders/triangle.vert.spv";
|
"adapters/fparkan-render-vulkan/shaders/triangle.vert.spv";
|
||||||
pub(crate) const TRIANGLE_VERTEX_COMPILE_COMMAND: &str =
|
pub(crate) const TRIANGLE_VERTEX_COMPILE_COMMAND: &str =
|
||||||
@@ -29,7 +29,7 @@ pub(crate) const TRIANGLE_VERTEX_VALIDATE_COMMAND: &str =
|
|||||||
"spirv-val --target-env vulkan1.1 adapters/fparkan-render-vulkan/shaders/triangle.vert.spv";
|
"spirv-val --target-env vulkan1.1 adapters/fparkan-render-vulkan/shaders/triangle.vert.spv";
|
||||||
const TRIANGLE_FRAGMENT_SOURCE_PATH: &str = "adapters/fparkan-render-vulkan/shaders/triangle.frag";
|
const TRIANGLE_FRAGMENT_SOURCE_PATH: &str = "adapters/fparkan-render-vulkan/shaders/triangle.frag";
|
||||||
const TRIANGLE_FRAGMENT_SOURCE_SHA256: &str =
|
const TRIANGLE_FRAGMENT_SOURCE_SHA256: &str =
|
||||||
"f19e74d001d07fb537d4b0f9e621f9b8bc40eeb68816130220853abea6bd4445";
|
"70b600a0c79b6cdee1747a47caf7854bbe0bb9a693b3fe29345e659df549d96f";
|
||||||
const TRIANGLE_FRAGMENT_SPIRV_PATH: &str =
|
const TRIANGLE_FRAGMENT_SPIRV_PATH: &str =
|
||||||
"adapters/fparkan-render-vulkan/shaders/triangle.frag.spv";
|
"adapters/fparkan-render-vulkan/shaders/triangle.frag.spv";
|
||||||
const TRIANGLE_FRAGMENT_COMPILE_COMMAND: &str =
|
const TRIANGLE_FRAGMENT_COMPILE_COMMAND: &str =
|
||||||
@@ -225,7 +225,7 @@ pub fn triangle_shader_manifest() -> Vec<VulkanShaderModuleManifest> {
|
|||||||
name: "triangle.frag",
|
name: "triangle.frag",
|
||||||
stage: VulkanShaderStage::Fragment,
|
stage: VulkanShaderStage::Fragment,
|
||||||
entry_point: "main",
|
entry_point: "main",
|
||||||
descriptor_sets: 0,
|
descriptor_sets: 1,
|
||||||
push_constant_bytes: 0,
|
push_constant_bytes: 0,
|
||||||
source_path: TRIANGLE_FRAGMENT_SOURCE_PATH,
|
source_path: TRIANGLE_FRAGMENT_SOURCE_PATH,
|
||||||
source_sha256: TRIANGLE_FRAGMENT_SOURCE_SHA256,
|
source_sha256: TRIANGLE_FRAGMENT_SOURCE_SHA256,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
| Path | Native window / swapchain | Draws pixels | Uses original assets | Acceptance class | Что доказывает | Чего не доказывает |
|
| Path | Native window / swapchain | Draws pixels | Uses original assets | Acceptance class | Что доказывает | Чего не доказывает |
|
||||||
| --- | --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- | --- |
|
||||||
| `fparkan-vulkan-smoke` / `VulkanSmokeRenderer` | Yes | Yes | Static MSH plus TEXM upload | `covered-gpu` for Stage 0 smoke and explicit MSH/TEXM bridge IDs | Loader, instance, surface, swapchain, submit/present, validation-clean triangle path; original MSH indexed draw; TEXM RGBA8 staging upload and `SHADER_READ_ONLY_OPTIMAL` transition | Texture sampling, descriptors, terrain, gameplay rendering |
|
| `fparkan-vulkan-smoke` / `VulkanSmokeRenderer` | Yes | Yes | Static MSH plus sampled TEXM | `covered-gpu` for Stage 0 smoke and explicit MSH/TEXM/descriptor bridge IDs | Loader, instance, surface, swapchain, submit/present, validation-clean triangle path; original MSH indexed draw; TEXM RGBA8 staging upload, `SHADER_READ_ONLY_OPTIMAL`, sampler/descriptor binding and fragment sampling | Original material mapping, exact MSH UV scale, terrain, gameplay rendering |
|
||||||
| `VulkanPlanningBackend` | No | No | Optional CPU-side IDs only | `covered-planning` | Deterministic command validation, canonical capture, frame submission planning | Любой live GPU draw, pixel parity, validation-clean asset frame |
|
| `VulkanPlanningBackend` | No | No | Optional CPU-side IDs only | `covered-planning` | Deterministic command validation, canonical capture, frame submission planning | Любой live GPU draw, pixel parity, validation-clean asset frame |
|
||||||
| `RecordingBackend` | No | No | Optional CPU-side IDs only | `covered-planning` | Stable command capture for backend-neutral tests | Native window, Vulkan, GPU resource lifetime, pixels |
|
| `RecordingBackend` | No | No | Optional CPU-side IDs only | `covered-planning` | Stable command capture for backend-neutral tests | Native window, Vulkan, GPU resource lifetime, pixels |
|
||||||
| `NullBackend` | No | No | Optional CPU-side IDs only | Usually `covered` for validation-only rows | Command stream framing and bounds validation | Capture stability, GPU execution, pixels |
|
| `NullBackend` | No | No | Optional CPU-side IDs only | Usually `covered` for validation-only rows | Command stream framing and bounds validation | Capture stability, GPU execution, pixels |
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
## Current repository status
|
## Current repository status
|
||||||
|
|
||||||
- Реальный Vulkan в репозитории имеет smoke triangle path и узкий static asset bridge: `fparkan-vulkan-smoke --model-root <GOG_ROOT> --model-archive system.rlb --model-name MTCHECK.MSH --texture-root <GOG_ROOT> --texture-archive Textures.lib --texture-name DEFAULT.0` загружает validated original MSH, разворачивает batch `base_vertex`, нормализует XZ viewer plane, выполняет real indexed draw и загружает decoded TEXM mip-0 в device-local image. Image переходится в sampling layout, но ещё не связан descriptor set-ом или fragment shader; это не texture/material/terrain renderer.
|
- Реальный Vulkan в репозитории имеет smoke triangle path и узкий static asset bridge: `fparkan-vulkan-smoke --model-root <GOG_ROOT> --model-archive system.rlb --model-name MTCHECK.MSH --texture-root <GOG_ROOT> --texture-archive Textures.lib --texture-name DEFAULT.0` загружает validated original MSH, разворачивает batch `base_vertex`, нормализует XZ viewer plane, выполняет real indexed draw и загружает decoded TEXM mip-0 в device-local image. Image переходит в sampling layout, записывается в `set=0,binding=0` combined image sampler и sampled fragment shader-ом. Для static viewer UV сейчас XZ-planar: parser сохраняет raw packed `Res5` UV0, но его fixed-point scale ещё не доказан. Это не WEAR/MAT0, exact material, terrain или gameplay renderer.
|
||||||
- `apps/fparkan-game` сейчас выдает `render-planning` JSON report поверх
|
- `apps/fparkan-game` сейчас выдает `render-planning` JSON report поверх
|
||||||
synthetic window descriptor и `VulkanPlanningBackend`.
|
synthetic window descriptor и `VulkanPlanningBackend`.
|
||||||
- `apps/fparkan-viewer` сейчас inspection-only CLI и не открывает live Vulkan
|
- `apps/fparkan-viewer` сейчас inspection-only CLI и не открывает live Vulkan
|
||||||
|
|||||||
@@ -296,7 +296,7 @@ S2-PLANNING-RENDER-008 covered-planning cargo test -p fparkan-render --offline r
|
|||||||
S2-PLANNING-RENDER-009 covered cargo xtask policy
|
S2-PLANNING-RENDER-009 covered cargo xtask policy
|
||||||
S3-VK-MESH-UPLOAD-001 covered-gpu cargo run -p fparkan-vulkan-smoke --release --locked -- --out target/fparkan/stage3-mtcheck-msh.json --frames 300 --resize-frame 120 --timeout-seconds 90 --model-root <GOG_ROOT> --model-archive system.rlb --model-name MTCHECK.MSH; original MSH reports 128 vertices and 252 indices
|
S3-VK-MESH-UPLOAD-001 covered-gpu cargo run -p fparkan-vulkan-smoke --release --locked -- --out target/fparkan/stage3-mtcheck-msh.json --frames 300 --resize-frame 120 --timeout-seconds 90 --model-root <GOG_ROOT> --model-archive system.rlb --model-name MTCHECK.MSH; original MSH reports 128 vertices and 252 indices
|
||||||
S3-VK-TEXM-UPLOAD-001 covered-gpu cargo run -p fparkan-vulkan-smoke --release --locked -- --out target/fparkan/stage3-mtcheck-texm-upload.json --frames 300 --resize-frame 120 --timeout-seconds 90 --model-root <GOG_ROOT> --model-archive system.rlb --model-name MTCHECK.MSH --texture-root <GOG_ROOT> --texture-archive Textures.lib --texture-name DEFAULT.0; original TEXM 16x16 decoded RGBA8, staged into device-local image and transitioned to SHADER_READ_ONLY_OPTIMAL
|
S3-VK-TEXM-UPLOAD-001 covered-gpu cargo run -p fparkan-vulkan-smoke --release --locked -- --out target/fparkan/stage3-mtcheck-texm-upload.json --frames 300 --resize-frame 120 --timeout-seconds 90 --model-root <GOG_ROOT> --model-archive system.rlb --model-name MTCHECK.MSH --texture-root <GOG_ROOT> --texture-archive Textures.lib --texture-name DEFAULT.0; original TEXM 16x16 decoded RGBA8, staged into device-local image and transitioned to SHADER_READ_ONLY_OPTIMAL
|
||||||
S3-VK-DESCRIPTOR-001 blocked awaits Stage 3 descriptor set contract implementation
|
S3-VK-DESCRIPTOR-001 covered-gpu cargo run -p fparkan-vulkan-smoke --release --locked -- --out target/fparkan/stage3-texm-sampled.json --frames 300 --resize-frame 120 --timeout-seconds 90 --model-root <GOG_ROOT> --model-archive system.rlb --model-name MTCHECK.MSH --texture-root <GOG_ROOT> --texture-archive Textures.lib --texture-name DEFAULT.0; original TEXM is bound as set=0,binding=0 combined image sampler and sampled in fragment shader; validation_warning_count=0 and validation_error_count=0
|
||||||
S3-VK-PIPELINE-001 blocked awaits Stage 3 graphics pipeline key and cache implementation
|
S3-VK-PIPELINE-001 blocked awaits Stage 3 graphics pipeline key and cache implementation
|
||||||
S3-VK-DRAW-MODEL-001 covered-gpu cargo run -p fparkan-vulkan-smoke --release --locked -- --out target/fparkan/stage3-mtcheck-msh.json --frames 300 --resize-frame 120 --timeout-seconds 90 --model-root <GOG_ROOT> --model-archive system.rlb --model-name MTCHECK.MSH; live Win32 Vulkan indexed MSH draw/present
|
S3-VK-DRAW-MODEL-001 covered-gpu cargo run -p fparkan-vulkan-smoke --release --locked -- --out target/fparkan/stage3-mtcheck-msh.json --frames 300 --resize-frame 120 --timeout-seconds 90 --model-root <GOG_ROOT> --model-archive system.rlb --model-name MTCHECK.MSH; live Win32 Vulkan indexed MSH draw/present
|
||||||
S3-VK-DRAW-TERRAIN-001 blocked awaits Stage 3 terrain Vulkan draw path
|
S3-VK-DRAW-TERRAIN-001 blocked awaits Stage 3 terrain Vulkan draw path
|
||||||
|
|||||||
|
Reference in New Issue
Block a user