Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions runtime/include/aurora_events.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@
#endif

extern "C" bool g_dynamicAspectRatioEnabled;
void ConfigureMkwDynamicAspect(bool widescreen, bool forceAspect169, uint32_t surfaceWidth, uint32_t surfaceHeight);
void SetMkwForceAspect169(bool enabled);
bool MkwForceAspect169Requested();
void ConfigureMkwDynamicAspect(bool widescreen, bool forceAspect, uint32_t surfaceWidth, uint32_t surfaceHeight);
void SetMkwForceAspect(bool enabled);
void UpdateMkwDynamicAspectSurface(uint32_t surfaceWidth, uint32_t surfaceHeight);
// Arms the "keep EGG::Frustum's projection scale" flag on every screen that
// renders to a fixed-size offscreen target. Cheap and idempotent; called from
Expand Down
29 changes: 21 additions & 8 deletions runtime/include/runtime_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@

struct RuntimeUserConfig {
std::optional<bool> widescreen;
std::optional<bool> forceAspect169;
std::optional<std::string> advertisedAspectRatio;
std::optional<bool> forceAspect;
std::optional<int32_t> windowPosX;
std::optional<int32_t> windowPosY;
std::optional<uint32_t> windowWidth;
Expand Down Expand Up @@ -271,7 +272,8 @@ inline void EnsureConfigFile() {
"# Set paths.dvd_root to an extracted Mario Kart Wii DATA directory.\n\n"
"[video]\n"
"widescreen = true\n"
"force_16_9 = false\n"
"advertised_aspect_ratio = \"16:9\"\n"
"force_aspect = false\n"
"resolution_multiplier = 1.0\n"
"frame_interpolation_fps = 0\n"
"display_mode = \"windowed\"\n"
Expand Down Expand Up @@ -403,7 +405,8 @@ inline RuntimeUserConfig ParseConfigDocument(const toml::value& document) {
}

config.widescreen = FindConfigValue<bool>(document, "video", "widescreen");
config.forceAspect169 = FindConfigValue<bool>(document, "video", "force_16_9");
config.advertisedAspectRatio = FindConfigValue<std::string>(document, "video", "advertised_aspect_ratio");
config.forceAspect = FindConfigValue<bool>(document, "video", "force_aspect");
config.windowPosX = FindConfigInt(document, "video", "window_x");
config.windowPosY = FindConfigInt(document, "video", "window_y");
if (auto value = FindConfigUint(document, "video", "window_width"); value && *value != 0) {
Expand Down Expand Up @@ -760,13 +763,23 @@ inline bool WidescreenEnabled(bool fallback = false) {
return Get().widescreen.value_or(fallback);
}

inline bool ForceAspect169Enabled(bool fallback = false) {
return Get().forceAspect169.value_or(fallback);
inline bool AdvertisedAspectRatio169(bool fallback = false) {
if (Get().advertisedAspectRatio) {
return *Get().advertisedAspectRatio != "4:3";
}
return WidescreenEnabled(fallback);
}

inline bool SetAdvertisedAspectRatio169(bool value) {
return WriteSetting("video", "advertised_aspect_ratio", value ? "\"16:9\"" : "\"4:3\"");
}

inline bool ForceAspectEnabled(bool fallback = false) {
return Get().forceAspect.value_or(fallback);
}

inline bool SetForceAspect169(bool value) {
Mutable().forceAspect169 = value;
return WriteSetting("video", "force_16_9", value ? "true" : "false");
inline bool SetForceAspect(bool value) {
return WriteSetting("video", "force_aspect", value ? "true" : "false");
}

inline bool WindowPosition(int32_t& x, int32_t& y) {
Expand Down
85 changes: 33 additions & 52 deletions runtime/src/dynamic_aspect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
#include "memory.h"

#include <algorithm>
#include <atomic>
#include "aurora_events.h"
#include "hle/gx/gx_dynamic_aspect.h"

Expand All @@ -14,10 +13,9 @@ extern "C" int g_gxFrameCount;

namespace {

bool g_widescreenConfigured = false;
bool g_widescreenSetting = false;
bool g_forceAspect169 = false;
std::atomic_bool g_requestedForceAspect169{false};
bool g_forceAspect = false;
bool g_referenceWidescreen = true;
float g_referenceAspect = MkwDynamicAspect::kPresentationAspect169;
bool g_policyDirty = false;
uint32_t g_lastEggWidth43 = 0;
uint32_t g_lastEggWidth169 = 0;
Expand Down Expand Up @@ -131,18 +129,14 @@ void WriteEggScreenRecord(uint32_t recordAddr, uint32_t width) {
void ApplyEggScreenRecords(uint32_t surfaceWidth, uint32_t surfaceHeight) {
using namespace MkwDynamicAspect;
const uint32_t width43 =
g_widescreenConfigured ? EggRecordWidth(kEggRecordWidth43, surfaceWidth, surfaceHeight)
: kEggRecordWidth43;
EggRecordWidth(kEggRecordWidth43, surfaceWidth, surfaceHeight, g_referenceAspect);
const uint32_t width169 =
g_widescreenConfigured ? EggRecordWidth(kEggRecordWidth169, surfaceWidth, surfaceHeight)
: kEggRecordWidth169;
EggRecordWidth(kEggRecordWidth169, surfaceWidth, surfaceHeight);
WriteEggScreenRecord(kEggScreenRecord43, width43);
WriteEggScreenRecord(kEggScreenRecord169, width169);
Memory::WriteFloat32(kEggScreenProjScaleX, 1.0f);
Memory::WriteFloat32(kEggScreenProjScaleY,
g_widescreenConfigured
? VerticalExpansion(surfaceWidth, surfaceHeight)
: 1.0f);
VerticalExpansion(surfaceWidth, surfaceHeight, g_referenceAspect));
AssertOffscreenScreenBypass();
if (width43 == g_lastEggWidth43 && width169 == g_lastEggWidth169) {
return;
Expand Down Expand Up @@ -172,58 +166,45 @@ void AssertMkwOffscreenScreenBypass() {
}

void UpdateMkwDynamicAspectSurface(uint32_t surfaceWidth, uint32_t surfaceHeight) {
const bool requestedForceAspect169 = g_requestedForceAspect169.load(std::memory_order_acquire);
if (g_forceAspect169 != requestedForceAspect169) {
g_forceAspect169 = requestedForceAspect169;
g_widescreenConfigured = g_widescreenSetting || g_forceAspect169;
g_dynamicAspectRatioEnabled = g_widescreenConfigured;
g_policyDirty = true;
}
if (surfaceWidth == 0 || surfaceHeight == 0) {
return;
}
if (!g_widescreenConfigured) {
if (g_policyDirty) {
if (g_policyDirty) {
if (g_forceAspect && !g_referenceWidescreen) {
AuroraSetViewportPolicy(AURORA_VIEWPORT_FIT);
VILockAspectRatio(4, 3);
ApplyEggScreenRecords(surfaceWidth, surfaceHeight);
g_policyDirty = false;
} else {
AuroraSetViewportPolicy(g_forceAspect ? AURORA_VIEWPORT_16_9 : AURORA_VIEWPORT_STRETCH);
VIUnlockAspectRatio();
}
return;
}
if (g_policyDirty) {
VIUnlockAspectRatio();
g_policyDirty = false;
}
AuroraSetViewportPolicy(g_forceAspect169 ? AURORA_VIEWPORT_16_9 : AURORA_VIEWPORT_STRETCH);
ApplyEggScreenRecords(g_forceAspect169 ? 16u : surfaceWidth,
g_forceAspect169 ? 9u : surfaceHeight);
}

void SetMkwForceAspect169(bool enabled) {
g_requestedForceAspect169.store(enabled, std::memory_order_release);
if (!g_forceAspect) {
AuroraSetViewportPolicy(AURORA_VIEWPORT_STRETCH);
ApplyEggScreenRecords(surfaceWidth, surfaceHeight);
return;
}
ApplyEggScreenRecords(g_referenceWidescreen ? 16u : 4u,
g_referenceWidescreen ? 9u : 3u);
}

bool MkwForceAspect169Requested() {
return g_requestedForceAspect169.load(std::memory_order_acquire);
void SetMkwForceAspect(bool enabled) {
g_forceAspect = enabled;
g_policyDirty = true;
uint32_t surfaceWidth = 0;
uint32_t surfaceHeight = 0;
AuroraGetSurfaceSize(&surfaceWidth, &surfaceHeight);
UpdateMkwDynamicAspectSurface(surfaceWidth, surfaceHeight);
}

void ConfigureMkwDynamicAspect(bool widescreen, bool forceAspect169, uint32_t surfaceWidth, uint32_t surfaceHeight) {
g_widescreenSetting = widescreen;
g_widescreenConfigured = widescreen || forceAspect169;
g_forceAspect169 = forceAspect169;
g_requestedForceAspect169.store(forceAspect169, std::memory_order_relaxed);
g_dynamicAspectRatioEnabled = g_widescreenConfigured;
void ConfigureMkwDynamicAspect(bool widescreen, bool forceAspect, uint32_t surfaceWidth, uint32_t surfaceHeight) {
g_forceAspect = forceAspect;
g_referenceWidescreen = widescreen;
g_referenceAspect = widescreen ? MkwDynamicAspect::kPresentationAspect169 : 4.0f / 3.0f;
g_policyDirty = true;
g_dynamicAspectRatioEnabled = true;
g_lastEggWidth43 = 0;
g_lastEggWidth169 = 0;
if (g_widescreenConfigured) {
VIUnlockAspectRatio();
ApplyEggScreenRecords(forceAspect169 ? 16u : surfaceWidth,
forceAspect169 ? 9u : surfaceHeight);
return;
}

AuroraSetViewportPolicy(AURORA_VIEWPORT_FIT);
VILockAspectRatio(4, 3);
ApplyEggScreenRecords(surfaceWidth, surfaceHeight);
ApplyEggScreenRecords(forceAspect ? (widescreen ? 16u : 4u) : surfaceWidth,
forceAspect ? (widescreen ? 9u : 3u) : surfaceHeight);
}
25 changes: 25 additions & 0 deletions runtime/src/hle/gx/gx_dynamic_aspect.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ inline float AspectRatioFactor(uint32_t width, uint32_t height) noexcept {
return SurfaceAspect(width, height) / kPresentationAspect169;
}

inline float AspectRatioFactor(uint32_t width, uint32_t height,
float referenceAspect) noexcept {
return SurfaceAspect(width, height) / referenceAspect;
}

// Hor+ factor, clamped at 1 so a tighter-than-16:9 surface never narrows the
// canvas (that would crop away scene the 16:9 view showed).
inline float HorizontalExpansion(uint32_t width, uint32_t height) noexcept {
Expand All @@ -53,6 +58,15 @@ inline float VerticalExpansion(uint32_t width, uint32_t height) noexcept {
return std::clamp(1.0f / factor, 1.0f, kMaxVerticalExpansion);
}

inline float VerticalExpansion(uint32_t width, uint32_t height,
float referenceAspect) noexcept {
const float factor = AspectRatioFactor(width, height, referenceAspect);
if (!(factor > 0.0f)) {
return 1.0f;
}
return std::clamp(1.0f / factor, 1.0f, kMaxVerticalExpansion);
}

inline uint32_t EggRecordWidth(uint32_t baseWidth, uint32_t surfaceWidth,
uint32_t surfaceHeight) noexcept {
const float scaledWidth =
Expand All @@ -61,6 +75,17 @@ inline uint32_t EggRecordWidth(uint32_t baseWidth, uint32_t surfaceWidth,
static_cast<uint32_t>(std::lround(scaledWidth / 4.0f)) * 4u, 4u, 0xFFFCu);
}

inline uint32_t EggRecordWidth(uint32_t baseWidth, uint32_t surfaceWidth,
uint32_t surfaceHeight,
float referenceAspect) noexcept {
const float scaledWidth = static_cast<float>(baseWidth) *
std::max(1.0f, AspectRatioFactor(surfaceWidth,
surfaceHeight,
referenceAspect));
return std::clamp<uint32_t>(
static_cast<uint32_t>(std::lround(scaledWidth / 4.0f)) * 4u, 4u, 0xFFFCu);
}

inline float EggHorizontalScale(uint32_t recordWidth) noexcept {
return kEggFramebufferWidth / static_cast<float>(std::max(recordWidth, 1u));
}
Expand Down
2 changes: 1 addition & 1 deletion runtime/src/hle/sc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ PPC_NATIVE_OVERRIDE(801B0220, SCCheckStatus_HLE, uint32_t, (), ());
// Returns: 0 = 4:3, 1 = 16:9
extern "C" uint32_t SCGetAspectRatio_HLE()
{
return (RuntimeConfigFile::WidescreenEnabled(true) || MkwForceAspect169Requested()) ? 1u : 0u;
return RuntimeConfigFile::AdvertisedAspectRatio169(true) ? 1u : 0u;
}

PPC_NATIVE_OVERRIDE(801B1BE4, SCGetAspectRatio_HLE, uint32_t, (), ());
Expand Down
19 changes: 11 additions & 8 deletions runtime/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1374,8 +1374,9 @@ int RuntimeMain(int argc, char** argv) {
auroraConfig.logCallback = &RuntimeAuroraLogCallback;
auroraConfig.logLevel = LOG_DEBUG;
const bool configWidescreen = RuntimeConfigFile::WidescreenEnabled(true);
const bool forceAspect169 = RuntimeConfigFile::ForceAspect169Enabled();
auroraConfig.windowWidth = (configWidescreen || forceAspect169) ? 854 : 640;
const bool advertisedAspect169 = RuntimeConfigFile::AdvertisedAspectRatio169(configWidescreen);
const bool forceAspect = RuntimeConfigFile::ForceAspectEnabled();
auroraConfig.windowWidth = (advertisedAspect169 || forceAspect) ? 854 : 640;
auroraConfig.windowHeight = 480;
auroraConfig.windowWidth = RuntimeConfigFile::WindowWidth(auroraConfig.windowWidth);
auroraConfig.windowHeight = RuntimeConfigFile::WindowHeight(auroraConfig.windowHeight);
Expand All @@ -1393,7 +1394,7 @@ int RuntimeMain(int argc, char** argv) {
auroraConfig.vsync = RuntimeConfigFile::Vsync();
auroraConfig.desiredBackend = BACKEND_AUTO;
const float resolutionMultiplier = RuntimeConfigFile::ResolutionMultiplier(1.0f);
ConfigureMkwDynamicAspect(configWidescreen, forceAspect169,
ConfigureMkwDynamicAspect(advertisedAspect169, forceAspect,
auroraConfig.windowWidth, auroraConfig.windowHeight);
VISetFrameBufferScale(resolutionMultiplier);
// One table for both directions. RuntimeConfigFile::IsSupportedGraphicsApi
Expand Down Expand Up @@ -1460,16 +1461,18 @@ int RuntimeMain(int argc, char** argv) {
UpdateMkwDynamicAspectSurface(auroraInfo.windowSize.native_fb_width,
auroraInfo.windowSize.native_fb_height);
settings_overlay::InitializeRuntimeSettings();
RT_LOG(RT_TAG_CONFIG) << "video.widescreen=" << (configWidescreen ? "true" : "false")
<< " force_16_9=" << (forceAspect169 ? "true" : "false")
<< " SCGetAspectRatio=" << (configWidescreen || forceAspect169 ? 1 : 0)
RT_LOG(RT_TAG_CONFIG) << "video.advertised_aspect_ratio="
<< (advertisedAspect169 ? "16:9" : "4:3")
<< " force_aspect=" << (forceAspect ? "true" : "false")
<< " SCGetAspectRatio=" << (advertisedAspect169 ? 1 : 0)
<< " resolutionMultiplier=" << resolutionMultiplier
<< " window=" << auroraInfo.windowSize.width << "x" << auroraInfo.windowSize.height
<< " native=" << auroraInfo.windowSize.native_fb_width << "x"
<< auroraInfo.windowSize.native_fb_height
<< " viewportPolicy=" << (forceAspect169 ? "16:9" : (configWidescreen ? "stretch" : "fit"))
<< " viewportPolicy=" << (forceAspect ? "fixed" : (advertisedAspect169 ? "stretch" : "fit"))
<< " presentAspect="
<< (forceAspect169 ? "16:9" : (configWidescreen ? "surface (dynamic EGG canvas)" : "4:3"))
<< (forceAspect ? (advertisedAspect169 ? "16:9" : "4:3")
: (advertisedAspect169 ? "surface (dynamic EGG canvas)" : "4:3"))
<< std::endl;
g_auroraInitialized.store(true, std::memory_order_release);
GxWorker::SetWaitCallback(ServiceGuestTimingDuringAuroraFrameWait);
Expand Down
23 changes: 18 additions & 5 deletions runtime/src/settings_overlay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ bool g_skipUnreadyPipelines = RuntimeConfigFile::SkipUnreadyPipelines(true);
bool g_vsync = RuntimeConfigFile::Vsync();
bool g_disableCopyFilter = RuntimeConfigFile::DisableCopyFilter(true);
bool g_showFps = RuntimeConfigFile::ShowFps(true);
bool g_forceAspect169 = RuntimeConfigFile::ForceAspect169Enabled();
bool g_forceAspect = RuntimeConfigFile::ForceAspectEnabled();
bool g_advertisedAspect169 = RuntimeConfigFile::AdvertisedAspectRatio169(true);
#if defined(__APPLE__)
bool g_metalFxSpatialUpscaling = RuntimeConfigFile::MetalFxSpatialUpscaling(false);
#endif
Expand Down Expand Up @@ -1069,11 +1070,23 @@ void DrawAudioSettings() {

void DrawGraphicsSettings() {
g_displayMode = static_cast<int>(aurora_get_display_mode());
if (ImGui::Checkbox("Force 16:9", &g_forceAspect169)) {
SetMkwForceAspect169(g_forceAspect169);
RuntimeConfigFile::SetForceAspect169(g_forceAspect169);
const char* advertisedAspectLabel = g_advertisedAspect169 ? "16:9" : "4:3";
if (ImGui::BeginCombo("Advertised aspect ratio (restart required)", advertisedAspectLabel)) {
if (ImGui::Selectable("16:9", g_advertisedAspect169)) {
g_advertisedAspect169 = true;
RuntimeConfigFile::SetAdvertisedAspectRatio169(true);
}
if (ImGui::Selectable("4:3", !g_advertisedAspect169)) {
g_advertisedAspect169 = false;
RuntimeConfigFile::SetAdvertisedAspectRatio169(false);
}
ImGui::EndCombo();
}
if (ImGui::Checkbox("Force aspect ratio", &g_forceAspect)) {
SetMkwForceAspect(g_forceAspect);
RuntimeConfigFile::SetForceAspect(g_forceAspect);
}
ImGui::TextDisabled("Keep a 16:9 image with black bars when the window has another shape.");
ImGui::TextDisabled("Keep the current aspect ratio with black bars when the window has another shape.");
ImGui::Separator();
struct EffectFlag {
const char* label;
Expand Down