@@ -67,16 +67,26 @@ constexpr std::array<PrimitiveType, 8> primitive_from_gx_pr{{
// 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)
static constexpr float ASPECT_RATIO_SLOP = 0.11f;

static bool IsAnamorphicProjection(const Projection::Raw& projection, const Viewport& viewport)
{
float aspect = fabsf(width / height);
return fabsf(aspect - 4.0f / 3.0f) < 4.0f / 3.0f * 0.11; // within 11% of 4:3
// If ratio between our projection and viewport aspect ratios is similar to 16:9 / 4:3
// we have an anamorphic projection.
static constexpr float IDEAL_RATIO = (16 / 9.f) / (4 / 3.f);

const float projection_ar = projection[2] / projection[0];
const float viewport_ar = viewport.wd / viewport.ht;

return std::abs(std::abs(projection_ar / viewport_ar) - IDEAL_RATIO) <
IDEAL_RATIO * ASPECT_RATIO_SLOP;
}

static bool AspectIs16_9(float width, float height)
static bool IsNormalProjection(const Projection::Raw& projection, const Viewport& viewport)
{
float aspect = fabsf(width / height);
return fabsf(aspect - 16.0f / 9.0f) < 16.0f / 9.0f * 0.11; // within 11% of 16:9
const float projection_ar = projection[2] / projection[0];
const float viewport_ar = viewport.wd / viewport.ht;
return std::abs(std::abs(projection_ar / viewport_ar) - 1) < ASPECT_RATIO_SLOP;
}

VertexManagerBase::VertexManagerBase()
@@ -227,12 +237,11 @@ u32 VertexManagerBase::GetRemainingIndices(int primitive) const
}
}

std::pair<size_t, size_t> VertexManagerBase::ResetFlushAspectRatioCount()
auto VertexManagerBase::ResetFlushAspectRatioCount() -> FlushStatistics
{
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;
const auto result = m_flush_statistics;
m_flush_statistics = {};
return result;
}

void VertexManagerBase::ResetBuffer(u32 vertex_stride)
@@ -387,18 +396,25 @@ void VertexManagerBase::Flush()
// Track some stats used elsewhere by the anamorphic widescreen heuristic.
if (!SConfig::GetInstance().bWii)
{
const auto& raw_projection = xfmem.projection.rawProjection;
const bool viewport_is_4_3 = AspectIs4_3(xfmem.viewport.wd, xfmem.viewport.ht);
if (AspectIs16_9(raw_projection[2], raw_projection[0]) && viewport_is_4_3)
const bool is_perspective = xfmem.projection.type == GX_PERSPECTIVE;

auto& counts =
is_perspective ? m_flush_statistics.perspective : m_flush_statistics.orthographic;

if (IsAnamorphicProjection(xfmem.projection.rawProjection, xfmem.viewport))
{
++counts.anamorphic_flush_count;
counts.anamorphic_vertex_count += m_index_generator.GetIndexLen();
}
else if (IsNormalProjection(xfmem.projection.rawProjection, xfmem.viewport))
{
// Projection is 16:9 and viewport is 4:3, we are rendering an anamorphic
// widescreen picture.
m_flush_count_anamorphic++;
++counts.normal_flush_count;
counts.normal_vertex_count += m_index_generator.GetIndexLen();
}
else if (AspectIs4_3(raw_projection[2], raw_projection[0]) && viewport_is_4_3)
else
{
// Projection and viewports are both 4:3, we are rendering a normal image.
m_flush_count_4_3++;
++counts.other_flush_count;
counts.other_vertex_count += m_index_generator.GetIndexLen();
}
}

@@ -46,6 +46,34 @@ class VertexManagerBase

static constexpr u32 MAX_PRIMITIVES_PER_COMMAND = 65535;

// Used for 16:9 anamorphic widescreen heuristic.
struct FlushStatistics
{
struct ProjectionCounts
{
size_t normal_flush_count;
size_t anamorphic_flush_count;
size_t other_flush_count;

size_t normal_vertex_count;
size_t anamorphic_vertex_count;
size_t other_vertex_count;

size_t GetTotalFlushCount() const
{
return normal_flush_count + anamorphic_flush_count + other_flush_count;
}

size_t GetTotalVertexCount() const
{
return normal_vertex_count + anamorphic_vertex_count + other_vertex_count;
}
};

ProjectionCounts perspective;
ProjectionCounts orthographic;
};

public:
static constexpr u32 MAXVBUFFERSIZE =
MathUtil::NextPowerOf2(MAX_PRIMITIVES_PER_COMMAND * LARGEST_POSSIBLE_VERTEX);
@@ -74,7 +102,7 @@ class VertexManagerBase

void DoState(PointerWrap& p);

std::pair<size_t, size_t> ResetFlushAspectRatioCount();
FlushStatistics ResetFlushAspectRatioCount();

// State setters, called from register update functions.
void SetRasterizationStateChanged() { m_rasterization_state_changed = true; }
@@ -171,8 +199,7 @@ class VertexManagerBase
void UpdatePipelineObject();

bool m_is_flushed = true;
size_t m_flush_count_4_3 = 0;
size_t m_flush_count_anamorphic = 0;
FlushStatistics m_flush_statistics = {};

// CPU access tracking
u32 m_draw_counter = 0;