feat(render): sample original TEXM in Vulkan

This commit is contained in:
2026-07-18 07:39:38 +04:00
parent 6e6496eebf
commit fd9ce461c2
15 changed files with 307 additions and 41 deletions
@@ -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
layout(location = 0) in vec3 in_color;
layout(location = 1) in vec2 in_uv;
layout(location = 0) out vec4 out_color;
layout(set = 0, binding = 0) uniform sampler2D base_color;
void main() {
out_color = vec4(in_color, 1.0);
out_color = texture(base_color, in_uv) * vec4(in_color, 1.0);
}
@@ -2,10 +2,13 @@
layout(location = 0) in vec2 in_position;
layout(location = 1) in vec3 in_color;
layout(location = 2) in vec2 in_uv;
layout(location = 0) out vec3 out_color;
layout(location = 1) out vec2 out_uv;
void main() {
out_color = in_color;
out_uv = in_uv;
gl_Position = vec4(in_position, 0.0, 1.0);
}
@@ -100,6 +100,13 @@ pub fn project_msh_to_static_mesh(
(position[2] - center_z) * scale,
],
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();
+27 -2
View File
@@ -90,7 +90,8 @@ const EXT_DEBUG_UTILS_EXTENSION: &str = "VK_EXT_debug_utils";
const VALIDATION_LAYER_NAME: &str = "VK_LAYER_KHRONOS_validation";
pub(crate) const SPIRV_MAGIC: u32 = 0x0723_0203;
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,
0x0001_0300,
0x0008_000b,
@@ -345,7 +346,8 @@ pub(crate) const TRIANGLE_VERTEX_SHADER_WORDS: &[u32] = &[
0x0001_00fd,
0x0001_0038,
];
pub(crate) const TRIANGLE_FRAGMENT_SHADER_WORDS: &[u32] = &[
#[allow(dead_code)]
const LEGACY_TRIANGLE_FRAGMENT_SHADER_WORDS: &[u32] = &[
0x0723_0203,
0x0001_0300,
0x0008_000b,
@@ -473,5 +475,28 @@ pub(crate) const TRIANGLE_FRAGMENT_SHADER_WORDS: &[u32] = &[
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)]
mod tests;
@@ -44,9 +44,14 @@ pub(super) fn create_static_mesh_vertex_buffer(
device: &VulkanLogicalDeviceProbe,
mesh: &VulkanStaticMesh,
) -> 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 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());
}
}
+35 -14
View File
@@ -181,21 +181,25 @@ impl VulkanSmokeRenderer {
return Err(error);
}
};
let texture = match create_info.texture.as_ref() {
None => None,
Some(texture) => {
match create_static_texture_image(&instance, &device, command_pool, texture) {
Ok(image) => Some(image),
Err(error) => {
// SAFETY: These resources belong to this live device and are rolled back before it drops.
unsafe { device.device().destroy_command_pool(command_pool, None) };
destroy_allocated_buffer(&device, &index_buffer);
destroy_allocated_buffer(&device, &vertex_buffer);
return Err(error);
}
}
}
// Keep the compatibility triangle path valid: it samples a white texel
// when no original TEXM was supplied.
let fallback_texture = super::VulkanStaticTexture {
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),
Err(error) => {
// SAFETY: These resources belong to this live device and are rolled back before it drops.
unsafe { device.device().destroy_command_pool(command_pool, None) };
destroy_allocated_buffer(&device, &index_buffer);
destroy_allocated_buffer(&device, &vertex_buffer);
return Err(error);
}
};
let mut renderer = Self {
instance: Some(instance),
validation,
@@ -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> {
self.surface
.as_ref()
@@ -532,6 +544,7 @@ impl VulkanSmokeRenderer {
self.command_pool,
self.vertex_buffer_ref()?,
self.index_buffer_ref()?,
self.texture_ref()?,
reuse_command_pool,
)?,
|resources| destroy_swapchain_resources(device, self.command_pool, resources),
@@ -608,6 +621,14 @@ impl VulkanSmokeRenderer {
vk::PipelineBindPoint::GRAPHICS,
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 offsets = [0_u64];
device
@@ -42,6 +42,8 @@ pub struct VulkanStaticVertex {
pub position: [f32; 2],
/// Linear RGB vertex color.
pub color: [f32; 3],
/// Texture coordinate consumed by the static material bridge.
pub uv: [f32; 2],
}
/// Static indexed geometry uploaded to live Vulkan buffers.
@@ -94,14 +96,17 @@ impl VulkanStaticMesh {
VulkanStaticVertex {
position: [0.0, -0.55],
color: [1.0, 0.2, 0.2],
uv: [0.5, 0.0],
},
VulkanStaticVertex {
position: [0.55, 0.55],
color: [0.2, 1.0, 0.2],
uv: [1.0, 1.0],
},
VulkanStaticVertex {
position: [-0.55, 0.55],
color: [0.2, 0.4, 1.0],
uv: [0.0, 1.0],
},
],
indices: vec![0, 1, 2],
@@ -3,7 +3,7 @@
use ash::vk;
use super::{
color_subresource_range, VulkanAllocatedBuffer, VulkanLogicalDeviceProbe,
color_subresource_range, VulkanAllocatedBuffer, VulkanAllocatedImage, VulkanLogicalDeviceProbe,
VulkanSmokeRendererError, VulkanSwapchainProbe, TRIANGLE_FRAGMENT_SHADER_WORDS,
TRIANGLE_VERTEX_SHADER_WORDS,
};
@@ -12,6 +12,10 @@ pub(super) struct VulkanSwapchainResources {
pub(super) image_views: Vec<vk::ImageView>,
pub(super) render_pass: vk::RenderPass,
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) framebuffers: Vec<vk::Framebuffer>,
pub(super) command_buffers: Vec<vk::CommandBuffer>,
@@ -21,6 +25,9 @@ struct PartialSwapchainResources {
image_views: Vec<vk::ImageView>,
render_pass: Option<vk::RenderPass>,
pipeline_layout: Option<vk::PipelineLayout>,
descriptor_set_layout: Option<vk::DescriptorSetLayout>,
descriptor_pool: Option<vk::DescriptorPool>,
sampler: Option<vk::Sampler>,
pipeline: Option<vk::Pipeline>,
framebuffers: Vec<vk::Framebuffer>,
command_buffers: Vec<vk::CommandBuffer>,
@@ -32,6 +39,7 @@ pub(super) fn create_swapchain_resources(
command_pool: vk::CommandPool,
vertex_buffer: &VulkanAllocatedBuffer,
index_buffer: &VulkanAllocatedBuffer,
texture: &VulkanAllocatedImage,
reuse_command_pool: bool,
) -> Result<VulkanSwapchainResources, VulkanSmokeRendererError> {
// 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,
pipeline_layout: None,
descriptor_set_layout: None,
descriptor_pool: None,
sampler: None,
pipeline: None,
framebuffers: 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,
swapchain.report.plan.format.format,
swapchain.report.plan.extent,
texture,
) {
Ok(bundle) => bundle,
Err(error) => {
@@ -69,6 +89,9 @@ pub(super) fn create_swapchain_resources(
};
partial.render_pass = Some(render_pass);
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);
let framebuffers = match create_swapchain_framebuffers(
device,
@@ -101,6 +124,10 @@ pub(super) fn create_swapchain_resources(
image_views: partial.image_views,
render_pass,
pipeline_layout,
descriptor_set_layout,
descriptor_pool,
descriptor_set,
sampler,
pipeline,
framebuffers: partial.framebuffers,
command_buffers: partial.command_buffers,
@@ -119,16 +146,44 @@ fn create_swapchain_image_views(
Ok(image_views)
}
#[allow(clippy::type_complexity)]
fn create_swapchain_pipeline_bundle(
device: &VulkanLogicalDeviceProbe,
format: i32,
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 pipeline_layout = create_pipeline_layout(device).inspect_err(|_| {
// 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) };
})?;
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.
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)
.inspect_err(|_| {
// 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()
.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);
}
})?;
Ok((render_pass, pipeline_layout, pipeline))
Ok((
render_pass,
pipeline_layout,
pipeline,
descriptor_set_layout,
descriptor_pool,
descriptor_set,
sampler,
))
}
fn create_swapchain_framebuffers(
@@ -248,9 +318,11 @@ fn create_render_pass(
fn create_pipeline_layout(
device: &VulkanLogicalDeviceProbe,
descriptor_set_layout: vk::DescriptorSetLayout,
) -> Result<vk::PipelineLayout, VulkanSmokeRendererError> {
let create_info = vk::PipelineLayoutCreateInfo::default();
// SAFETY: The pipeline layout has no descriptor sets or push constants in Stage 0 smoke.
let set_layouts = [descriptor_set_layout];
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| {
VulkanSmokeRendererError::VulkanOperation {
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)]
fn extent_component_to_f32(value: u32) -> f32 {
value as f32
@@ -293,7 +465,7 @@ fn create_graphics_pipeline(
];
let vertex_binding = vk::VertexInputBindingDescription::default()
.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);
let vertex_attributes = [
vk::VertexInputAttributeDescription::default()
@@ -306,6 +478,11 @@ fn create_graphics_pipeline(
.location(1)
.format(vk::Format::R32G32B32_SFLOAT)
.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_input_state = vk::PipelineVertexInputStateCreateInfo::default()
@@ -461,6 +638,13 @@ pub(super) fn destroy_swapchain_resources(
device
.device()
.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()
.destroy_render_pass(resources.render_pass, None);
@@ -493,6 +677,19 @@ fn destroy_partial_swapchain_resources(
.device()
.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 {
device.device().destroy_render_pass(render_pass, None);
}
@@ -609,10 +609,10 @@ fn triangle_shader_manifest_hashes_are_stable() {
TRIANGLE_VERTEX_SOURCE_SHA256
);
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!(
report.modules[0].sha256,
"4d3ceca7b42ebc971d831b0a0d816457397bd9aeda47fb8d44c4b1aeaa5e7ba0"
"1984662f78873b70135ec444ccd86d86fa66dfca3f615d19ddaf0cda1587d4cf"
);
assert_eq!(report.modules[0].descriptor_sets, 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_eq!(
report.modules[1].sha256,
"5a7441be03cd3c25d557268b2e58d5aa50504c87bffcb4c3fd7cbcf007db0b96"
"49dae3e1c46d5d23cccf3b161c36ea0b3a606e89c2289dbfed3e4fe991eb8556"
);
assert_eq!(
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 =
"adapters/fparkan-render-vulkan/shaders/triangle.vert";
pub(crate) const TRIANGLE_VERTEX_SOURCE_SHA256: &str =
"1e57f14d193fc61457c0749081c452ad25669998913107df12f3ccc3c33e0341";
"82f9ee39a30b094203041205954576ca820d75771421bb27ddd300359e4e9043";
pub(crate) const TRIANGLE_VERTEX_SPIRV_PATH: &str =
"adapters/fparkan-render-vulkan/shaders/triangle.vert.spv";
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";
const TRIANGLE_FRAGMENT_SOURCE_PATH: &str = "adapters/fparkan-render-vulkan/shaders/triangle.frag";
const TRIANGLE_FRAGMENT_SOURCE_SHA256: &str =
"f19e74d001d07fb537d4b0f9e621f9b8bc40eeb68816130220853abea6bd4445";
"70b600a0c79b6cdee1747a47caf7854bbe0bb9a693b3fe29345e659df549d96f";
const TRIANGLE_FRAGMENT_SPIRV_PATH: &str =
"adapters/fparkan-render-vulkan/shaders/triangle.frag.spv";
const TRIANGLE_FRAGMENT_COMPILE_COMMAND: &str =
@@ -225,7 +225,7 @@ pub fn triangle_shader_manifest() -> Vec<VulkanShaderModuleManifest> {
name: "triangle.frag",
stage: VulkanShaderStage::Fragment,
entry_point: "main",
descriptor_sets: 0,
descriptor_sets: 1,
push_constant_bytes: 0,
source_path: TRIANGLE_FRAGMENT_SOURCE_PATH,
source_sha256: TRIANGLE_FRAGMENT_SOURCE_SHA256,