From 2c7ee7ea6840b1565ca59e79d8c1f2dae27aaac2 Mon Sep 17 00:00:00 2001 From: Dipshet <264011288+Dipshet@users.noreply.github.com> Date: Wed, 8 Jul 2026 20:54:59 +0300 Subject: [PATCH] Fix cull the sun-flare's spurious second billboard (flare "square") The sun lens-flare draw (VS ADF9AFC4C10921B9 emits two billboards: V0-V3 = the visible glow quad, V4-V7 = a malformed quad that mis-renders in the emulator as a faint bright rectangle in the sky (the "square"). Cull it in the vertex shader using the translator's existing kill-vertex mechanism: in CompleteVertexOrDomainShader, for this ucode hash (plain host VS only), vertices with SV_VertexID >= ac6_flare_drop_index_min (default 4) get a NaN output position, so the rasterizer discards the primitive. The real glow (V0-V3) is untouched. cvars: ac6_flare_drop_quad2 (bool, default true), ac6_flare_drop_index_min (int32, default 4). Baked at shader translation. --- .../rexglue-sdk/include/rex/graphics/flags.h | 4 +++ thirdparty/rexglue-sdk/src/graphics/flags.cpp | 6 ++++ .../pipeline/shader/dxbc_translator.cpp | 30 +++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/thirdparty/rexglue-sdk/include/rex/graphics/flags.h b/thirdparty/rexglue-sdk/include/rex/graphics/flags.h index b8033c8a..58d9bb87 100644 --- a/thirdparty/rexglue-sdk/include/rex/graphics/flags.h +++ b/thirdparty/rexglue-sdk/include/rex/graphics/flags.h @@ -39,6 +39,10 @@ REXCVAR_DECLARE(bool, readback_memexport_fast); REXCVAR_DECLARE(bool, occlusion_query_enable); REXCVAR_DECLARE(int32_t, query_occlusion_fake_sample_count); +// AC6 sun-flare "square" fix (drop the flare's spurious second billboard) +REXCVAR_DECLARE(bool, ac6_flare_drop_quad2); +REXCVAR_DECLARE(int32_t, ac6_flare_drop_index_min); + // GPU Depth / Render Target Behavior REXCVAR_DECLARE(bool, depth_float24_round); REXCVAR_DECLARE(bool, depth_float24_convert_in_pixel_shader); diff --git a/thirdparty/rexglue-sdk/src/graphics/flags.cpp b/thirdparty/rexglue-sdk/src/graphics/flags.cpp index dd54dcc9..da18cc0e 100644 --- a/thirdparty/rexglue-sdk/src/graphics/flags.cpp +++ b/thirdparty/rexglue-sdk/src/graphics/flags.cpp @@ -65,6 +65,12 @@ REXCVAR_DEFINE_STRING(ac6_neutralize_deswizzle_hashes, "", "GPU/Shader", "Xenos tfetch slot 4 (needed when only some fetches de-swizzle, e.g. " "the AC6 cloud compositor: scene fetch de-swizzles, mask/cloud " "fetches use plain UVs and must be left alone). Runtime, no rebuild."); +REXCVAR_DEFINE_BOOL(ac6_flare_drop_quad2, true, "GPU/Shader", + "AC6: cull the sun lens-flare's spurious second billboard " + "(vertices 4-7) to remove the faint rectangle in the sky"); +REXCVAR_DEFINE_INT32(ac6_flare_drop_index_min, 4, "GPU/Shader", + "AC6: first vertex index of the flare draw to cull (the " + "spurious billboard is vertices 4-7 of 8)"); REXCVAR_DEFINE_BOOL(gpu_debug_markers, false, "GPU", "Insert debug markers into GPU command streams for tools " "like PIX and RenderDoc. Automatically enabled when " diff --git a/thirdparty/rexglue-sdk/src/graphics/pipeline/shader/dxbc_translator.cpp b/thirdparty/rexglue-sdk/src/graphics/pipeline/shader/dxbc_translator.cpp index e3833e26..ff7c9e7c 100644 --- a/thirdparty/rexglue-sdk/src/graphics/pipeline/shader/dxbc_translator.cpp +++ b/thirdparty/rexglue-sdk/src/graphics/pipeline/shader/dxbc_translator.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -1031,6 +1032,35 @@ void DxbcShaderTranslator::CompleteVertexOrDomainShader() { } } + // AC6 sun-flare "square" fix - drop the flare's second billboard + // This VS (ADF9AFC4C10921B9) emits two billboards per flare draw: V0-V3 = + // the visible glow quad, V4-V7 = a huge malformed quad (corners far + // off-screen, garbage UVs) that is invisible on real hardware but + // mis-renders in the emulator as a faint bright-edged rectangle. Cull it + // the same way as kill-vertex above: NaN the output position of vertices + // with index >= the threshold so the rasterizer discards the primitive. + // V0-V3 (the real glow) are untouched. + if (REXCVAR_GET(ac6_flare_drop_quad2) && + current_shader().ucode_data_hash() == 0xADF9AFC4C10921B9ull && + GetDxbcShaderModification().vertex.host_vertex_shader_type == + Shader::HostVertexShaderType::kVertex) { + int32_t ac6_drop_index_min = REXCVAR_GET(ac6_flare_drop_index_min); + if (ac6_drop_index_min < 0) { + ac6_drop_index_min = 0; + } + uint32_t ac6_drop_temp = PushSystemTemp(); + // ac6_drop_temp.x = (SV_VertexID >= index_min) ? 0xFFFFFFFF : 0 + a_.OpUGE(dxbc::Dest::R(ac6_drop_temp, 0b0001), + dxbc::Src::V1D(kInRegisterVSVertexIndex, dxbc::Src::kXXXX), + dxbc::Src::LU(uint32_t(ac6_drop_index_min))); + // NaN the whole position of culled vertices. + a_.OpMovC(dxbc::Dest::R(system_temp_position_, 0b1111), + dxbc::Src::R(ac6_drop_temp, dxbc::Src::kXXXX), + dxbc::Src::LF(std::nanf("")), dxbc::Src::R(system_temp_position_)); + // Release ac6_drop_temp. + PopSystemTemp(); + } + // Write the position to the output. a_.OpMov(dxbc::Dest::O(out_reg_vs_position_), dxbc::Src::R(system_temp_position_));