mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-25 20:28:48 +08:00
unstub: preserve notice screen skip flag (#559)
* fix(system-service): preserve notice screen skip flag * test(bink): avoid frame timing flake on CI
This commit is contained in:
@@ -18,6 +18,7 @@ public static class SystemServiceExports
|
|||||||
private const int TitleIdFieldSize = 0x10;
|
private const int TitleIdFieldSize = 0x10;
|
||||||
|
|
||||||
private static string? _mainAppTitleId;
|
private static string? _mainAppTitleId;
|
||||||
|
private static int _noticeScreenSkipFlag;
|
||||||
|
|
||||||
public static void ConfigureApplicationInfo(string? titleId)
|
public static void ConfigureApplicationInfo(string? titleId)
|
||||||
{
|
{
|
||||||
@@ -37,9 +38,11 @@ public static class SystemServiceExports
|
|||||||
return ctx.SetReturn(OrbisSystemServiceErrorParameter);
|
return ctx.SetReturn(OrbisSystemServiceErrorParameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// No system notice screen to skip in the emulator; report "do not skip".
|
// Keep the flag state even though the emulator does not display the
|
||||||
|
// system notice screen. Titles use this service as a normal preference
|
||||||
|
// store and expect a later get to observe the value they set.
|
||||||
Span<byte> flagBytes = stackalloc byte[1];
|
Span<byte> flagBytes = stackalloc byte[1];
|
||||||
flagBytes[0] = 0;
|
flagBytes[0] = unchecked((byte)Volatile.Read(ref _noticeScreenSkipFlag));
|
||||||
return ctx.Memory.TryWrite(flagAddress, flagBytes)
|
return ctx.Memory.TryWrite(flagAddress, flagBytes)
|
||||||
? ctx.SetReturn(0)
|
? ctx.SetReturn(0)
|
||||||
: ctx.SetReturn((int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
: ctx.SetReturn((int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
||||||
@@ -61,8 +64,13 @@ public static class SystemServiceExports
|
|||||||
ExportName = "sceSystemServiceSetNoticeScreenSkipFlag",
|
ExportName = "sceSystemServiceSetNoticeScreenSkipFlag",
|
||||||
Target = Generation.Gen5,
|
Target = Generation.Gen5,
|
||||||
LibraryName = "libSceSystemService")]
|
LibraryName = "libSceSystemService")]
|
||||||
public static int SystemServiceSetNoticeScreenSkipFlag(CpuContext ctx) =>
|
public static int SystemServiceSetNoticeScreenSkipFlag(CpuContext ctx)
|
||||||
ctx.SetReturn(0);
|
{
|
||||||
|
// The native API takes the flag value in the first argument. Treat any
|
||||||
|
// non-zero value as true, matching the bool-like PS5 ABI.
|
||||||
|
Volatile.Write(ref _noticeScreenSkipFlag, ctx[CpuRegister.Rdi] != 0 ? 1 : 0);
|
||||||
|
return ctx.SetReturn(0);
|
||||||
|
}
|
||||||
|
|
||||||
[SysAbiExport(
|
[SysAbiExport(
|
||||||
Nid = "4veE0XiIugA",
|
Nid = "4veE0XiIugA",
|
||||||
@@ -231,4 +239,7 @@ public static class SystemServiceExports
|
|||||||
Target = Generation.Gen4 | Generation.Gen5,
|
Target = Generation.Gen4 | Generation.Gen5,
|
||||||
LibraryName = "libSceSystemService")]
|
LibraryName = "libSceSystemService")]
|
||||||
public static int SystemServiceReportAbnormalTermination(CpuContext ctx) => ctx.SetReturn(0);
|
public static int SystemServiceReportAbnormalTermination(CpuContext ctx) => ctx.SetReturn(0);
|
||||||
|
|
||||||
|
internal static void ResetForTests() =>
|
||||||
|
Volatile.Write(ref _noticeScreenSkipFlag, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,7 +83,9 @@ public sealed class BinkFramePlaybackTests
|
|||||||
|
|
||||||
public uint Height => 1;
|
public uint Height => 1;
|
||||||
|
|
||||||
public uint FramesPerSecondNumerator => 20;
|
// Keep frame boundaries far enough apart that a loaded CI runner cannot
|
||||||
|
// skip an expected frame between polling iterations.
|
||||||
|
public uint FramesPerSecondNumerator => 2;
|
||||||
|
|
||||||
public uint FramesPerSecondDenominator => 1;
|
public uint FramesPerSecondDenominator => 1;
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,11 @@ public sealed class SystemServiceExportsTests
|
|||||||
{
|
{
|
||||||
private const ulong MemoryBase = 0x1_0000_0000;
|
private const ulong MemoryBase = 0x1_0000_0000;
|
||||||
|
|
||||||
|
public SystemServiceExportsTests()
|
||||||
|
{
|
||||||
|
SystemServiceExports.ResetForTests();
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetNoticeScreenSkipFlagWritesOneByteAtMemoryBoundary()
|
public void GetNoticeScreenSkipFlagWritesOneByteAtMemoryBoundary()
|
||||||
{
|
{
|
||||||
@@ -26,4 +31,23 @@ public sealed class SystemServiceExportsTests
|
|||||||
Assert.True(memory.TryRead(MemoryBase, flag));
|
Assert.True(memory.TryRead(MemoryBase, flag));
|
||||||
Assert.Equal(0, flag[0]);
|
Assert.Equal(0, flag[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SetNoticeScreenSkipFlagRoundTripsThroughGetter()
|
||||||
|
{
|
||||||
|
var memory = new FakeCpuMemory(MemoryBase, 2);
|
||||||
|
var context = new CpuContext(memory, Generation.Gen5)
|
||||||
|
{
|
||||||
|
[CpuRegister.Rdi] = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.Equal(0, SystemServiceExports.SystemServiceSetNoticeScreenSkipFlag(context));
|
||||||
|
|
||||||
|
context[CpuRegister.Rdi] = MemoryBase;
|
||||||
|
Assert.Equal(0, SystemServiceExports.SystemServiceGetNoticeScreenSkipFlag(context));
|
||||||
|
|
||||||
|
Span<byte> flag = stackalloc byte[1];
|
||||||
|
Assert.True(memory.TryRead(MemoryBase, flag));
|
||||||
|
Assert.Equal(1, flag[0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user