From d3c67d2bfd7255fc175cb2604067084c460ec9a3 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Wed, 20 May 2026 05:03:32 -0700 Subject: [PATCH] Use special conditional survey shader instead of guest shader specialization Fixes alpha test issues from the conditional survey logic needing early fragment test. --- MarathonRecomp/CMakeLists.txt | 5 ++-- .../shader/hlsl/conditional_survey_ps.hlsl | 8 ++++++ .../shader/msl/conditional_survey_ps.metal | 10 +++++++ MarathonRecomp/gpu/video.cpp | 28 ++++++++++++++----- MarathonRecomp/gpu/video.h | 3 -- tools/XenosRecomp | 2 +- 6 files changed, 43 insertions(+), 13 deletions(-) create mode 100644 MarathonRecomp/gpu/shader/hlsl/conditional_survey_ps.hlsl create mode 100644 MarathonRecomp/gpu/shader/msl/conditional_survey_ps.metal diff --git a/MarathonRecomp/CMakeLists.txt b/MarathonRecomp/CMakeLists.txt index 509443847..1399812ec 100644 --- a/MarathonRecomp/CMakeLists.txt +++ b/MarathonRecomp/CMakeLists.txt @@ -157,7 +157,7 @@ set(MARATHON_RECOMP_UI_CXX_SOURCES "ui/achievement_menu.cpp" "ui/achievement_overlay.cpp" "ui/black_bar.cpp" - "ui/button_window.cpp" + "ui/button_window.cpp" "ui/common_menu.cpp" "ui/fader.cpp" "ui/game_window.cpp" @@ -481,6 +481,7 @@ function(compile_pixel_shader FILE_PATH) endfunction() compile_pixel_shader(blend_color_alpha_ps) +compile_pixel_shader(conditional_survey_ps) compile_vertex_shader(copy_vs) compile_pixel_shader(copy_color_ps) compile_pixel_shader(copy_depth_ps) @@ -549,7 +550,7 @@ BIN2C(TARGET_OBJ MarathonRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/com BIN2C(TARGET_OBJ MarathonRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/main_menu9.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/main_menu9.dds" ARRAY_NAME "g_main_menu9" COMPRESSION_TYPE "zstd") BIN2C(TARGET_OBJ MarathonRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/arrow.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/arrow.dds" ARRAY_NAME "g_arrow" COMPRESSION_TYPE "zstd") BIN2C(TARGET_OBJ MarathonRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/window.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/window.dds" ARRAY_NAME "g_window" COMPRESSION_TYPE "zstd") -BIN2C(TARGET_OBJ MarathonRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/select_arrow.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/select_arrow.dds" ARRAY_NAME "g_select_arrow" COMPRESSION_TYPE "zstd") +BIN2C(TARGET_OBJ MarathonRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/select_arrow.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/select_arrow.dds" ARRAY_NAME "g_select_arrow" COMPRESSION_TYPE "zstd") ## Installer ## BIN2C(TARGET_OBJ MarathonRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/install_001.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/install_001.dds" ARRAY_NAME "g_install_001" COMPRESSION_TYPE "zstd") diff --git a/MarathonRecomp/gpu/shader/hlsl/conditional_survey_ps.hlsl b/MarathonRecomp/gpu/shader/hlsl/conditional_survey_ps.hlsl new file mode 100644 index 000000000..64a30a6ff --- /dev/null +++ b/MarathonRecomp/gpu/shader/hlsl/conditional_survey_ps.hlsl @@ -0,0 +1,8 @@ +#include "../../../../tools/XenosRecomp/XenosRecomp/shader_common.h" + +[earlydepthstencil] +float4 shaderMain() : SV_Target +{ + atomicFetchAddUint(g_ConditionalSurveyBuffer, g_conditionalSurveyIndex, 1); + return float4(0.0, 0.0, 0.0, 0.0); +} diff --git a/MarathonRecomp/gpu/shader/msl/conditional_survey_ps.metal b/MarathonRecomp/gpu/shader/msl/conditional_survey_ps.metal new file mode 100644 index 000000000..5707d50ad --- /dev/null +++ b/MarathonRecomp/gpu/shader/msl/conditional_survey_ps.metal @@ -0,0 +1,10 @@ +#include "../../../../tools/XenosRecomp/XenosRecomp/shader_common.h" + +[[fragment]] +[[early_fragment_tests]] +float4 shaderMain(device AtomicUintBuffer* g_ConditionalSurveyBuffer [[buffer(4)]], + constant PushConstants& g_PushConstants [[buffer(8)]]) +{ + atomicFetchAddUint(g_ConditionalSurveyBuffer, g_conditionalSurveyIndex, 1); + return float4(0.0, 0.0, 0.0, 0.0); +} diff --git a/MarathonRecomp/gpu/video.cpp b/MarathonRecomp/gpu/video.cpp index 4677c9add..3a4393d1f 100644 --- a/MarathonRecomp/gpu/video.cpp +++ b/MarathonRecomp/gpu/video.cpp @@ -40,10 +40,12 @@ #include #endif +#define MARATHON_RECOMP #include "../../tools/XenosRecomp/XenosRecomp/shader_common.h" #ifdef MARATHON_RECOMP_D3D12 #include "shader/hlsl/blend_color_alpha_ps.hlsl.dxil.h" +#include "shader/hlsl/conditional_survey_ps.hlsl.dxil.h" #include "shader/hlsl/copy_vs.hlsl.dxil.h" #include "shader/hlsl/copy_color_ps.hlsl.dxil.h" #include "shader/hlsl/copy_depth_ps.hlsl.dxil.h" @@ -69,6 +71,7 @@ #ifdef MARATHON_RECOMP_METAL #include "shader/msl/blend_color_alpha_ps.metal.metallib.h" +#include "shader/msl/conditional_survey_ps.metal.metallib.h" #include "shader/msl/copy_vs.metal.metallib.h" #include "shader/msl/copy_color_ps.metal.metallib.h" #include "shader/msl/copy_depth_ps.metal.metallib.h" @@ -93,6 +96,7 @@ #endif #include "shader/hlsl/blend_color_alpha_ps.hlsl.spirv.h" +#include "shader/hlsl/conditional_survey_ps.hlsl.spirv.h" #include "shader/hlsl/copy_vs.hlsl.spirv.h" #include "shader/hlsl/copy_color_ps.hlsl.spirv.h" #include "shader/hlsl/copy_depth_ps.hlsl.spirv.h" @@ -188,6 +192,7 @@ struct PipelineState RenderFormat depthStencilFormat{}; RenderSampleCounts sampleCount = RenderSampleCount::COUNT_1; bool enableAlphaToCoverage = false; + bool enableConditionalSurvey = false; uint32_t specConstants = 0; }; #pragma pack(pop) @@ -1488,6 +1493,8 @@ static GuestShader* g_csdShader; static std::unique_ptr g_enhancedBurnoutBlurVSShader; static std::unique_ptr g_enhancedBurnoutBlurPSShader; +static std::unique_ptr g_conditionalSurveyPSShader; + #if defined(MARATHON_RECOMP_D3D12) #define CREATE_SHADER(NAME) \ @@ -2245,6 +2252,9 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver, bool graphicsApiRetry) g_enhancedBurnoutBlurPSShader = std::make_unique(ResourceType::PixelShader); g_enhancedBurnoutBlurPSShader->shader = CREATE_SHADER(enhanced_burnout_blur_ps); + g_conditionalSurveyPSShader = std::make_unique(ResourceType::PixelShader); + g_conditionalSurveyPSShader->shader = CREATE_SHADER(conditional_survey_ps); + CreateImGuiBackend(); auto gammaCorrectionShader = CREATE_SHADER(gamma_correction_ps); @@ -4518,7 +4528,12 @@ static std::unique_ptr CreateGraphicsPipeline(const PipelineStat RenderGraphicsPipelineDesc desc; desc.pipelineLayout = g_pipelineLayout.get(); desc.vertexShader = GetOrLinkShader(pipelineState.vertexShader, pipelineState.specConstants); - desc.pixelShader = pipelineState.pixelShader != nullptr ? GetOrLinkShader(pipelineState.pixelShader, pipelineState.specConstants) : nullptr; + if (pipelineState.enableConditionalSurvey) + desc.pixelShader = GetOrLinkShader(g_conditionalSurveyPSShader.get(), pipelineState.specConstants); + else if (pipelineState.pixelShader != nullptr) + desc.pixelShader = GetOrLinkShader(pipelineState.pixelShader, pipelineState.specConstants); + else + desc.pixelShader = nullptr; desc.depthFunction = pipelineState.zFunc; desc.depthEnabled = pipelineState.zEnable; desc.depthWriteEnabled = pipelineState.zWriteEnable; @@ -4666,6 +4681,7 @@ static RenderPipeline* CreateGraphicsPipelineInRenderThread(PipelineState pipeli " depthStencilFormat: {}\n" " sampleCount: {}\n" " enableAlphaToCoverage: {}\n" + " enableConditionalSurvey: {}\n" " specConstants: {:X}\n", hash, pipelineState.vertexShader->name, @@ -4708,6 +4724,7 @@ static RenderPipeline* CreateGraphicsPipelineInRenderThread(PipelineState pipeli magic_enum::enum_name(pipelineState.depthStencilFormat), pipelineState.sampleCount, pipelineState.enableAlphaToCoverage, + pipelineState.enableConditionalSurvey, pipelineState.specConstants) + g_pipelineDebugText; } @@ -5720,7 +5737,6 @@ static void EndConditionalSurvey(GuestDevice* device) static void ProcSetConditionalSurvey(const RenderCommand& cmd) { - uint32_t specConstants = g_pipelineState.specConstants; if (cmd.setConditionalSurvey.enabled) { // Clear previous survey result first. @@ -5734,13 +5750,9 @@ static void ProcSetConditionalSurvey(const RenderCommand& cmd) commandList->barriers(RenderBarrierStage::GRAPHICS, RenderBufferBarrier(g_conditionalSurveyBuffer.get(), RenderBufferAccess::READ | RenderBufferAccess::WRITE)); g_tempBuffers[g_frame].emplace_back(std::move(uploadBuffer)); - - specConstants |= SPEC_CONSTANT_CONDITIONAL_SURVEY; } - else - specConstants &= ~SPEC_CONSTANT_CONDITIONAL_SURVEY; - SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.specConstants, specConstants); + SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.enableConditionalSurvey, cmd.setConditionalSurvey.enabled); SetDirtyValue(g_dirtyStates.sharedConstants, g_sharedConstants.conditionalSurveyIndex, cmd.setConditionalSurvey.index); } @@ -7694,6 +7706,7 @@ class SDLEventListenerForPSOCaching : public SDLEventListener "RenderFormat::{}," "{}," "{}," + "{}," "0x{:X} }},", pipelineState.vertexShader->shaderCacheEntry->hash, pipelineState.pixelShader != nullptr ? pipelineState.pixelShader->shaderCacheEntry->hash : 0, @@ -7747,6 +7760,7 @@ class SDLEventListenerForPSOCaching : public SDLEventListener magic_enum::enum_name(pipelineState.depthStencilFormat), pipelineState.sampleCount, pipelineState.enableAlphaToCoverage, + pipelineState.enableConditionalSurvey, pipelineState.specConstants); } diff --git a/MarathonRecomp/gpu/video.h b/MarathonRecomp/gpu/video.h index 09f78f263..0d58732e2 100644 --- a/MarathonRecomp/gpu/video.h +++ b/MarathonRecomp/gpu/video.h @@ -16,9 +16,6 @@ #define SPEC_CONSTANT_ALPHA_TO_COVERAGE (1 << 3) #define SPEC_CONSTANT_REVERSE_Z (1 << 4) -#define SPEC_CONSTANT_CONDITIONAL_SURVEY (1 << 5) -#define SPEC_CONSTANT_CONDITIONAL_RENDERING (1 << 6) - #define LOAD_ZSTD_TEXTURE(name) LoadTexture(decompressZstd(name, name##_uncompressed_size).get(), name##_uncompressed_size) using namespace plume; diff --git a/tools/XenosRecomp b/tools/XenosRecomp index 811240b01..fb32631ee 160000 --- a/tools/XenosRecomp +++ b/tools/XenosRecomp @@ -1 +1 @@ -Subproject commit 811240b0137dc9806ae1480d96314cf43941c4b9 +Subproject commit fb32631ee398e46f2a113d8f9103201dbaa000b4