Fix AC6 >1x mosaic and cloud/effects de-swizzle streaks

Upscale mosaic. At draw-resolution scale > 1, AC6's deferred
EDRAM restore passes do integer pixel-address math on the PsParamGen
position. Its leftover sub-guest-pixel fraction scrambles into an 8x8
mosaic. Floor the param-gen position (param_gen_integer_guest_position)
and re-add the host sub-pixel at the fetch (param_gen_host_subpixel_restore).
Inert at 1x.

De-swizzle scramble. Some AC6 restore/resample passes
manually de-swizzle the Xenos EDRAM sub-tile layout of their source, which
is only correct on tiled data. The emulator detiles everything to linear,
so the de-swizzle always scrambles, streaking the cloud/effects pipeline.
For allowlisted shader hashes (ac6_neutralize_deswizzle_hashes) the sample
coordinate is replaced with the identity host-texel UV (a 1:1 copy).
This commit is contained in:
Dipshet
2026-07-08 01:28:57 +03:00
parent 06868b3780
commit 313fd236ee
5 changed files with 257 additions and 0 deletions
+45
View File
@@ -17,6 +17,9 @@ REXCVAR_DECLARE(bool, direct_host_resolve);
REXCVAR_DECLARE(int32_t, resolution_scale);
REXCVAR_DECLARE(int32_t, draw_resolution_scale_x);
REXCVAR_DECLARE(int32_t, draw_resolution_scale_y);
REXCVAR_DECLARE(bool, param_gen_integer_guest_position);
REXCVAR_DECLARE(bool, param_gen_host_subpixel_restore);
REXCVAR_DECLARE(std::string, ac6_neutralize_deswizzle_hashes);
REXCVAR_DECLARE(std::string, log_file);
REXCVAR_DECLARE(std::string, log_level);
REXCVAR_DECLARE(bool, ac6_d3d_trace);
@@ -54,6 +57,19 @@ REXCVAR_DEFINE_STRING(ac6_graphics_backend, AC6_DEFAULT_GRAPHICS_BACKEND,
REXCVAR_DEFINE_BOOL(ac6_performance_mode, true, "AC6/Performance",
"Disable all diagnostics, logging, and development overlays for maximum runtime performance");
// Correctness-fix switches. Each expands
// to its detailed cvars + AC6-specific shader hashes in ApplyAc6FixDefaults()
// unless the user overrode them.
REXCVAR_DEFINE_BOOL(ac6_fix_scaling, true, "AC6",
"Fix the upscaling mosaic on AC6's deferred EDRAM restore passes by "
"flooring the PsParamGen pixel position (+ host sub-pixel restore). "
"Auto-applies only at draw resolution scale > 1; inert at 1x. On by default.");
REXCVAR_DEFINE_BOOL(ac6_fix_deswizzle, true, "AC6",
"Fix the de-swizzle mosaic/streaks: identity-override AC6's manual EDRAM "
"sub-tile de-swizzle, which is always a wrong texel permutation once the "
"emulator detiles to linear. On by default; effective at all draw scales "
"(the swizzle is present at 1x too).");
#include "generated/ac6recomp_config.h"
#include "generated/ac6recomp_init.h"
@@ -82,6 +98,8 @@ void ApplyAc6HybridStartupSafetyOverrides() {
REXCVAR_SET(draw_resolution_scale_x, 1);
REXCVAR_SET(draw_resolution_scale_y, 1);
}
// (The >1x param-gen mosaic fix is applied by ApplyAc6FixDefaults via
// ac6_fix_scaling.)
if (REXCVAR_GET(ac6_force_safe_direct_host_resolve)) {
REXCVAR_SET(direct_host_resolve, false);
@@ -139,6 +157,32 @@ void ApplyAc6PerformanceModeOverrides() {
REXCVAR_SET(ac6_texture_swaps_dump_enabled, false);
}
// Each fix switch -> its detailed cvars + AC6-specific shader hashes. The
// game-specific constants live here in code, not in the user's toml; each
// value is filled in only if the user did NOT set it explicitly, so any toml
// override still wins (the dev/debug path).
#define AC6_SET_IF_UNSET(cv, value) \
do { if (!rex::cvar::HasNonDefaultValue(#cv)) REXCVAR_SET(cv, value); } while (0)
void ApplyAc6FixDefaults() {
const bool scaled = REXCVAR_GET(draw_resolution_scale_x) > 1 ||
REXCVAR_GET(draw_resolution_scale_y) > 1;
// param_gen floor + host sub-pixel restore only bites at >1x --
// inert at 1x, so gate it on the draw scale.
if (REXCVAR_GET(ac6_fix_scaling) && scaled) {
AC6_SET_IF_UNSET(param_gen_integer_guest_position, true);
AC6_SET_IF_UNSET(param_gen_host_subpixel_restore, true);
}
// de-swizzle identity override is a texture-layout mismatch present
// at ALL draw scales, so it is NOT gated on scale.
if (REXCVAR_GET(ac6_fix_deswizzle)) {
AC6_SET_IF_UNSET(ac6_neutralize_deswizzle_hashes,
"7d22894002d16018, 17e5e4ac3e713245:4");
}
}
#undef AC6_SET_IF_UNSET
} // namespace
void ApplyAc6PerformanceModeOverridesPublic() {
@@ -169,6 +213,7 @@ std::unique_ptr<rex::ui::WindowedApp> Ac6recompAppCreate(rex::ui::WindowedAppCon
REXCVAR_SET(ac6_unlock_fps, false);
ApplyAc6DefaultSettings();
ApplyAc6HybridStartupSafetyOverrides();
ApplyAc6FixDefaults();
ApplyAc6PerformanceModeOverrides();
REXLOG_INFO("Ac6recompAppCreate: graphics mode={} capture={}",