From 1029511bbc135262e30fe0edb308ee09e22f7472 Mon Sep 17 00:00:00 2001 From: nmzik Date: Sun, 11 Oct 2026 08:08:50 +0200 Subject: [PATCH] add depth to color copy Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com> --- src/graphics/host_gpu/graphicContext.h | 1 + .../host_gpu/renderer/depthRenderTarget.cpp | 10 +++- src/graphics/host_gpu/renderer/render.h | 2 + src/graphics/host_gpu/renderer/renderDraw.cpp | 59 +++++++++++++++++++ .../presentation/window/vulkanWindow.cpp | 15 +++++ 5 files changed, 85 insertions(+), 2 deletions(-) diff --git a/src/graphics/host_gpu/graphicContext.h b/src/graphics/host_gpu/graphicContext.h index d579eeee..113a086d 100644 --- a/src/graphics/host_gpu/graphicContext.h +++ b/src/graphics/host_gpu/graphicContext.h @@ -33,6 +33,7 @@ struct GraphicContext { // bool fp64_denorm_preserve = false; // Temporarily disabled. bool attachment_feedback_loop_enabled = false; bool provoking_vertex_last_enabled = false; + bool depth_color_copy_enabled = false; bool supports_block_texel_view = false; bool mesh_shader_enabled = false; vk::PhysicalDeviceMeshShaderPropertiesEXT mesh_shader_properties = {}; diff --git a/src/graphics/host_gpu/renderer/depthRenderTarget.cpp b/src/graphics/host_gpu/renderer/depthRenderTarget.cpp index 033e9ac6..9a14b674 100644 --- a/src/graphics/host_gpu/renderer/depthRenderTarget.cpp +++ b/src/graphics/host_gpu/renderer/depthRenderTarget.cpp @@ -298,14 +298,20 @@ void RenderExecutor::ResolveRenderDepthTarget(CommandBuffer& buffer, RenderDepth } return; } - // Centroid/sample selectors only affect depth/stencil-to-color copies. - if (rc.copy_depth_to_color || rc.copy_stencil_to_color || + if (rc.copy_stencil_to_color || dc.zfunc > static_cast(vk::CompareOp::eAlways) || (!z.depth_view.depth_write_disable && z.z_write_base_addr != z.z_read_base_addr) || (has_stencil && !z.depth_view.stencil_write_disable && z.stencil_write_base_addr != z.stencil_read_base_addr)) { DepthFatal("unsupported depth register state"); } + if (rc.copy_depth_to_color && + (z.z_info.num_samples != 0 || rc.copy_sample != 0 || + z.z_info.format != Prospero::DepthFormat::kZ32F || + dc.z_enable || dc.z_write_enable || dc.depth_bounds_enable || dc.stencil_enable || + rc.depth_clear_enable || rc.stencil_clear_enable)) { + DepthFatal("unsupported depth-to-color copy state"); + } r.desc = MakeDepthTargetDesc(buffer, z); r.depth_clear_enable = rc.depth_clear_enable; r.depth_load_clear_enable = r.depth_clear_enable; diff --git a/src/graphics/host_gpu/renderer/render.h b/src/graphics/host_gpu/renderer/render.h index 39ae92dc..a08c43b8 100644 --- a/src/graphics/host_gpu/renderer/render.h +++ b/src/graphics/host_gpu/renderer/render.h @@ -186,6 +186,8 @@ private: bool ignore_target_mask = false, bool exact_format = false); void ResolveRenderDepthTarget(CommandBuffer& buffer, RenderDepthInfo& target); [[nodiscard]] bool DepthStencilCopy(CommandBuffer& buffer); + [[nodiscard]] bool CopyDepthToColor(CommandBuffer& buffer, const DrawCallInfo& draw, + const DrawEmitInfo& emit, DrawRenderState& state); [[nodiscard]] bool PrepareDrawRenderState(CommandBuffer& buffer, const DrawCallInfo& draw, uint32_t render_target_slice_offset, diff --git a/src/graphics/host_gpu/renderer/renderDraw.cpp b/src/graphics/host_gpu/renderer/renderDraw.cpp index f088fff4..fb007103 100644 --- a/src/graphics/host_gpu/renderer/renderDraw.cpp +++ b/src/graphics/host_gpu/renderer/renderDraw.cpp @@ -1029,12 +1029,71 @@ static void EmitDrawPrimitives(const HW::UserConfig& ucfg, vk::CommandBuffer vk_ } } +bool RenderExecutor::CopyDepthToColor(CommandBuffer& buffer, const DrawCallInfo& draw, + const DrawEmitInfo& emit, DrawRenderState& state) { + if (!buffer.GetRegisters().GetRenderControl().copy_depth_to_color) { + return false; + } + auto& ucfg = buffer.GetUserConfig(); + const auto& hw = buffer.GetRegisters(); + auto& depth = state.depth_info; + auto& color = state.color_info[0]; + EXIT_NOT_IMPLEMENTED(!m_context.GetGraphics().depth_color_copy_enabled || + !Prospero::IsRectList(ucfg.GetPrimType()) || + draw.IsIndexed() || draw.index_count != 3 || draw.instance_count != 1 || + emit.first_vertex != 0 || emit.first_instance != 0 || + state.color_count != 1 || color.target_slot != 0 || !depth.image_id || + color.desc.info.samples != 1 || + depth.desc.info.extent.width != color.Extent().width || + depth.desc.info.extent.height != color.Extent().height || + depth.desc.view_info.layer_count != 1 || + color.desc.view_info.layer_count != 1 || + hw.GetBlendControl(0).enable || state.ps_input_info.ps_pixel_kill_enable || + state.ps_input_info.ps_depth_export_enable || + state.ps_input_info.ps_sample_mask_export_enable); + vk::ImageAspectFlags feedback; + const auto rendering = AcquireRenderTargets(buffer, &color, 1, depth, feedback); + if (depth.depth_load_clear_enable) { + m_context.GetCommandScheduler().BeginRendering(rendering); + } + auto& cache = m_context.GetTextureCache(); + auto& source = cache.GetImage(depth.image_id); + auto& destination = cache.GetImage(color.image_id); + EXIT_NOT_IMPLEMENTED((source.backing.format != vk::Format::eD32Sfloat && + source.backing.format != vk::Format::eD32SfloatS8Uint) || + destination.backing.format != vk::Format::eR32Sfloat); + const auto rect = calc_final_scissor(hw.GetScreenViewport(), hw.GetScanModeControl(), + {rendering.width, rendering.height}, 0); + if (rect.right > rect.left && rect.bottom > rect.top) { + const vk::ImageCopy region { + {vk::ImageAspectFlagBits::eDepth, depth.desc.view_info.base_level, + depth.desc.view_info.base_layer, 1}, {rect.left, rect.top, 0}, + {vk::ImageAspectFlagBits::eColor, color.desc.view_info.base_level, + color.desc.view_info.base_layer, 1}, {rect.left, rect.top, 0}, + {static_cast(rect.right - rect.left), + static_cast(rect.bottom - rect.top), 1}}; + m_context.GetCommandScheduler().EndRendering(); + const auto command = buffer.Handle(); + source.Transit(vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlagBits2::eTransferRead, + {}, command); + destination.Transit(vk::ImageLayout::eTransferDstOptimal, + vk::AccessFlagBits2::eTransferWrite, {}, command); + command.copyImage(source.backing.image, vk::ImageLayout::eTransferSrcOptimal, + destination.backing.image, vk::ImageLayout::eTransferDstOptimal, + 1, ®ion); + } + return true; +} + void RenderExecutor::ExecutePreparedDraw(uint64_t submit_id, CommandBuffer& buffer, const DrawCallInfo& draw, DrawRenderState& state, vk::PrimitiveTopology topology, const DrawEmitInfo& emit, const DrawIndexBufferSource& index_source, bool primitive_restart_enable) { auto& ucfg = buffer.GetUserConfig(); + if (CopyDepthToColor(buffer, draw, emit, state)) { + return; + } const auto vertex_stages = std::span {state.vertex_info.data(), state.programs.VertexStageCount()}; const bool mesh_active = state.vertex_info[0].stage.program->stage == ShaderType::Mesh; diff --git a/src/graphics/presentation/window/vulkanWindow.cpp b/src/graphics/presentation/window/vulkanWindow.cpp index ab03572e..43cc734d 100644 --- a/src/graphics/presentation/window/vulkanWindow.cpp +++ b/src/graphics/presentation/window/vulkanWindow.cpp @@ -478,6 +478,13 @@ static vk::Device VulkanCreateDevice(GraphicContext& graphics, provoking_vertex.pNext = supported_features2.pNext; supported_features2.pNext = &provoking_vertex; } + const bool maintenance8_extension = + HasExtension(device_extensions, VK_KHR_MAINTENANCE_8_EXTENSION_NAME); + vk::PhysicalDeviceMaintenance8FeaturesKHR maintenance8 {}; + if (maintenance8_extension) { + maintenance8.pNext = supported_features2.pNext; + supported_features2.pNext = &maintenance8; + } const bool image_atomic_int64_extension = HasExtension(device_extensions, VK_EXT_SHADER_IMAGE_ATOMIC_INT64_EXTENSION_NAME); vk::PhysicalDeviceShaderImageAtomicInt64FeaturesEXT image_atomic_int64 {}; @@ -542,6 +549,9 @@ static vk::Device VulkanCreateDevice(GraphicContext& graphics, graphics.attachment_feedback_loop_enabled = feedback_extensions && feedback_layout.attachmentFeedbackLoopLayout && feedback_dynamic.attachmentFeedbackLoopDynamicState; + graphics.depth_color_copy_enabled = maintenance8_extension && maintenance8.maintenance8; + LOGF("Vulkan depth/color copy support: %s\n", + graphics.depth_color_copy_enabled ? "true" : "false"); LOGF("Vulkan depth feedback support: %s\n", graphics.attachment_feedback_loop_enabled ? "true" : "false"); if (graphics.mesh_shader_enabled) { @@ -638,6 +648,10 @@ static vk::Device VulkanCreateDevice(GraphicContext& graphics, image_atomic_int64.sparseImageInt64Atomics = VK_FALSE; create_info.pNext = &image_atomic_int64; } + if (graphics.depth_color_copy_enabled) { + maintenance8.pNext = const_cast(create_info.pNext); + create_info.pNext = &maintenance8; + } create_info.pQueueCreateInfos = &queue_create_info; create_info.queueCreateInfoCount = 1; create_info.enabledExtensionCount = static_cast(device_extensions.size()); @@ -1002,6 +1016,7 @@ void WindowContext::CreateVulkan() { graphic_ctx.memory_budget_ext_enabled = true; } for (const auto* extension: {VK_EXT_ROBUSTNESS_2_EXTENSION_NAME, + VK_KHR_MAINTENANCE_8_EXTENSION_NAME, VK_EXT_SHADER_IMAGE_ATOMIC_INT64_EXTENSION_NAME, VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME, VK_EXT_MESH_SHADER_EXTENSION_NAME,