Video: update widescreen heuristic code to never get stuck to specific old values when changing settings

This commit is contained in:
Filoppi 2023-12-18 20:16:58 +02:00
parent 95ee0ac781
commit 48fbbdba7c
2 changed files with 91 additions and 60 deletions

View File

@ -4,6 +4,7 @@
#include "VideoCommon/Widescreen.h" #include "VideoCommon/Widescreen.h"
#include "Common/ChunkFile.h" #include "Common/ChunkFile.h"
#include "Common/Logging/Log.h"
#include "Core/Config/SYSCONFSettings.h" #include "Core/Config/SYSCONFSettings.h"
#include "Core/System.h" #include "Core/System.h"
@ -13,12 +14,34 @@ std::unique_ptr<WidescreenManager> g_widescreen;
WidescreenManager::WidescreenManager() WidescreenManager::WidescreenManager()
{ {
Update(); std::optional<bool> is_game_widescreen = GetWidescreenOverride();
if (is_game_widescreen.has_value())
m_is_game_widescreen = is_game_widescreen.value();
// Throw a warning as unsupported aspect ratio modes have no specific behavior to them
const bool is_valid_suggested_aspect_mode =
g_ActiveConfig.suggested_aspect_mode == AspectMode::Auto ||
g_ActiveConfig.suggested_aspect_mode == AspectMode::ForceStandard ||
g_ActiveConfig.suggested_aspect_mode == AspectMode::ForceWide;
if (!is_valid_suggested_aspect_mode)
{
WARN_LOG_FMT(VIDEO,
"Invalid suggested aspect ratio mode: only Auto, 4:3 and 16:9 are supported");
}
m_config_changed = ConfigChangedEvent::Register( m_config_changed = ConfigChangedEvent::Register(
[this](u32 bits) { [this](u32 bits) {
if (bits & (CONFIG_CHANGE_BIT_ASPECT_RATIO)) if (bits & (CONFIG_CHANGE_BIT_ASPECT_RATIO))
Update(); {
std::optional<bool> is_game_widescreen = GetWidescreenOverride();
// If the widescreen flag isn't being overridden by any settings,
// reset it to default if heuristic aren't running or to the last
// heuristic value if they were running.
if (!is_game_widescreen.has_value())
is_game_widescreen = (m_heuristic_state == HeuristicState::Active_Found_Anamorphic);
if (is_game_widescreen.has_value())
m_is_game_widescreen = is_game_widescreen.value();
}
}, },
"Widescreen"); "Widescreen");
@ -31,7 +54,7 @@ WidescreenManager::WidescreenManager()
} }
} }
void WidescreenManager::Update() std::optional<bool> WidescreenManager::GetWidescreenOverride() const
{ {
std::optional<bool> is_game_widescreen; std::optional<bool> is_game_widescreen;
@ -53,44 +76,33 @@ void WidescreenManager::Update()
is_game_widescreen = false; is_game_widescreen = false;
else if (aspect_mode == AspectMode::ForceWide) else if (aspect_mode == AspectMode::ForceWide)
is_game_widescreen = true; is_game_widescreen = true;
// Reset settings to default if heuristics aren't currently running and
// the user selected the automatic aspect ratio.
if (!is_game_widescreen.has_value() && !m_widescreen_heuristics_active_and_successful &&
aspect_mode == AspectMode::Auto)
{
is_game_widescreen = false;
}
} }
if (is_game_widescreen.has_value()) return is_game_widescreen;
{
m_is_game_widescreen = is_game_widescreen.value();
}
} }
// Heuristic to detect if a GameCube game is in 16:9 anamorphic widescreen mode. // Heuristic to detect if a GameCube game is in 16:9 anamorphic widescreen mode.
// Cheats that change the game aspect ratio to natively unsupported ones won't be recognized here. // Cheats that change the game aspect ratio to natively unsupported ones won't be recognized here.
void WidescreenManager::UpdateWidescreenHeuristic() void WidescreenManager::UpdateWidescreenHeuristic()
{ {
// Reset to baseline state before the update
const auto flush_statistics = g_vertex_manager->ResetFlushAspectRatioCount(); const auto flush_statistics = g_vertex_manager->ResetFlushAspectRatioCount();
const bool was_orthographically_anamorphic = m_was_orthographically_anamorphic;
m_heuristic_state = HeuristicState::Inactive;
m_was_orthographically_anamorphic = false;
// If suggested_aspect_mode (GameINI) is configured don't use heuristic. // If suggested_aspect_mode (GameINI) is configured don't use heuristic.
// We also don't need to check "GetWidescreenOverride()" in this case as
// nothing would have changed there.
if (g_ActiveConfig.suggested_aspect_mode != AspectMode::Auto) if (g_ActiveConfig.suggested_aspect_mode != AspectMode::Auto)
{
m_widescreen_heuristics_active_and_successful = false;
return; return;
}
Update(); std::optional<bool> is_game_widescreen = GetWidescreenOverride();
m_widescreen_heuristics_active_and_successful = false;
// If widescreen hack isn't active and aspect_mode (UI) is 4:3 or 16:9 don't use heuristic. // If widescreen hack isn't active and aspect_mode (UI) is 4:3 or 16:9 don't use heuristic.
if (!g_ActiveConfig.bWidescreenHack && (g_ActiveConfig.aspect_mode == AspectMode::ForceStandard || if (g_ActiveConfig.bWidescreenHack || (g_ActiveConfig.aspect_mode != AspectMode::ForceStandard &&
g_ActiveConfig.aspect_mode == AspectMode::ForceWide)) g_ActiveConfig.aspect_mode != AspectMode::ForceWide))
return; {
// Modify the threshold based on which aspect ratio we're already using: // Modify the threshold based on which aspect ratio we're already using:
// If the game's in 4:3, it probably won't switch to anamorphic, and vice-versa. // If the game's in 4:3, it probably won't switch to anamorphic, and vice-versa.
const u32 transition_threshold = g_ActiveConfig.widescreen_heuristic_transition_threshold; const u32 transition_threshold = g_ActiveConfig.widescreen_heuristic_transition_threshold;
@ -106,14 +118,15 @@ void WidescreenManager::UpdateWidescreenHeuristic()
const auto& ortho = flush_statistics.orthographic; const auto& ortho = flush_statistics.orthographic;
const auto ortho_looks_anamorphic = looks_anamorphic(ortho); const auto ortho_looks_anamorphic = looks_anamorphic(ortho);
const auto persp_looks_normal = looks_normal(persp);
if (looks_anamorphic(persp) || ortho_looks_anamorphic) if (looks_anamorphic(persp) || ortho_looks_anamorphic)
{ {
// If either perspective or orthographic projections look anamorphic, it's a safe bet. // If either perspective or orthographic projections look anamorphic, it's a safe bet.
m_is_game_widescreen = true; is_game_widescreen = true;
m_widescreen_heuristics_active_and_successful = true; m_heuristic_state = HeuristicState::Active_Found_Anamorphic;
} }
else if (looks_normal(persp) || (m_was_orthographically_anamorphic && looks_normal(ortho))) else if (persp_looks_normal || looks_normal(ortho))
{ {
// Many widescreen games (or AR/GeckoCodes) use anamorphic perspective projections // Many widescreen games (or AR/GeckoCodes) use anamorphic perspective projections
// with NON-anamorphic orthographic projections. // with NON-anamorphic orthographic projections.
@ -121,13 +134,22 @@ void WidescreenManager::UpdateWidescreenHeuristic()
// shown. e.g. Animal Crossing's inventory menu. // shown. e.g. Animal Crossing's inventory menu.
// Unless we were in a situation which was orthographically anamorphic // Unless we were in a situation which was orthographically anamorphic
// we won't consider orthographic data for changes from 16:9 to 4:3. // we won't consider orthographic data for changes from 16:9 to 4:3.
m_is_game_widescreen = false; if (persp_looks_normal || was_orthographically_anamorphic)
m_widescreen_heuristics_active_and_successful = true; is_game_widescreen = false;
m_heuristic_state = HeuristicState::Active_Found_Normal;
}
else
{
m_heuristic_state = HeuristicState::Active_NotFound;
} }
m_was_orthographically_anamorphic = ortho_looks_anamorphic; m_was_orthographically_anamorphic = ortho_looks_anamorphic;
} }
if (is_game_widescreen.has_value())
m_is_game_widescreen = is_game_widescreen.value();
}
void WidescreenManager::DoState(PointerWrap& p) void WidescreenManager::DoState(PointerWrap& p)
{ {
p.Do(m_is_game_widescreen); p.Do(m_is_game_widescreen);
@ -135,6 +157,6 @@ void WidescreenManager::DoState(PointerWrap& p)
if (p.IsReadMode()) if (p.IsReadMode())
{ {
m_was_orthographically_anamorphic = false; m_was_orthographically_anamorphic = false;
m_widescreen_heuristics_active_and_successful = false; m_heuristic_state = HeuristicState::Inactive;
} }
} }

View File

@ -24,12 +24,21 @@ public:
void DoState(PointerWrap& p); void DoState(PointerWrap& p);
private: private:
void Update(); enum class HeuristicState
{
Inactive,
Active_NotFound,
Active_Found_Normal,
Active_Found_Anamorphic,
};
// Returns whether the widescreen state wants to change, and its target value
std::optional<bool> GetWidescreenOverride() const;
void UpdateWidescreenHeuristic(); void UpdateWidescreenHeuristic();
bool m_is_game_widescreen = false; bool m_is_game_widescreen = false;
bool m_was_orthographically_anamorphic = false; bool m_was_orthographically_anamorphic = false;
bool m_widescreen_heuristics_active_and_successful = false; HeuristicState m_heuristic_state = HeuristicState::Inactive;
Common::EventHook m_update_widescreen; Common::EventHook m_update_widescreen;
Common::EventHook m_config_changed; Common::EventHook m_config_changed;