diff --git a/adapters/fparkan-render-vulkan/src/ffi.rs b/adapters/fparkan-render-vulkan/src/ffi.rs index 91c8254..c722656 100644 --- a/adapters/fparkan-render-vulkan/src/ffi.rs +++ b/adapters/fparkan-render-vulkan/src/ffi.rs @@ -53,10 +53,10 @@ pub use self::instance::{ #[cfg(test)] use self::instance::{cstring_vec, ensure_instance_extensions_available}; use self::resources::{ - color_subresource_range, create_command_pool, create_frame_sync, + color_subresource_range, create_command_pool, create_depth_attachment, create_frame_sync, create_static_mesh_index_buffer, create_static_mesh_vertex_buffer, create_static_texture_image, - destroy_allocated_buffer, destroy_allocated_image, VulkanAllocatedBuffer, VulkanAllocatedImage, - VulkanFrameSync, + destroy_allocated_buffer, destroy_allocated_image, destroy_depth_attachment, + VulkanAllocatedBuffer, VulkanAllocatedImage, VulkanDepthAttachment, VulkanFrameSync, }; pub use self::runtime::{ create_vulkan_logical_device_probe, create_vulkan_logical_device_probe_for_request, diff --git a/adapters/fparkan-render-vulkan/src/ffi/resources.rs b/adapters/fparkan-render-vulkan/src/ffi/resources.rs index 089e759..2318b3b 100644 --- a/adapters/fparkan-render-vulkan/src/ffi/resources.rs +++ b/adapters/fparkan-render-vulkan/src/ffi/resources.rs @@ -1,11 +1,13 @@ #![allow(unsafe_code)] use ash::vk; +use fparkan_platform::DepthStencilSupport; use super::{ VulkanInstanceProbe, VulkanLogicalDeviceProbe, VulkanSmokeRendererError, VulkanStaticMesh, VulkanStaticTexture, }; +use crate::select_depth_stencil_attachment_format; pub(super) struct VulkanAllocatedBuffer { pub(super) buffer: vk::Buffer, @@ -18,6 +20,171 @@ pub(super) struct VulkanAllocatedImage { pub(super) view: vk::ImageView, } +/// Depth/stencil image and the exact format selected for its render pass. +pub(super) struct VulkanDepthAttachment { + pub(super) image: VulkanAllocatedImage, + pub(super) format: vk::Format, +} + +#[allow(clippy::too_many_lines)] +pub(super) fn create_depth_attachment( + instance: &VulkanInstanceProbe, + device: &VulkanLogicalDeviceProbe, + extent: (u32, u32), + request: DepthStencilSupport, +) -> Result { + let supported_formats = depth_attachment_formats(instance, device); + let format = select_depth_stencil_attachment_format(&supported_formats, request) + .map(vk::Format::from_raw) + .ok_or(VulkanSmokeRendererError::InvalidStaticMesh { + context: "logical device has no selected depth attachment format", + })?; + let image_info = vk::ImageCreateInfo::default() + .image_type(vk::ImageType::TYPE_2D) + .format(format) + .extent(vk::Extent3D { + width: extent.0, + height: extent.1, + depth: 1, + }) + .mip_levels(1) + .array_layers(1) + .samples(vk::SampleCountFlags::TYPE_1) + .tiling(vk::ImageTiling::OPTIMAL) + .usage(vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT) + .sharing_mode(vk::SharingMode::EXCLUSIVE) + .initial_layout(vk::ImageLayout::UNDEFINED); + // SAFETY: The creation info is stack-owned and uses the live non-zero swapchain extent. + let image = unsafe { device.device().create_image(&image_info, None) }.map_err(|result| { + VulkanSmokeRendererError::VulkanOperation { + context: "vkCreateImage(depth attachment)", + result, + } + })?; + // SAFETY: The newly created image belongs to this device. + let requirements = unsafe { device.device().get_image_memory_requirements(image) }; + let Some(memory_type_index) = find_memory_type( + instance, + device.physical_device(), + requirements.memory_type_bits, + vk::MemoryPropertyFlags::DEVICE_LOCAL, + ) else { + // SAFETY: The unbound image is rolled back on its owning device. + unsafe { device.device().destroy_image(image, None) }; + return Err(VulkanSmokeRendererError::MissingMemoryType { + context: "depth attachment", + }); + }; + let allocation = vk::MemoryAllocateInfo::default() + .allocation_size(requirements.size) + .memory_type_index(memory_type_index); + // SAFETY: Allocation parameters are derived from this image's requirements. + let allocation_result = unsafe { device.device().allocate_memory(&allocation, None) }; + let memory = match allocation_result { + Ok(memory) => memory, + Err(result) => { + // SAFETY: The unbound image is rolled back on allocation failure. + unsafe { device.device().destroy_image(image, None) }; + return Err(VulkanSmokeRendererError::VulkanOperation { + context: "vkAllocateMemory(depth attachment)", + result, + }); + } + }; + // SAFETY: The allocation satisfies this image's queried requirements. + if let Err(result) = unsafe { device.device().bind_image_memory(image, memory, 0) } { + // SAFETY: Both newly created resources are rolled back together. + unsafe { + device.device().destroy_image(image, None); + device.device().free_memory(memory, None); + } + return Err(VulkanSmokeRendererError::VulkanOperation { + context: "vkBindImageMemory(depth attachment)", + result, + }); + } + let range = vk::ImageSubresourceRange::default() + .aspect_mask(depth_aspect(format)) + .base_mip_level(0) + .level_count(1) + .base_array_layer(0) + .layer_count(1); + let view_info = vk::ImageViewCreateInfo::default() + .image(image) + .view_type(vk::ImageViewType::TYPE_2D) + .format(format) + .subresource_range(range); + // SAFETY: The image is bound and the depth/stencil aspect matches its selected format. + let view_result = unsafe { device.device().create_image_view(&view_info, None) }; + let view = match view_result { + Ok(view) => view, + Err(result) => { + // SAFETY: Both newly created resources are rolled back together. + unsafe { + device.device().destroy_image(image, None); + device.device().free_memory(memory, None); + } + return Err(VulkanSmokeRendererError::VulkanOperation { + context: "vkCreateImageView(depth attachment)", + result, + }); + } + }; + Ok(VulkanDepthAttachment { + image: VulkanAllocatedImage { + image, + memory, + view, + }, + format, + }) +} + +pub(super) fn destroy_depth_attachment( + device: &VulkanLogicalDeviceProbe, + attachment: &VulkanDepthAttachment, +) { + destroy_allocated_image(device, &attachment.image); +} + +fn depth_attachment_formats( + instance: &VulkanInstanceProbe, + device: &VulkanLogicalDeviceProbe, +) -> Vec { + [ + vk::Format::D16_UNORM, + vk::Format::X8_D24_UNORM_PACK32, + vk::Format::D32_SFLOAT, + vk::Format::D16_UNORM_S8_UINT, + vk::Format::D24_UNORM_S8_UINT, + vk::Format::D32_SFLOAT_S8_UINT, + ] + .into_iter() + .filter(|format| { + // SAFETY: The physical device belongs to this instance and the query returns a value copy. + unsafe { + instance + .instance + .get_physical_device_format_properties(device.physical_device(), *format) + } + .optimal_tiling_features + .contains(vk::FormatFeatureFlags::DEPTH_STENCIL_ATTACHMENT) + }) + .map(vk::Format::as_raw) + .collect() +} + +fn depth_aspect(format: vk::Format) -> vk::ImageAspectFlags { + match format { + vk::Format::D16_UNORM_S8_UINT + | vk::Format::D24_UNORM_S8_UINT + | vk::Format::D32_SFLOAT_S8_UINT => { + vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL + } + _ => vk::ImageAspectFlags::DEPTH, + } +} + pub(super) struct VulkanFrameSync { pub(super) image_available: vk::Semaphore, pub(super) render_finished: vk::Semaphore, diff --git a/adapters/fparkan-render-vulkan/src/ffi/smoke.rs b/adapters/fparkan-render-vulkan/src/ffi/smoke.rs index 71af2a8..92db1a0 100644 --- a/adapters/fparkan-render-vulkan/src/ffi/smoke.rs +++ b/adapters/fparkan-render-vulkan/src/ffi/smoke.rs @@ -228,6 +228,7 @@ impl VulkanSmokeRenderer { frame_sync: Vec::new(), images_in_flight: Vec::new(), current_frame: 0, + depth_request: create_info.render_request.depth, pending_extent: None, swapchain_recreate_count: 0, report: VulkanSmokeRendererReport { @@ -554,6 +555,7 @@ impl VulkanSmokeRenderer { let swapchain = self.swapchain_ref()?; let resources = RollbackOnDrop::new( create_swapchain_resources( + self.instance_ref()?, device, swapchain, self.command_pool, @@ -561,6 +563,7 @@ impl VulkanSmokeRenderer { self.index_buffer_ref()?, self.textures_ref()?, &self.draw_ranges, + self.depth_request, reuse_command_pool, )?, |resources| destroy_swapchain_resources(device, self.command_pool, resources), @@ -608,11 +611,19 @@ impl VulkanSmokeRenderer { result: error, })?; - let clear_values = [vk::ClearValue { - color: vk::ClearColorValue { - float32: [0.05, 0.08, 0.11, 1.0], + let clear_values = [ + vk::ClearValue { + color: vk::ClearColorValue { + float32: [0.05, 0.08, 0.11, 1.0], + }, }, - }]; + vk::ClearValue { + depth_stencil: vk::ClearDepthStencilValue { + depth: 1.0, + stencil: 0, + }, + }, + ]; let render_area = vk::Rect2D { offset: vk::Offset2D { x: 0, y: 0 }, extent: vk::Extent2D { diff --git a/adapters/fparkan-render-vulkan/src/ffi/smoke_types.rs b/adapters/fparkan-render-vulkan/src/ffi/smoke_types.rs index 97ee54a..76bf842 100644 --- a/adapters/fparkan-render-vulkan/src/ffi/smoke_types.rs +++ b/adapters/fparkan-render-vulkan/src/ffi/smoke_types.rs @@ -543,6 +543,7 @@ pub struct VulkanSmokeRenderer { pub(super) frame_sync: Vec, pub(super) images_in_flight: Vec, pub(super) current_frame: usize, + pub(super) depth_request: fparkan_platform::DepthStencilSupport, pub(super) pending_extent: Option<(u32, u32)>, pub(super) swapchain_recreate_count: u32, pub(super) report: VulkanSmokeRendererReport, diff --git a/adapters/fparkan-render-vulkan/src/ffi/swapchain_resources.rs b/adapters/fparkan-render-vulkan/src/ffi/swapchain_resources.rs index 07c2869..ff797e1 100644 --- a/adapters/fparkan-render-vulkan/src/ffi/swapchain_resources.rs +++ b/adapters/fparkan-render-vulkan/src/ffi/swapchain_resources.rs @@ -1,19 +1,22 @@ #![allow(unsafe_code)] use ash::vk; +use fparkan_platform::DepthStencilSupport; use fparkan_render::{ LegacyBlendMode, LegacyCullMode, LegacyDepthMode, LegacyPipelineState, PipelineKey, }; use std::collections::BTreeMap; use super::{ - color_subresource_range, VulkanAllocatedBuffer, VulkanAllocatedImage, VulkanLogicalDeviceProbe, - VulkanSmokeRendererError, VulkanSwapchainProbe, TRIANGLE_FRAGMENT_SHADER_WORDS, - TRIANGLE_VERTEX_SHADER_WORDS, + color_subresource_range, create_depth_attachment, destroy_depth_attachment, + VulkanAllocatedBuffer, VulkanAllocatedImage, VulkanDepthAttachment, VulkanInstanceProbe, + VulkanLogicalDeviceProbe, VulkanSmokeRendererError, VulkanSwapchainProbe, + TRIANGLE_FRAGMENT_SHADER_WORDS, TRIANGLE_VERTEX_SHADER_WORDS, }; pub(super) struct VulkanSwapchainResources { pub(super) image_views: Vec, + pub(super) depth_attachment: VulkanDepthAttachment, pub(super) render_pass: vk::RenderPass, pub(super) pipeline_layout: vk::PipelineLayout, pub(super) descriptor_set_layout: vk::DescriptorSetLayout, @@ -28,6 +31,7 @@ pub(super) struct VulkanSwapchainResources { struct PartialSwapchainResources { image_views: Vec, + depth_attachment: Option, render_pass: Option, pipeline_layout: Option, descriptor_set_layout: Option, @@ -38,8 +42,9 @@ struct PartialSwapchainResources { command_buffers: Vec, } -#[allow(clippy::too_many_arguments)] +#[allow(clippy::too_many_arguments, clippy::too_many_lines)] pub(super) fn create_swapchain_resources( + instance: &VulkanInstanceProbe, device: &VulkanLogicalDeviceProbe, swapchain: &VulkanSwapchainProbe, command_pool: vk::CommandPool, @@ -47,6 +52,7 @@ pub(super) fn create_swapchain_resources( index_buffer: &VulkanAllocatedBuffer, textures: &[VulkanAllocatedImage], draw_ranges: &[super::VulkanStaticDrawRange], + depth_request: DepthStencilSupport, reuse_command_pool: bool, ) -> Result { // SAFETY: The swapchain is live and owned by this renderer for the duration of the query. @@ -65,6 +71,7 @@ pub(super) fn create_swapchain_resources( &images, swapchain.report.plan.format.format, )?, + depth_attachment: None, render_pass: None, pipeline_layout: None, descriptor_set_layout: None, @@ -75,6 +82,7 @@ pub(super) fn create_swapchain_resources( command_buffers: Vec::new(), }; let ( + depth_attachment, render_pass, pipeline_layout, pipelines, @@ -83,11 +91,13 @@ pub(super) fn create_swapchain_resources( descriptor_sets, sampler, ) = match create_swapchain_pipeline_bundle( + instance, device, swapchain.report.plan.format.format, swapchain.report.plan.extent, textures, draw_ranges, + depth_request, ) { Ok(bundle) => bundle, Err(error) => { @@ -95,6 +105,8 @@ pub(super) fn create_swapchain_resources( return Err(error); } }; + let depth_view = depth_attachment.image.view; + partial.depth_attachment = Some(depth_attachment); partial.render_pass = Some(render_pass); partial.pipeline_layout = Some(pipeline_layout); partial.descriptor_set_layout = Some(descriptor_set_layout); @@ -105,6 +117,7 @@ pub(super) fn create_swapchain_resources( device, render_pass, &partial.image_views, + depth_view, swapchain.report.plan.extent, ) { Ok(framebuffers) => framebuffers, @@ -128,8 +141,16 @@ pub(super) fn create_swapchain_resources( }; partial.command_buffers = command_buffers; let _ = (vertex_buffer, index_buffer); + let depth_attachment = + partial + .depth_attachment + .take() + .ok_or(VulkanSmokeRendererError::InvariantViolation { + context: "depth attachment ownership after swapchain setup", + })?; Ok(VulkanSwapchainResources { image_views: partial.image_views, + depth_attachment, render_pass, pipeline_layout, descriptor_set_layout, @@ -156,13 +177,16 @@ fn create_swapchain_image_views( #[allow(clippy::type_complexity)] fn create_swapchain_pipeline_bundle( + instance: &VulkanInstanceProbe, device: &VulkanLogicalDeviceProbe, format: i32, extent: (u32, u32), textures: &[VulkanAllocatedImage], draw_ranges: &[super::VulkanStaticDrawRange], + depth_request: DepthStencilSupport, ) -> Result< ( + VulkanDepthAttachment, vk::RenderPass, vk::PipelineLayout, BTreeMap, @@ -173,11 +197,19 @@ fn create_swapchain_pipeline_bundle( ), VulkanSmokeRendererError, > { - let render_pass = create_render_pass(device, format)?; + let depth_attachment = create_depth_attachment(instance, device, extent, depth_request)?; + let render_pass = match create_render_pass(device, format, depth_attachment.format) { + Ok(render_pass) => render_pass, + Err(error) => { + destroy_depth_attachment(device, &depth_attachment); + return Err(error); + } + }; let (descriptor_set_layout, descriptor_pool, descriptor_sets, sampler) = create_texture_descriptor_bundle(device, textures).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) }; + destroy_depth_attachment(device, &depth_attachment); })?; let pipeline_layout = create_pipeline_layout(device, descriptor_set_layout).inspect_err(|_| { @@ -192,6 +224,7 @@ fn create_swapchain_pipeline_bundle( .destroy_descriptor_set_layout(descriptor_set_layout, None); device.device().destroy_render_pass(render_pass, None); } + destroy_depth_attachment(device, &depth_attachment); })?; let pipelines = create_graphics_pipeline_cache(device, render_pass, pipeline_layout, extent, draw_ranges) @@ -210,8 +243,10 @@ fn create_swapchain_pipeline_bundle( .destroy_descriptor_set_layout(descriptor_set_layout, None); device.device().destroy_render_pass(render_pass, None); } + destroy_depth_attachment(device, &depth_attachment); })?; Ok(( + depth_attachment, render_pass, pipeline_layout, pipelines, @@ -226,11 +261,12 @@ fn create_swapchain_framebuffers( device: &VulkanLogicalDeviceProbe, render_pass: vk::RenderPass, image_views: &[vk::ImageView], + depth_view: vk::ImageView, extent: (u32, u32), ) -> Result, VulkanSmokeRendererError> { let mut framebuffers = Vec::with_capacity(image_views.len()); for image_view in image_views.iter().copied() { - match create_framebuffer(device, render_pass, image_view, extent) { + match create_framebuffer(device, render_pass, image_view, depth_view, extent) { Ok(framebuffer) => framebuffers.push(framebuffer), Err(error) => { // SAFETY: These framebuffers were created above on this live logical device and are destroyed on setup failure. @@ -288,6 +324,7 @@ fn create_image_view( fn create_render_pass( device: &VulkanLogicalDeviceProbe, format: i32, + depth_format: vk::Format, ) -> Result { let color_attachment = vk::AttachmentDescription::default() .format(vk::Format::from_raw(format)) @@ -299,10 +336,23 @@ fn create_render_pass( let color_attachment_ref = vk::AttachmentReference::default() .attachment(0) .layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL); + let depth_attachment = vk::AttachmentDescription::default() + .format(depth_format) + .samples(vk::SampleCountFlags::TYPE_1) + .load_op(vk::AttachmentLoadOp::CLEAR) + .store_op(vk::AttachmentStoreOp::DONT_CARE) + .stencil_load_op(vk::AttachmentLoadOp::DONT_CARE) + .stencil_store_op(vk::AttachmentStoreOp::DONT_CARE) + .initial_layout(vk::ImageLayout::UNDEFINED) + .final_layout(vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + let depth_attachment_ref = vk::AttachmentReference::default() + .attachment(1) + .layout(vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL); let color_attachments = [color_attachment_ref]; let subpass = vk::SubpassDescription::default() .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS) - .color_attachments(&color_attachments); + .color_attachments(&color_attachments) + .depth_stencil_attachment(&depth_attachment_ref); let dependency = vk::SubpassDependency::default() .src_subpass(vk::SUBPASS_EXTERNAL) .dst_subpass(0) @@ -310,7 +360,7 @@ fn create_render_pass( .dst_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT) .src_access_mask(vk::AccessFlags::empty()) .dst_access_mask(vk::AccessFlags::COLOR_ATTACHMENT_WRITE); - let attachments = [color_attachment]; + let attachments = [color_attachment, depth_attachment]; let subpasses = [subpass]; let dependencies = [dependency]; let create_info = vk::RenderPassCreateInfo::default() @@ -512,11 +562,6 @@ fn create_graphics_pipeline( extent: (u32, u32), state: LegacyPipelineState, ) -> Result { - if state.depth != LegacyDepthMode::Disabled { - return Err(VulkanSmokeRendererError::InvalidStaticMesh { - context: "static renderer has no depth attachment for requested pipeline state", - }); - } if state.alpha_test { return Err(VulkanSmokeRendererError::InvalidStaticMesh { context: @@ -604,6 +649,12 @@ fn create_graphics_pipeline( let multisample_state = vk::PipelineMultisampleStateCreateInfo::default() .sample_shading_enable(false) .rasterization_samples(vk::SampleCountFlags::TYPE_1); + let depth_stencil_state = vk::PipelineDepthStencilStateCreateInfo::default() + .depth_test_enable(state.depth != LegacyDepthMode::Disabled) + .depth_write_enable(state.depth == LegacyDepthMode::TestWrite) + .depth_compare_op(vk::CompareOp::LESS_OR_EQUAL) + .depth_bounds_test_enable(false) + .stencil_test_enable(false); let color_blend_attachment = vk::PipelineColorBlendAttachmentState::default() .color_write_mask( vk::ColorComponentFlags::R @@ -629,6 +680,7 @@ fn create_graphics_pipeline( .viewport_state(&viewport_state) .rasterization_state(&rasterization_state) .multisample_state(&multisample_state) + .depth_stencil_state(&depth_stencil_state) .color_blend_state(&color_blend_state) .layout(pipeline_layout) .render_pass(render_pass) @@ -671,9 +723,10 @@ fn create_framebuffer( device: &VulkanLogicalDeviceProbe, render_pass: vk::RenderPass, image_view: vk::ImageView, + depth_view: vk::ImageView, extent: (u32, u32), ) -> Result { - let attachments = [image_view]; + let attachments = [image_view, depth_view]; let create_info = vk::FramebufferCreateInfo::default() .render_pass(render_pass) .attachments(&attachments) @@ -738,6 +791,7 @@ pub(super) fn destroy_swapchain_resources( device .device() .destroy_render_pass(resources.render_pass, None); + destroy_depth_attachment(device, &resources.depth_attachment); for image_view in resources.image_views { device.device().destroy_image_view(image_view, None); } @@ -783,6 +837,9 @@ fn destroy_partial_swapchain_resources( if let Some(render_pass) = partial.render_pass { device.device().destroy_render_pass(render_pass, None); } + if let Some(depth_attachment) = partial.depth_attachment { + destroy_depth_attachment(device, &depth_attachment); + } for image_view in partial.image_views { device.device().destroy_image_view(image_view, None); } diff --git a/docs/tomes/05-render.md b/docs/tomes/05-render.md index 545b8db..6c0524d 100644 --- a/docs/tomes/05-render.md +++ b/docs/tomes/05-render.md @@ -845,20 +845,23 @@ swapchain resources, создаёт один `vk::Pipeline` на уникаль созданные variants. Baseline оригинального MSH подтверждён с состоянием `opaque + depth disabled + cull disabled + alpha-test disabled`. -`SourceAlpha` и front/back culling имеют Vulkan mapping в этом кэше. Запрос -depth или alpha-test сейчас завершается явной ошибкой: renderer ещё не имеет -depth attachment либо alpha-test shader variant, поэтому он не должен молча -подменять state. Также не установлен источник значений для Batch20/MAT0: их +`SourceAlpha`, front/back culling и depth modes имеют Vulkan mapping в этом +кэше. При создании swapchain resources renderer выбирает capability-approved +depth/stencil format, выделяет device-local attachment, очищает его в render +pass и прикрепляет к каждому framebuffer. `TestWrite` включает depth test и +write; `TestReadOnly` включает test без write. Alpha-test пока завершается +явной ошибкой: shader variant ещё не существует, поэтому renderer не должен +молча подменять state. Также не установлен источник значений для Batch20/MAT0: их поля нельзя объявлять blend/depth/cull mapping без dynamic capture или дополнительного дизассемблирования. Это частично реализованная compatibility boundary, а не заявление о готовой parity fixed-function state. -Выбор будущего depth/stencil attachment уже отделён от renderer lifetime: +Выбор depth/stencil attachment отделён от renderer lifetime: `select_depth_stencil_attachment_format` применяет тот же фиксированный порядок форматов, что и capability gate, к фактически поддерживаемому списку GPU. Это исключает ситуацию, когда admission принимает один совместимый формат, а -allocation позднее выбирает другой; сам attachment и render-pass integration -остаются следующей отдельной задачей. +allocation позднее выбирает другой; resource уничтожается после framebuffer и +render pass при recreate/teardown. После последнего world pass renderer закрывает сцену и выводит back buffer. World3D снимает `in_render`, восстанавливает временный viewport state и вызывает diff --git a/fixtures/acceptance/coverage.tsv b/fixtures/acceptance/coverage.tsv index 6177c75..89de6d9 100644 --- a/fixtures/acceptance/coverage.tsv +++ b/fixtures/acceptance/coverage.tsv @@ -297,7 +297,7 @@ 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 --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 --model-archive system.rlb --model-name MTCHECK.MSH --texture-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 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 --model-archive system.rlb --model-name MTCHECK.MSH --texture-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 covered-gpu cargo run -p fparkan-vulkan-smoke --release --locked -- --out target/fparkan/stage3-pipeline-key-cache-smoke.json --frames 300 --resize-frame 120 --timeout-seconds 90 --model-root --model-archive system.rlb --model-name MTCHECK.MSH --texture-root --texture-archive Textures.lib --texture-name DEFAULT.0; PipelineKey selects a deduplicated live Vulkan pipeline per static draw range (baseline key only); unproven Batch20/MAT0 state mapping and unsupported depth/alpha-test variants remain explicit gaps +S3-VK-PIPELINE-001 covered-gpu cargo run -p fparkan-vulkan-smoke --release --locked -- --out target/fparkan/stage3-depth-attachment-smoke.json --frames 300 --resize-frame 120 --timeout-seconds 90 --model-root --model-archive system.rlb --model-name MTCHECK.MSH --texture-root --texture-archive Textures.lib --texture-name DEFAULT.0; PipelineKey selects a deduplicated live Vulkan pipeline per static draw range; capability-selected device-local depth attachment supports TestWrite/TestReadOnly, baseline key is live-proven; unproven Batch20/MAT0 state mapping and unsupported alpha-test remain explicit gaps S3-VK-DRAW-MODEL-001 covered-gpu cargo run -p fparkan-vulkan-smoke --release --locked -- --out target/fparkan/stage3-fr-l-mtp-per-batch-materials.json --frames 300 --resize-frame 120 --timeout-seconds 90 --model-root --model-archive fortif.rlb --model-name FR_L_MTP.msh --wear-root --wear-archive fortif.rlb --wear-name FR_L_MTP.WEA; live Win32 Vulkan issues 237 source-preserving indexed batch draws and binds the deduplicated WEAR→MAT0 material descriptor selected by each Batch20.material_index (this corpus model has selector 0 only) S3-VK-DRAW-TERRAIN-001 blocked awaits Stage 3 terrain Vulkan draw path S3-VK-PIXEL-CAPTURE-001 blocked awaits Stage 3 fixed-camera pixel capture approval flow