5 Commits

Author SHA1 Message Date
patchzyy 82991ec337 Version centrilsation 2026-09-27 13:00:12 +02:00
patchzyy e164af9ff4 Shader wait screen 2026-09-27 12:39:10 +02:00
patchzyy e409d9f99b undo black kart fix
it causes stutters
2026-09-27 12:11:03 +02:00
Michael G 85f250155f Fix controller mapping platform, player index sync, and socket errors (#251)
* Fix macOS controller platform, sync player indices, and preserve socket send error

- Preserve captured socket send error across diagnostic logging in network_socket.cpp
- Use SDL_GetPlatform() instead of hardcoded Windows in controller mapping wizard
- Synchronize Aurora and SDL player indices on port assignment and clear in pad.cpp
- Auto-assign Player 1 on macOS when unconfigured in input.cpp

* fix(input): refine macOS port 0 assignment and persistence logic

- Persist port 0 preference for newly connected controller even if already assigned player index 0
- Verify controller has no preference on other ports before assigning to port 0
2026-09-24 22:01:49 +02:00
patchzyy a9c9c0de26 Add force 16:9 viewport mode (#256) 2026-09-24 22:00:57 +02:00
28 changed files with 230 additions and 59 deletions
+2 -4
View File
@@ -107,7 +107,7 @@ jobs:
persist-credentials: false
# Wheel Wizard runs the downloaded setup with --version and refuses it when the reported
# version differs from the release tag, so a tag that was pushed without bumping every pinned
# version differs from the release tag, so a tag that was pushed without bumping the pinned
# version would ship an update nobody can install. Catch that before anything is published.
- name: Verify the tag matches the pinned setup version
env:
@@ -122,9 +122,7 @@ jobs:
status=1
fi
}
check Launcher/WiiCompiled.Setup.Windows/Program.cs "public const string Version = \"$version\";"
check Launcher/WiiCompiled.Setup.Windows/WiiCompiled.Setup.Windows.csproj "<Version>$version</Version>"
check Launcher/Build-Installer.ps1 "ProductVersion = '$version'"
check Launcher/Directory.Build.props "<Version>$version</Version>"
exit $status
# The build jobs upload with `archive: false`, which stores each installer as a raw file
+4 -1
View File
@@ -279,9 +279,12 @@ foreach ($required in @('ToolkitFingerprint','TranslationFingerprint','NativeToo
if ([string]::IsNullOrWhiteSpace($identities.$required)) { throw "Payload identity output is missing $required." }
}
$productVersion = ((& $setupHost --version) -join '').Trim()
if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($productVersion)) { throw 'The setup host did not report its version.' }
$manifest = [ordered]@{
SchemaVersion = 2
ProductVersion = '0.2.32'
ProductVersion = $productVersion
ExpectedGameId = $pins.GameId
ExpectedDolSha256 = $pins.DolSha256
ExpectedRelSha256 = $pins.RelSha256
+7
View File
@@ -0,0 +1,7 @@
<Project>
<PropertyGroup>
<!-- The one product version. Release tags must match it. -->
<Version>0.2.33</Version>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
</PropertyGroup>
</Project>
@@ -6,7 +6,6 @@
<Nullable>enable</Nullable>
<RootNamespace>WiiCompiled.Setup.Common.Cli</RootNamespace>
<AssemblyName>WiiCompiled.Setup.Common.Cli</AssemblyName>
<Version>0.2.32</Version>
<Authors>patchzy</Authors>
<Product>WiiCompiled</Product>
<Description>Packaging-time helper: resolves (downloading if needed) the nodtool binary bundled by build-appimage.sh and Build-Installer.ps1</Description>
@@ -5,7 +5,6 @@
<Nullable>enable</Nullable>
<RootNamespace>WiiCompiled.Setup.Common</RootNamespace>
<AssemblyName>WiiCompiled.Setup.Common</AssemblyName>
<Version>0.2.32</Version>
<Authors>patchzy</Authors>
<Product>WiiCompiled</Product>
<Description>Shared nodtool/Retro-WFC-payload logic used by both the Windows and Linux installers</Description>
+5 -1
View File
@@ -1,9 +1,13 @@
using System.Reflection;
namespace WiiCompiled.Setup.Linux;
internal static class ProductInfo
{
public const string Name = "WiiCompiled";
public const string Version = "0.2.32";
public static readonly string Version =
typeof(ProductInfo).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()!
.InformationalVersion;
}
/// <summary>One installed product's record inside install-state.json.</summary>
@@ -6,7 +6,6 @@
<Nullable>enable</Nullable>
<AssemblyName>WiiCompiled.Setup.Linux</AssemblyName>
<RootNamespace>WiiCompiled.Setup.Linux</RootNamespace>
<Version>0.2.32</Version>
<Authors>patchzy</Authors>
<Product>WiiCompiled</Product>
<Description>Command-line installer and launcher for WiiCompiled on Linux</Description>
@@ -1,5 +1,6 @@
namespace WiiCompiled.Setup.Windows;
using System.Reflection;
using System.Runtime.InteropServices;
internal static class Program
@@ -121,7 +122,9 @@ internal static class PlatformChecks
internal static class ProductInfo
{
public const string Name = "WiiCompiled";
public const string Version = "0.2.32";
public static readonly string Version =
typeof(ProductInfo).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()!
.InformationalVersion;
/// <summary>
/// The setup executable is copied into the installation under this name. It is the launcher and
@@ -7,7 +7,6 @@
<AssemblyName>WiiCompiled.Setup</AssemblyName>
<RootNamespace>WiiCompiled.Setup.Windows</RootNamespace>
<ApplicationManifest>app.manifest</ApplicationManifest>
<Version>0.2.32</Version>
<Authors>patchzy</Authors>
<Product>WiiCompiled</Product>
<Description>Command-line installer and launcher for WiiCompiled</Description>
@@ -88,6 +88,7 @@ typedef enum _AuroraViewportPolicy {
AURORA_VIEWPORT_FIT = 0, // Preserve logical aspect in the content framebuffer
AURORA_VIEWPORT_STRETCH = 1, // Match content framebuffer aspect to the native surface
AURORA_VIEWPORT_NATIVE = 2, // Use active framebuffer pixels directly
AURORA_VIEWPORT_16_9 = 3, // Fixed 16:9 content with bars on other surfaces
} AuroraViewportPolicy;
/**
+1
View File
@@ -46,6 +46,7 @@ void AuroraSetViewportPolicy(AuroraViewportPolicy policy) {
}
g_gxState.viewportPolicy = policy;
aurora::window::set_frame_buffer_aspect_fit(policy == AURORA_VIEWPORT_FIT);
aurora::window::set_force_aspect_16_9(policy == AURORA_VIEWPORT_16_9);
aurora::window::set_present_surface_fill(policy == AURORA_VIEWPORT_STRETCH);
if (changed) {
// Reapply the guest viewport and scissor after a resize.
+3 -5
View File
@@ -520,11 +520,9 @@ void GXCopyTex(void* dest, GXBool clear) {
clearState.clearAlpha = clear && alphaUpdate;
}
const auto copyFilter = combined_copy_filter_coefficients(g_gxState.copyFilterVFilter);
// Every GXCopyTex is observable texture data. Reusing a destination in this
// or the previous frame does not guarantee another redraw: menu thumbnail
// scratch targets can be reused and then retained. Depth copies have the
// same requirement. Only display presentation may skip unfinished draws.
const bool persistentCopy = true;
// Skip only recurring color copies so one-shot copies are never lost.
const bool producedConsecutively = handle.revision != 0 && currentFrame - handle.lastProducedFrame <= 1;
const bool persistentCopy = !aurora::gx::is_depth_format(texCopyFmt) && !producedConsecutively;
aurora::gfx::resolve_pass(handle.handle, rect, clearState.clearColor, clearState.clearAlpha, clearState.clearDepth,
clearState.clearColorValue, aurora::gx::clear_depth_value(), resolveFmt,
&sourceRect.sampleRect, g_gxState.texCopyHalfScale, &copyFilter, forceOpaqueAlpha,
+5 -4
View File
@@ -399,19 +399,20 @@ const char* PADGetNameForControllerIndex(const u32 idx) {
}
void PADSetPortForIndex(const u32 idx, const u32 port) {
if (port >= PAD_MAX_CONTROLLERS) return;
const auto* ctrl = __PADGetControllerForIndex(idx);
if (ctrl == nullptr) {
return;
}
const int32_t oldPort = SDL_GetGamepadPlayerIndex(ctrl->m_controller);
const int32_t oldPort = aurora::input::player_index(ctrl->m_index);
if (const auto* dest = aurora::input::get_controller_for_player(port); dest != nullptr && dest != ctrl) {
SDL_SetGamepadPlayerIndex(dest->m_controller, -1);
aurora::input::set_player_index(dest->m_index, -1);
}
if (oldPort >= 0 && oldPort != port) {
aurora::input::persist_controller_for_player(oldPort, nullptr);
}
SDL_SetGamepadPlayerIndex(ctrl->m_controller, static_cast<Sint32>(port));
aurora::input::set_player_index(ctrl->m_index, static_cast<Sint32>(port));
aurora::input::persist_controller_for_player(port, ctrl);
}
@@ -437,7 +438,7 @@ void PADClearPort(const u32 port) {
if (ctrl == nullptr) {
return;
}
SDL_SetGamepadPlayerIndex(ctrl->m_controller, -1);
aurora::input::set_player_index(ctrl->m_index, -1);
}
// Secondary bindings live only in memory; the runtime re-applies them from its
+2 -7
View File
@@ -1259,11 +1259,6 @@ void split_staging_batch() {
retained[i].assign(buffers[i]->data(), buffers[i]->data() + g_suspendedEfbBytes[i]);
}
}
// GXCopyTex can capture the ordinary EFB as well as an explicit offscreen
// target. Its command may arrive in the next batch, after this prefix has
// already been submitted. Preserve every prefix; target kind cannot tell
// us whether the guest will later retain these pixels in a texture.
for (auto& pass : g_renderPasses) pass.requireReadyPipelines = true;
auto encoder = g_device.CreateCommandEncoder();
end_batch(encoder);
render(encoder);
@@ -1614,8 +1609,8 @@ bool bind_pipeline(PipelineRef ref, const wgpu::RenderPassEncoder& pass, Pipelin
if (!skip_unready_pipelines()) {
pipelineReady = wait_pipeline(ref, pipeline);
} else if (requireReady) {
// Texture copies and capacity prefixes must retain complete draw results.
// A future display frame cannot repair a texture that already captured them.
// The pass resolves into a persistent texture (a one-shot bake such as MKW's minimap), so a
// skipped draw would never be re-issued. These run behind loads, not mid-race.
pipelineReady = wait_pipeline_for_persistent_pass(ref, pipeline);
} else {
pipelineReady = try_pipeline(ref, pipeline);
+2 -1
View File
@@ -214,7 +214,8 @@ Params make_params(wgpu::Extent3D sourceSize, const FrameMapping& mapping) noexc
return params;
}
const bool stretch = mapping.viewportPolicy == AURORA_VIEWPORT_STRETCH;
const bool stretch = mapping.viewportPolicy == AURORA_VIEWPORT_STRETCH ||
mapping.viewportPolicy == AURORA_VIEWPORT_16_9;
const float scaleX = static_cast<float>(sourceSize.width) / static_cast<float>(logicalSize.x);
const float scaleY = static_cast<float>(sourceSize.height) / static_cast<float>(logicalSize.y);
const float scale = std::min(scaleX, scaleY);
+23
View File
@@ -414,6 +414,29 @@ SDL_JoystickID add_controller(SDL_JoystickID which) noexcept {
g_GameControllers[instance] = controller;
ensure_player_index(g_GameControllers[instance]);
apply_port_preferences();
#if defined(SDL_PLATFORM_MACOS)
// First-use convenience only: never override a saved assignment or None.
if (g_portPreferences[0].state == PortPreferenceState::Unset) {
bool hasOtherPortPreference = false;
for (size_t port = 1; port < g_portPreferences.size(); ++port) {
if (g_portPreferences[port].state == PortPreferenceState::Controller &&
identity_match(g_portPreferences[port].identity, controller_identity(g_GameControllers[instance])) !=
IdentityMatch::None) {
hasOtherPortPreference = true;
break;
}
}
if (!hasOtherPortPreference) {
const auto* p0 = get_controller_for_player(0);
if (p0 == nullptr) {
assign_player_index(g_GameControllers[instance], 0);
persist_controller_for_player(0, &g_GameControllers[instance]);
} else if (p0 == &g_GameControllers[instance]) {
persist_controller_for_player(0, &g_GameControllers[instance]);
}
}
}
#endif
return instance;
}
+27 -1
View File
@@ -46,6 +46,7 @@ SDL_Window* g_window;
SDL_Renderer* g_renderer;
float g_frameBufferScale = 0.f;
bool g_frameBufferAspectFit = true;
std::atomic_bool g_forceAspect169{false};
bool g_presentSurfaceFill = false;
int g_presentAspectWidth = 0;
int g_presentAspectHeight = 0;
@@ -525,7 +526,20 @@ AuroraWindowSize get_window_size() {
int fb_w = native_fb_w;
int fb_h = native_fb_h;
const auto [baseW, baseH] = vi::configured_fb_size();
if (g_frameBufferAspectFit && baseW > 0 && baseH > 0) {
if (g_forceAspect169.load(std::memory_order_acquire) && native_fb_w > 0 && native_fb_h > 0) {
if (g_frameBufferScale > 0.f && baseW > 0 && baseH > 0) {
const auto [scaledW, scaledH] =
scale_frame_buffer_to_aspect(static_cast<int>(baseW), static_cast<int>(baseH),
g_frameBufferScale, 16.f / 9.f);
fb_w = scaledW;
fb_h = scaledH;
} else {
fb_w = std::min(native_fb_w,
std::max(1, static_cast<int>(std::lround(native_fb_h * (16.f / 9.f)))));
fb_h = std::min(native_fb_h,
std::max(1, static_cast<int>(std::lround(native_fb_w * (9.f / 16.f)))));
}
} else if (g_frameBufferAspectFit && baseW > 0 && baseH > 0) {
float renderScale = g_frameBufferScale > 0.f ? g_frameBufferScale : 1.f;
if (g_frameBufferScale <= 0.f) {
renderScale = std::min(static_cast<float>(native_fb_w) / static_cast<float>(baseW),
@@ -759,6 +773,14 @@ void set_frame_buffer_aspect_fit(bool fit) {
request_frame_buffer_resize();
}
void set_force_aspect_16_9(bool force) {
if (g_forceAspect169.load(std::memory_order_relaxed) == force) {
return;
}
g_forceAspect169.store(force, std::memory_order_release);
request_frame_buffer_resize();
}
void set_present_surface_fill(bool fill) {
g_presentSurfaceFill = fill;
}
@@ -781,6 +803,10 @@ void unlock_present_aspect_ratio() {
}
bool get_present_aspect_ratio(float& aspect) noexcept {
if (g_forceAspect169.load(std::memory_order_acquire)) {
aspect = 16.f / 9.f;
return true;
}
if (g_presentSurfaceFill && g_window != nullptr) {
// Queried once per presentation snapshot; use the cached native client size
// instead of re-entering SDL for a value the window procedure already knows.
+1
View File
@@ -56,6 +56,7 @@ void sync_frame_buffer_size() noexcept;
void request_frame_buffer_resize();
void set_frame_buffer_scale(float scale);
void set_frame_buffer_aspect_fit(bool fit);
void set_force_aspect_16_9(bool force);
void set_present_surface_fill(bool fill);
void lock_present_aspect_ratio(int width, int height);
void unlock_present_aspect_ratio();
+4 -4
View File
@@ -4267,7 +4267,7 @@ TEST_F(GXFifoTest, CopyTexColorFormatMarksResolvePersistent) {
EXPECT_TRUE(records.front().persistentCopy);
}
TEST_F(GXFifoTest, RecurringColorCopyPreservesEveryResolve) {
TEST_F(GXFifoTest, RecurringColorCopyKeepsLaterResolveSkippable) {
std::array<u8, 152 * 114 * 4> image{};
gxState().pixelFmt = GX_PF_RGBA6_Z24;
@@ -4281,7 +4281,7 @@ TEST_F(GXFifoTest, RecurringColorCopyPreservesEveryResolve) {
const auto& records = aurora::gfx::testing::resolve_pass_records();
ASSERT_EQ(records.size(), 2u);
EXPECT_TRUE(records[0].persistentCopy);
EXPECT_TRUE(records[1].persistentCopy);
EXPECT_FALSE(records[1].persistentCopy);
}
TEST_F(GXFifoTest, ColorCopyAfterFrameGapRegainsPersistentProtection) {
@@ -4301,7 +4301,7 @@ TEST_F(GXFifoTest, ColorCopyAfterFrameGapRegainsPersistentProtection) {
EXPECT_TRUE(records[1].persistentCopy);
}
TEST_F(GXFifoTest, CopyTexDepthFormatPreservesResolve) {
TEST_F(GXFifoTest, CopyTexDepthFormatKeepsResolveSkippable) {
std::array<u8, 4 * 4 * 4> image{};
gxState().pixelFmt = GX_PF_RGBA6_Z24;
@@ -4311,7 +4311,7 @@ TEST_F(GXFifoTest, CopyTexDepthFormatPreservesResolve) {
const auto& records = aurora::gfx::testing::resolve_pass_records();
ASSERT_EQ(records.size(), 1u);
EXPECT_TRUE(records.front().persistentCopy);
EXPECT_FALSE(records.front().persistentCopy);
}
TEST_F(GXFifoTest, CopyDispResolveIsNotPersistent) {
+3 -1
View File
@@ -16,7 +16,9 @@
#endif
extern "C" bool g_dynamicAspectRatioEnabled;
void ConfigureMkwDynamicAspect(bool widescreen, uint32_t surfaceWidth, uint32_t surfaceHeight);
void ConfigureMkwDynamicAspect(bool widescreen, bool forceAspect169, uint32_t surfaceWidth, uint32_t surfaceHeight);
void SetMkwForceAspect169(bool enabled);
bool MkwForceAspect169Requested();
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
+12
View File
@@ -33,6 +33,7 @@
struct RuntimeUserConfig {
std::optional<bool> widescreen;
std::optional<bool> forceAspect169;
std::optional<int32_t> windowPosX;
std::optional<int32_t> windowPosY;
std::optional<uint32_t> windowWidth;
@@ -298,6 +299,7 @@ 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"
"resolution_multiplier = 1.0\n"
"frame_interpolation_fps = 0\n"
"display_mode = \"windowed\"\n"
@@ -426,6 +428,7 @@ inline RuntimeUserConfig ParseConfigDocument(const toml::value& document) {
}
config.widescreen = FindConfigValue<bool>(document, "video", "widescreen");
config.forceAspect169 = FindConfigValue<bool>(document, "video", "force_16_9");
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) {
@@ -782,6 +785,15 @@ 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 SetForceAspect169(bool value) {
Mutable().forceAspect169 = value;
return WriteSetting("video", "force_16_9", value ? "true" : "false");
}
inline bool WindowPosition(int32_t& x, int32_t& y) {
if (!Get().windowPosX || !Get().windowPosY) {
return false;
+2 -1
View File
@@ -5,6 +5,7 @@
#include <imgui.h>
#include <SDL3/SDL_gamepad.h>
#include <SDL3/SDL_joystick.h>
#include <SDL3/SDL_platform.h>
#include <algorithm>
#include <array>
@@ -146,7 +147,7 @@ std::string BuildMappingString() {
mapping += std::string(kSteps[i].mappingKey) + ":" + *g_wizard.bindings[i] + ",";
}
}
mapping += "platform:Windows,";
mapping += std::string("platform:") + SDL_GetPlatform() + ",";
return mapping;
}
+46 -8
View File
@@ -2,6 +2,7 @@
#include "memory.h"
#include <algorithm>
#include <atomic>
#include "aurora_events.h"
#include "hle/gx/gx_dynamic_aspect.h"
@@ -14,6 +15,10 @@ 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_policyDirty = false;
uint32_t g_lastEggWidth43 = 0;
uint32_t g_lastEggWidth169 = 0;
@@ -167,21 +172,54 @@ void AssertMkwOffscreenScreenBypass() {
}
void UpdateMkwDynamicAspectSurface(uint32_t surfaceWidth, uint32_t surfaceHeight) {
if (!g_widescreenConfigured || surfaceWidth == 0 || surfaceHeight == 0) {
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;
}
AuroraSetViewportPolicy(AURORA_VIEWPORT_STRETCH);
ApplyEggScreenRecords(surfaceWidth, surfaceHeight);
if (!g_widescreenConfigured) {
if (g_policyDirty) {
AuroraSetViewportPolicy(AURORA_VIEWPORT_FIT);
VILockAspectRatio(4, 3);
ApplyEggScreenRecords(surfaceWidth, surfaceHeight);
g_policyDirty = false;
}
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 ConfigureMkwDynamicAspect(bool widescreen, uint32_t surfaceWidth, uint32_t surfaceHeight) {
g_widescreenConfigured = widescreen;
g_dynamicAspectRatioEnabled = widescreen;
void SetMkwForceAspect169(bool enabled) {
g_requestedForceAspect169.store(enabled, std::memory_order_release);
}
bool MkwForceAspect169Requested() {
return g_requestedForceAspect169.load(std::memory_order_acquire);
}
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;
g_lastEggWidth43 = 0;
g_lastEggWidth169 = 0;
if (widescreen) {
if (g_widescreenConfigured) {
VIUnlockAspectRatio();
ApplyEggScreenRecords(surfaceWidth, surfaceHeight);
ApplyEggScreenRecords(forceAspect169 ? 16u : surfaceWidth,
forceAspect169 ? 9u : surfaceHeight);
return;
}
+21 -2
View File
@@ -1,4 +1,5 @@
#include "hle_stubs.h"
#include "input_bindings.h"
#include "memory.h"
#include "wii_remote_input.h"
@@ -203,6 +204,24 @@ void WriteUnifiedStatus(uint32_t addr, const WiiRemoteInput::KpadSample* sample)
}
}
// Neutral sticks and no buttons while an overlay owns input; the remote stays connected.
bool ReadSample(uint32_t chan, WiiRemoteInput::KpadSample& sample) {
if (!WiiRemoteInput::ReadKpadSample(chan, sample)) {
return false;
}
if (InputBindings::InputBlocked()) {
sample.hold = 0;
sample.clHold = 0;
sample.stick[0] = sample.stick[1] = 0.0f;
sample.clLStick[0] = sample.clLStick[1] = 0.0f;
sample.clRStick[0] = sample.clRStick[1] = 0.0f;
sample.clLStickRaw[0] = sample.clLStickRaw[1] = 0;
sample.clRStickRaw[0] = sample.clRStickRaw[1] = 0;
sample.clTriggerL = sample.clTriggerR = 0;
}
return true;
}
} // namespace
// KPADRead: fills KPADStatus[0] for `chan` from the Bluetooth remote, returns the entry count.
@@ -212,7 +231,7 @@ extern "C" int32_t KPAD__Read_HLE(uint32_t chan, uint32_t statusPtr, uint32_t co
return 0;
}
WiiRemoteInput::KpadSample sample;
const bool have = WiiRemoteInput::ReadKpadSample(chan, sample);
const bool have = ReadSample(chan, sample);
try {
return WriteStatus(chan, statusPtr, have ? &sample : nullptr);
} catch (const Memory::AccessViolation&) {
@@ -234,7 +253,7 @@ extern "C" int32_t KPAD__GetUnifiedWpadStatus_HLE(uint32_t chan, uint32_t status
return 0;
}
WiiRemoteInput::KpadSample sample;
const bool have = WiiRemoteInput::ReadKpadSample(chan, sample);
const bool have = ReadSample(chan, sample);
try {
const uint32_t entries = std::min(count, kMaxEntries);
for (uint32_t i = 0; i < entries; ++i) {
+2 -1
View File
@@ -467,7 +467,8 @@ int32_t HandleIpTopIoctlv(uint32_t cmd, const std::vector<IoVector>& in, const s
const int ret = sendto(s->native, reinterpret_cast<const char*>(sendData), static_cast<int>(sendSize),
static_cast<int>(flags), destPtr, destLen);
const int hostError = ret < 0 ? NativeLastError() : 0;
int32_t result = SocketResult(ret);
// Diagnostics may change the native error; use the send result captured above.
int32_t result = ret >= 0 ? SocketResult(ret) : SocketErrorResult(hostError);
if (patchedWrite && ret == static_cast<int>(sendSize)) {
result = static_cast<int32_t>(in[0].size);
}
+2 -1
View File
@@ -9,6 +9,7 @@
#include <cstring>
#include "memory.h"
#include "runtime_config.h"
#include "aurora_events.h"
#include "runtime_log.h"
namespace {
@@ -52,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) ? 1u : 0u;
return (RuntimeConfigFile::WidescreenEnabled(true) || MkwForceAspect169Requested()) ? 1u : 0u;
}
PPC_NATIVE_OVERRIDE(801B1BE4, SCGetAspectRatio_HLE, uint32_t, (), ());
+8 -5
View File
@@ -1354,7 +1354,8 @@ int RuntimeMain(int argc, char** argv) {
auroraConfig.logCallback = &RuntimeAuroraLogCallback;
auroraConfig.logLevel = LOG_DEBUG;
const bool configWidescreen = RuntimeConfigFile::WidescreenEnabled(true);
auroraConfig.windowWidth = configWidescreen ? 854 : 640;
const bool forceAspect169 = RuntimeConfigFile::ForceAspect169Enabled();
auroraConfig.windowWidth = (configWidescreen || forceAspect169) ? 854 : 640;
auroraConfig.windowHeight = 480;
auroraConfig.windowWidth = RuntimeConfigFile::WindowWidth(auroraConfig.windowWidth);
auroraConfig.windowHeight = RuntimeConfigFile::WindowHeight(auroraConfig.windowHeight);
@@ -1372,7 +1373,8 @@ int RuntimeMain(int argc, char** argv) {
// No vsync knob: aurora always configures a non-blocking present mode.
auroraConfig.desiredBackend = BACKEND_AUTO;
const float resolutionMultiplier = RuntimeConfigFile::ResolutionMultiplier(1.0f);
ConfigureMkwDynamicAspect(configWidescreen, auroraConfig.windowWidth, auroraConfig.windowHeight);
ConfigureMkwDynamicAspect(configWidescreen, forceAspect169,
auroraConfig.windowWidth, auroraConfig.windowHeight);
VISetFrameBufferScale(resolutionMultiplier);
// One table for both directions. RuntimeConfigFile::IsSupportedGraphicsApi
// whitelists exactly these config names, so an unrecognised value has
@@ -1439,14 +1441,15 @@ int RuntimeMain(int argc, char** argv) {
auroraInfo.windowSize.native_fb_height);
settings_overlay::InitializeRuntimeSettings();
RT_LOG(RT_TAG_CONFIG) << "video.widescreen=" << (configWidescreen ? "true" : "false")
<< " SCGetAspectRatio=" << (configWidescreen ? 1 : 0)
<< " force_16_9=" << (forceAspect169 ? "true" : "false")
<< " SCGetAspectRatio=" << (configWidescreen || forceAspect169 ? 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=" << (g_dynamicAspectRatioEnabled ? "stretch" : "fit")
<< " viewportPolicy=" << (forceAspect169 ? "16:9" : (configWidescreen ? "stretch" : "fit"))
<< " presentAspect="
<< (g_dynamicAspectRatioEnabled ? "surface (dynamic EGG canvas)" : "4:3")
<< (forceAspect169 ? "16:9" : (configWidescreen ? "surface (dynamic EGG canvas)" : "4:3"))
<< std::endl;
g_auroraInitialized.store(true, std::memory_order_release);
+43 -7
View File
@@ -26,6 +26,7 @@
#include <chrono>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <limits>
#include <iostream>
#include <string>
@@ -109,6 +110,7 @@ int g_displayMode = [] {
bool g_skipUnreadyPipelines = RuntimeConfigFile::SkipUnreadyPipelines(true);
bool g_disableCopyFilter = RuntimeConfigFile::DisableCopyFilter(true);
bool g_showFps = RuntimeConfigFile::ShowFps(true);
bool g_forceAspect169 = RuntimeConfigFile::ForceAspect169Enabled();
uint32_t g_disabledPostProcessingPaths = RuntimeConfigFile::DisabledPostProcessingPaths(0);
std::array<int32_t, PAD_MAX_CONTROLLERS> g_configuredControllerIndices = [] {
std::array<int32_t, PAD_MAX_CONTROLLERS> indices{};
@@ -161,6 +163,11 @@ uint64_t g_presentedFrame = 0;
std::atomic_bool g_strapInputAccepted = false;
std::atomic_uint64_t g_startupDismissFrame = UINT64_MAX;
constexpr uint64_t kStrapTransitionCoverFrames = 60;
std::atomic_bool g_bootShadersReady = false;
bool g_bootShaderNotice = false;
Clock::time_point g_bootShaderWaitStart{};
constexpr uint32_t kBootShaderNoticeThreshold = 100;
constexpr auto kBootShaderWaitLimit = std::chrono::minutes(3);
constexpr std::array<ResolutionItem, 8> kResolutions = {{
{"Auto (window size)", 0.0f}, {"Native (1x)", 1.0f}, {"1.5x", 1.5f}, {"2x", 2.0f},
@@ -1006,6 +1013,12 @@ 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);
}
ImGui::TextDisabled("Keep a 16:9 image with black bars when the window has another shape.");
ImGui::Separator();
struct EffectFlag {
const char* label;
uint32_t flag;
@@ -1186,18 +1199,36 @@ void DrawStartupScreen() {
const float startY = std::max(0.0f, (viewport->Size.y - titleSize.y) * 0.5f);
ImGui::SetCursorPos(ImVec2(titleX, startY));
ImGui::TextUnformatted(kTitle);
constexpr const char* kHint = "Press F10 to open settings";
const ImVec2 hintSize = ImGui::CalcTextSize(kHint);
ImGui::SetWindowFontScale(0.8f);
ImGui::SetCursorPos(ImVec2(std::max(0.0f, (viewport->Size.x - hintSize.x) * 0.5f),
startY + titleSize.y + 12.0f));
ImGui::TextUnformatted(kHint);
if (g_bootShaderNotice && !g_bootShadersReady.load(std::memory_order_relaxed)) {
ImGui::SetWindowFontScale(0.9f);
char line[96];
std::snprintf(line, sizeof(line), "Compiling shaders, please hold on: %u remaining",
aurora_get_queued_pipeline_count());
const float lineX = std::max(0.0f, (viewport->Size.x - ImGui::CalcTextSize(line).x) * 0.5f);
ImGui::SetCursorPos(ImVec2(lineX, startY + titleSize.y * 1.8f));
ImGui::TextUnformatted(line);
}
}
ImGui::End();
ImGui::PopStyleVar();
ImGui::PopStyleColor();
}
void UpdateBootShaderState() {
if (g_bootShadersReady.load(std::memory_order_relaxed)) {
return;
}
const auto now = Clock::now();
if (g_bootShaderWaitStart == Clock::time_point{}) {
g_bootShaderWaitStart = now;
}
const uint32_t queued = aurora_get_queued_pipeline_count();
g_bootShaderNotice |= queued > kBootShaderNoticeThreshold;
if (queued == 0 || now - g_bootShaderWaitStart > kBootShaderWaitLimit) {
g_bootShadersReady.store(true, std::memory_order_release);
}
}
void DrawExitPrompt() {
constexpr const char* kTitle = "Exit";
if (g_exitPromptOpen && !ImGui::IsPopupOpen(kTitle)) ImGui::OpenPopup(kTitle);
@@ -1347,7 +1378,7 @@ void PersistDisplayModeIfChanged() {
void ApplyInputBlockState() {
const bool blocked = controller_mapping_wizard::IsActive() || g_rebind.active ||
g_exitPromptOpen || g_topBarVisible;
g_exitPromptOpen || g_topBarVisible || StartupScreenVisible();
PADBlockInput(blocked);
InputBindings::SetInputBlocked(blocked);
}
@@ -1375,6 +1406,9 @@ void InitializeRuntimeSettings() noexcept {
aurora_set_skip_unready_pipelines(g_skipUnreadyPipelines);
g_strapInputAccepted.store(false, std::memory_order_relaxed);
g_startupDismissFrame.store(UINT64_MAX, std::memory_order_relaxed);
g_bootShadersReady.store(false, std::memory_order_relaxed);
g_bootShaderNotice = false;
g_bootShaderWaitStart = {};
PADBlockInput(false);
InputBindings::SetInputBlocked(false);
}
@@ -1455,6 +1489,7 @@ void Draw() noexcept {
ApplyConfiguredMappings();
PersistDisplayModeIfChanged();
UpdateCursorAutoHide();
UpdateBootShaderState();
if (!StartupScreenVisible()) {
DrawShaderCompilationStatus();
}
@@ -1468,6 +1503,7 @@ void Draw() noexcept {
bool StartupScreenVisible() noexcept {
return !g_strapInputAccepted.load(std::memory_order_acquire) ||
!g_bootShadersReady.load(std::memory_order_acquire) ||
g_presentedFrame < g_startupDismissFrame.load(std::memory_order_relaxed);
}