From 3e48eedecf91f8f8d0917f8f78ce26a3d0482e5c Mon Sep 17 00:00:00 2001 From: Takoroka <137927095+Takoroka@users.noreply.github.com> Date: Wed, 28 Oct 2026 02:45:00 -0400 Subject: nx2: title 4's cutscene scene renders; blit constants for fragment shaders - Render area falls back to colour target 0 when the surface clip is unset (Switch 2 titles may never program it); it feeds the synthesized blit block. - BlitConstantsPass also covers fragment shaders: UV clamp rectangle 0..1 (0x30-0x3c) and zero dither bias. - Debug: EDEN_NX2_SKIP_VS=, EDEN_NX2_TRACE_VS=, EDEN_NX2_UPSCALE_SOURCE[_FORMAT], EDEN_NX2_TRACE_AFTER_UPSCALE, EDEN_NX2_SAMPLE_AT, skipped-draw reasons, clear tracing. Showing the raw HDR scene colour through the upscale fallback gives the correct lit cockpit scene; the game's tonemap pass still outputs black. --- src/video_core/renderer_vulkan/vk_rasterizer.cpp | 85 +++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) (limited to 'src/video_core/renderer_vulkan/vk_rasterizer.cpp') diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 47a55c9580..1b05716653 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -256,15 +256,28 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) { FlushWork(); gpu_memory->FlushCaching(); + const auto report_failure = [&](std::string_view reason) { + static std::set> seen; + const auto& regs = maxwell3d->regs; + const u64 vs = (u64{regs.pipelines[1].reserved[0] & 0xff} << 32) | regs.pipelines[1].reserved[1]; + const u64 ps = (u64{regs.pipelines[5].reserved[0] & 0xff} << 32) | regs.pipelines[5].reserved[1]; + if (seen.size() < 64 && seen.emplace(vs, ps, reason).second) { + LOG_WARNING(HW_GPU, "Draw skipped ({}): vs={:#x} ps={:#x} rt0={:#x} {}x{}", reason, vs, ps, + regs.rt[0].Address(), regs.rt[0].width, regs.rt[0].height); + } + }; GraphicsPipeline* const pipeline{pipeline_cache.CurrentGraphicsPipeline()}; if (!pipeline) { + report_failure("no pipeline"); return; } std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; // update engine as channel may be different. pipeline->SetEngine(maxwell3d, gpu_memory); - if (!pipeline->Configure(is_indexed)) + if (!pipeline->Configure(is_indexed)) { + report_failure("configure failed"); return; + } UpdateDynamicStates(); @@ -428,6 +441,69 @@ void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) { } } } + // EDEN_NX2_TRACE_VS=
: describe the next few draws using that vertex shader like the + // after-upscale trace does (render target, blend, fragment textures). + static const u64 trace_vs = [] { + const char* value = std::getenv("EDEN_NX2_TRACE_VS"); + return value ? std::strtoull(value, nullptr, 16) : 0ULL; + }(); + if (trace_vs != 0) { + const auto& regs = maxwell3d->regs; + const u64 vs = (u64{regs.pipelines[1].reserved[0] & 0xff} << 32) | regs.pipelines[1].reserved[1]; + static u32 traced{}; + if (vs == trace_vs && traced++ % 200 == 0 && traced < 1000) { + Tegra::Engines::g_nx2_trace_draws_after_upscale = 1; + } + } + if (Tegra::Engines::g_nx2_trace_draws_after_upscale > 0) { + --Tegra::Engines::g_nx2_trace_draws_after_upscale; + const auto& regs = maxwell3d->regs; + const u64 vs = (u64{regs.pipelines[1].reserved[0] & 0xff} << 32) | regs.pipelines[1].reserved[1]; + const u64 ps = (u64{regs.pipelines[5].reserved[0] & 0xff} << 32) | regs.pipelines[5].reserved[1]; + LOG_INFO(HW_GPU, "after upscale: draw rt0 {:#x} {}x{} fmt {:#x} block {}/{}/{} pitch_linear {} depth {} array_pitch {:#x} ctrl {:#x} vs {:#x} ps {:#x}", + regs.rt[0].Address(), regs.rt[0].width, regs.rt[0].height, + static_cast(regs.rt[0].format), regs.rt[0].tile_mode.block_width.Value(), + regs.rt[0].tile_mode.block_height.Value(), regs.rt[0].tile_mode.block_depth.Value(), + regs.rt[0].tile_mode.is_pitch_linear.Value(), regs.rt[0].depth.Value(), + regs.rt[0].array_pitch, regs.rt_control.count.Value(), vs, ps); + // Fragment-stage texture handles (bound buffer 2) and the images they name. + const auto& handles = maxwell3d->state.shader_stages[4].const_buffers[2]; + if (handles.enabled) { + for (u32 i = 0; i < 24; ++i) { + const u32 handle = gpu_memory->Read(handles.address + i * 4); + if (handle == 0 || handle == 0xffffffff) continue; + Tegra::Texture::TICEntry tic{}; + gpu_memory->ReadBlockUnsafe(regs.tex_header.Address() + u64{handle & 0xfffff} * sizeof(tic), + &tic, sizeof(tic)); + LOG_INFO(HW_GPU, " fs handle[{}] = {:#x}: {:#x} {}x{} format {:#x}", i, handle, + tic.Address(), tic.Width(), tic.Height(), static_cast(tic.format.Value())); + } + } + const auto& bt = regs.blend_per_target[0]; + LOG_INFO(HW_GPU, " blend enable {} per-target {} global op {} src {:#x} dst {:#x} | rt0 op {} src {:#x} dst {:#x} alpha {:#x}/{:#x} mask {:#x}", + regs.blend.enable[0], regs.blend_per_target_enabled, + static_cast(regs.blend.color_op), static_cast(regs.blend.color_source), + static_cast(regs.blend.color_dest), static_cast(bt.color_op), + static_cast(bt.color_source), static_cast(bt.color_dest), + static_cast(bt.alpha_source), static_cast(bt.alpha_dest), + regs.color_mask[0].raw); + } + // EDEN_NX2_SKIP_VS=
[,
...]: drop draws using those vertex shaders (debug aid). + static const std::vector skip_list = [] { + std::vector list; + if (const char* value = std::getenv("EDEN_NX2_SKIP_VS")) { + for (char* end = nullptr; *value; value = *end ? end + 1 : end) { + list.push_back(std::strtoull(value, &end, 16)); + if (end == value) break; + } + } + return list; + }(); + if (!skip_list.empty()) { + const auto& regs = maxwell3d->regs; + const u64 vs = (u64{regs.pipelines[1].reserved[0] & 0xff} << 32) | regs.pipelines[1].reserved[1]; + if (std::find(skip_list.begin(), skip_list.end(), vs) != skip_list.end()) return; + } // EDEN_NX2_RT_TRACE: log the first draw to every distinct colour target (debug aid). if (static const bool trace = std::getenv("EDEN_NX2_RT_TRACE") != nullptr; trace) { static std::set> seen; @@ -580,6 +656,13 @@ void RasterizerVulkan::DrawTexture() { } void RasterizerVulkan::Clear(u32 layer_count) { + if (Tegra::Engines::g_nx2_trace_draws_after_upscale > 0) { + const auto& regs = maxwell3d->regs; + LOG_INFO(HW_GPU, "after upscale: clear rt0 {:#x} {}x{} fmt {:#x} surface {:#x} colour {} {} {} {}", + regs.rt[0].Address(), regs.rt[0].width, regs.rt[0].height, + static_cast(regs.rt[0].format), regs.clear_surface.raw, regs.clear_color[0], + regs.clear_color[1], regs.clear_color[2], regs.clear_color[3]); + } TraceWindowTarget(*maxwell3d, *gpu_memory, "clear", layer_count); FlushWork(); gpu_memory->FlushCaching(); -- cgit v1.2.3