mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-10 08:09:26 +01:00
VideoCommon: rework anamorphic widescreen heuristic
Some widescreen hacks (see below) properly force anamorphic output, but don't make the last projection in a frame 16:9, so Dolphin doesn't display it correctly. This changes the heuristic code to assume a frame is anamorphic based on the total number of vertex flushes in 4:3 and 16:9 projections that frame. It also adds a bit of "aspect ratio inertia" by making it harder to switch aspect ratios, which takes care of aspect ratio flickering that some games / widescreen hacks would be susceptible with the new logic. I've tested this on SSX Tricky's native anamorphic support, Tom Clancy's Splinter Cell (it stayed in 4:3 the whole time), and on the following widescreen hacks for which the heuristic doesn't currently work: Paper Mario: The Thousand-Year Door (Gecko widescreen code from Nintendont) C202F310 00000003 3DC08042 3DE03FD8 91EEF6D8 4E800020 60000000 00000000 04199598 4E800020 C200F500 00000004 3DE08082 3DC0402B 61CE12A2 91CFA1BC 60000000 387D015C 60000000 00000000 C200F508 00000004 3DE08082 3DC04063 61CEE8D3 91CFA1BC 60000000 7FC3F378 60000000 00000000 The Simpsons: Hit & Run (AR widescreen code from the wiki) 04004600 C002A604 04004604 C09F0014 04004608 FC002040 0400460C 4082000C 04004610 C002A608 04004614 EC630032 04004618 48220508 04041A5C 38600001 04224344 C002A60C 04224B1C 4BDDFAE4 044786B0 3FAAAAAB 04479F28 3FA33333
This commit is contained in:
parent
4c0a392698
commit
d10d09ccc1
@ -290,13 +290,11 @@ bool BootCore(const std::string& _rFilename)
|
||||
}
|
||||
}
|
||||
|
||||
Core::g_aspect_wide = StartUp.bWii;
|
||||
|
||||
// Wii settings
|
||||
if (StartUp.bWii)
|
||||
{
|
||||
IniFile::Section* wii_section = game_ini.GetOrCreateSection("Wii");
|
||||
wii_section->Get("Widescreen", &Core::g_aspect_wide, !!StartUp.m_wii_aspect_ratio);
|
||||
wii_section->Get("Widescreen", &StartUp.m_wii_aspect_ratio, !!StartUp.m_wii_aspect_ratio);
|
||||
wii_section->Get("Language", &StartUp.m_wii_language, StartUp.m_wii_language);
|
||||
|
||||
int source;
|
||||
|
@ -81,9 +81,6 @@
|
||||
|
||||
namespace Core
|
||||
{
|
||||
// TODO: ugly, remove
|
||||
bool g_aspect_wide;
|
||||
|
||||
static bool s_wants_determinism;
|
||||
|
||||
// Declarations and definitions
|
||||
|
@ -18,9 +18,6 @@
|
||||
|
||||
namespace Core
|
||||
{
|
||||
// TODO: ugly, remove
|
||||
extern bool g_aspect_wide;
|
||||
|
||||
bool GetIsThrottlerTempDisabled();
|
||||
void SetIsThrottlerTempDisabled(bool disable);
|
||||
|
||||
|
@ -55,6 +55,8 @@
|
||||
#include "VideoCommon/Statistics.h"
|
||||
#include "VideoCommon/TextureCacheBase.h"
|
||||
#include "VideoCommon/TextureDecoder.h"
|
||||
#include "VideoCommon/VertexManagerBase.h"
|
||||
#include "VideoCommon/VertexShaderManager.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
#include "VideoCommon/XFMemory.h"
|
||||
|
||||
@ -89,6 +91,11 @@ Renderer::Renderer(int backbuffer_width, int backbuffer_height)
|
||||
|
||||
OSDChoice = 0;
|
||||
OSDTime = 0;
|
||||
|
||||
if (SConfig::GetInstance().bWii)
|
||||
{
|
||||
m_aspect_wide = SConfig::GetInstance().m_wii_aspect_ratio != 0;
|
||||
}
|
||||
}
|
||||
|
||||
Renderer::~Renderer()
|
||||
@ -447,7 +454,7 @@ float Renderer::CalculateDrawAspectRatio(int target_width, int target_height)
|
||||
|
||||
// The rendering window aspect ratio as a proportion of the 4:3 or 16:9 ratio
|
||||
if (g_ActiveConfig.iAspectRatio == ASPECT_ANALOG_WIDE ||
|
||||
(g_ActiveConfig.iAspectRatio != ASPECT_ANALOG && Core::g_aspect_wide))
|
||||
(g_ActiveConfig.iAspectRatio != ASPECT_ANALOG && m_aspect_wide))
|
||||
{
|
||||
return (static_cast<float>(target_width) / static_cast<float>(target_height)) /
|
||||
AspectToWidescreen(VideoInterface::GetAspectRatio());
|
||||
@ -521,7 +528,7 @@ void Renderer::UpdateDrawRectangle()
|
||||
if (g_ActiveConfig.bWidescreenHack)
|
||||
{
|
||||
float source_aspect = VideoInterface::GetAspectRatio();
|
||||
if (Core::g_aspect_wide)
|
||||
if (m_aspect_wide)
|
||||
source_aspect = AspectToWidescreen(source_aspect);
|
||||
float target_aspect;
|
||||
|
||||
@ -641,11 +648,10 @@ void Renderer::SetWindowSize(int width, int height)
|
||||
{
|
||||
// Force 4:3 or 16:9 by cropping the image.
|
||||
float current_aspect = scaled_width / scaled_height;
|
||||
float expected_aspect =
|
||||
(g_ActiveConfig.iAspectRatio == ASPECT_ANALOG_WIDE ||
|
||||
(g_ActiveConfig.iAspectRatio != ASPECT_ANALOG && Core::g_aspect_wide)) ?
|
||||
(16.0f / 9.0f) :
|
||||
(4.0f / 3.0f);
|
||||
float expected_aspect = (g_ActiveConfig.iAspectRatio == ASPECT_ANALOG_WIDE ||
|
||||
(g_ActiveConfig.iAspectRatio != ASPECT_ANALOG && m_aspect_wide)) ?
|
||||
(16.0f / 9.0f) :
|
||||
(4.0f / 3.0f);
|
||||
if (current_aspect > expected_aspect)
|
||||
{
|
||||
// keep height, crop width
|
||||
@ -711,6 +717,22 @@ void Renderer::RecordVideoMemory()
|
||||
void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc,
|
||||
u64 ticks, float Gamma)
|
||||
{
|
||||
// Heuristic to detect if a GameCube game is in 16:9 anamorphic widescreen mode.
|
||||
if (!SConfig::GetInstance().bWii)
|
||||
{
|
||||
size_t flush_count_4_3, flush_count_anamorphic;
|
||||
std::tie(flush_count_4_3, flush_count_anamorphic) =
|
||||
g_vertex_manager->ResetFlushAspectRatioCount();
|
||||
size_t flush_total = flush_count_4_3 + flush_count_anamorphic;
|
||||
|
||||
// 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 (m_aspect_wide)
|
||||
m_aspect_wide = !(flush_count_4_3 > 0.75 * flush_total);
|
||||
else
|
||||
m_aspect_wide = flush_count_anamorphic > 0.75 * flush_total;
|
||||
}
|
||||
|
||||
// TODO: merge more generic parts into VideoCommon
|
||||
g_renderer->SwapImpl(xfbAddr, fbWidth, fbStride, fbHeight, rc, ticks, Gamma);
|
||||
|
||||
|
@ -158,6 +158,7 @@ protected:
|
||||
Common::Event m_screenshot_completed;
|
||||
std::mutex m_screenshot_lock;
|
||||
std::string m_screenshot_name;
|
||||
bool m_aspect_wide = false;
|
||||
|
||||
// The framebuffer size
|
||||
int m_target_width = 0;
|
||||
|
@ -4,12 +4,14 @@
|
||||
|
||||
#include "VideoCommon/VertexManagerBase.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
|
||||
#include "Common/BitSet.h"
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
|
||||
#include "VideoCommon/BPMemory.h"
|
||||
#include "VideoCommon/DataReader.h"
|
||||
@ -41,6 +43,23 @@ static const PrimitiveType primitive_from_gx[8] = {
|
||||
PRIMITIVE_POINTS, // GX_DRAW_POINTS
|
||||
};
|
||||
|
||||
// Due to the BT.601 standard which the GameCube is based on being a compromise
|
||||
// between PAL and NTSC, neither standard gets square pixels. They are each off
|
||||
// by ~9% in opposite directions.
|
||||
// Just in case any game decides to take this into account, we do both these
|
||||
// tests with a large amount of slop.
|
||||
static bool AspectIs4_3(float width, float height)
|
||||
{
|
||||
float aspect = fabsf(width / height);
|
||||
return fabsf(aspect - 4.0f / 3.0f) < 4.0f / 3.0f * 0.11; // within 11% of 4:3
|
||||
}
|
||||
|
||||
static bool AspectIs16_9(float width, float height)
|
||||
{
|
||||
float aspect = fabsf(width / height);
|
||||
return fabsf(aspect - 16.0f / 9.0f) < 16.0f / 9.0f * 0.11; // within 11% of 16:9
|
||||
}
|
||||
|
||||
VertexManagerBase::VertexManagerBase()
|
||||
{
|
||||
}
|
||||
@ -157,6 +176,14 @@ u32 VertexManagerBase::GetRemainingIndices(int primitive)
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<size_t, size_t> VertexManagerBase::ResetFlushAspectRatioCount()
|
||||
{
|
||||
std::pair<size_t, size_t> val = std::make_pair(m_flush_count_4_3, m_flush_count_anamorphic);
|
||||
m_flush_count_4_3 = 0;
|
||||
m_flush_count_anamorphic = 0;
|
||||
return val;
|
||||
}
|
||||
|
||||
void VertexManagerBase::Flush()
|
||||
{
|
||||
if (m_is_flushed)
|
||||
@ -237,6 +264,24 @@ void VertexManagerBase::Flush()
|
||||
// set global vertex constants
|
||||
VertexShaderManager::SetConstants();
|
||||
|
||||
// Track some stats used elsewhere by the anamorphic widescreen heuristic.
|
||||
if (!SConfig::GetInstance().bWii)
|
||||
{
|
||||
float* rawProjection = xfmem.projection.rawProjection;
|
||||
bool viewport_is_4_3 = AspectIs4_3(xfmem.viewport.wd, xfmem.viewport.ht);
|
||||
if (AspectIs16_9(rawProjection[2], rawProjection[0]) && viewport_is_4_3)
|
||||
{
|
||||
// Projection is 16:9 and viewport is 4:3, we are rendering an anamorphic
|
||||
// widescreen picture.
|
||||
m_flush_count_anamorphic++;
|
||||
}
|
||||
else if (AspectIs4_3(rawProjection[2], rawProjection[0]) && viewport_is_4_3)
|
||||
{
|
||||
// Projection and viewports are both 4:3, we are rendering a normal image.
|
||||
m_flush_count_4_3++;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate ZSlope for zfreeze
|
||||
if (!bpmem.genMode.zfreeze)
|
||||
{
|
||||
|
@ -61,6 +61,8 @@ public:
|
||||
|
||||
void DoState(PointerWrap& p);
|
||||
|
||||
std::pair<size_t, size_t> ResetFlushAspectRatioCount();
|
||||
|
||||
protected:
|
||||
virtual void vDoState(PointerWrap& p) {}
|
||||
PrimitiveType m_current_primitive_type = PrimitiveType::PRIMITIVE_POINTS;
|
||||
@ -81,6 +83,8 @@ protected:
|
||||
|
||||
private:
|
||||
bool m_is_flushed = true;
|
||||
size_t m_flush_count_4_3 = 0;
|
||||
size_t m_flush_count_anamorphic = 0;
|
||||
|
||||
virtual void vFlush() = 0;
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
#include "Common/Assert.h"
|
||||
|
@ -92,23 +92,6 @@ static float PHackValue(std::string sValue)
|
||||
return f;
|
||||
}
|
||||
|
||||
// Due to the BT.601 standard which the GameCube is based on being a compromise
|
||||
// between PAL and NTSC, neither standard gets square pixels. They are each off
|
||||
// by ~9% in opposite directions.
|
||||
// Just in case any game decides to take this into account, we do both these
|
||||
// tests with a large amount of slop.
|
||||
static bool AspectIs4_3(float width, float height)
|
||||
{
|
||||
float aspect = fabsf(width / height);
|
||||
return fabsf(aspect - 4.0f / 3.0f) < 4.0f / 3.0f * 0.11; // within 11% of 4:3
|
||||
}
|
||||
|
||||
static bool AspectIs16_9(float width, float height)
|
||||
{
|
||||
float aspect = fabsf(width / height);
|
||||
return fabsf(aspect - 16.0f / 9.0f) < 16.0f / 9.0f * 0.11; // within 11% of 16:9
|
||||
}
|
||||
|
||||
void UpdateProjectionHack(int iPhackvalue[], std::string sPhackvalue[])
|
||||
{
|
||||
float fhackvalue1 = 0, fhackvalue2 = 0;
|
||||
@ -470,18 +453,6 @@ void VertexShaderManager::SetConstants()
|
||||
g_fProjectionMatrix[14] = -1.0f;
|
||||
g_fProjectionMatrix[15] = 0.0f;
|
||||
|
||||
// Heuristic to detect if a GameCube game is in 16:9 anamorphic widescreen mode.
|
||||
if (!SConfig::GetInstance().bWii)
|
||||
{
|
||||
bool viewport_is_4_3 = AspectIs4_3(xfmem.viewport.wd, xfmem.viewport.ht);
|
||||
if (AspectIs16_9(rawProjection[2], rawProjection[0]) && viewport_is_4_3)
|
||||
Core::g_aspect_wide = true; // Projection is 16:9 and viewport is 4:3, we are rendering
|
||||
// an anamorphic widescreen picture
|
||||
else if (AspectIs4_3(rawProjection[2], rawProjection[0]) && viewport_is_4_3)
|
||||
Core::g_aspect_wide =
|
||||
false; // Project and viewports are both 4:3, we are rendering a normal image.
|
||||
}
|
||||
|
||||
SETSTAT_FT(stats.gproj_0, g_fProjectionMatrix[0]);
|
||||
SETSTAT_FT(stats.gproj_1, g_fProjectionMatrix[1]);
|
||||
SETSTAT_FT(stats.gproj_2, g_fProjectionMatrix[2]);
|
||||
|
Loading…
x
Reference in New Issue
Block a user