Refactored parts of the time subsystem to improve POSIX/Orbis compliance and secure guest memory boundaries.
**1. POSIX `clock_gettime` updates:**
- Added `CLOCK_REALTIME_FAST` (10) and `CLOCK_MONOTONIC_FAST` (12) support for games using FreeBSD fast clock extensions.
- Fixed `NULL` pointer handling for `timespecAddress == 0`. It now returns `-1` with `EINVAL` (22) instead of `EFAULT` to match Orbis runtime behavior.
- Invalid `clock_id` values now properly fallback to `default` -> `-1` + `EINVAL`.
**2. Memory safety & monotonic tracking:**
- Replaced dual 8-byte scalar writes in both POSIX `clock_gettime` and Orbis `sceKernelClockGettime` with a single 16-byte write via `stackalloc byte[16]` and `BinaryPrimitives`. This prevents partial memory corruption at page boundaries.
- Bad non-NULL guest addresses now fail cleanly as `EFAULT` (POSIX) or `MEMORY_FAULT` (Orbis).
- Extracted core monotonic math into `GetProcessMonotonicTime()` in `KernelRuntimeCompatExports.cs` so both clock paths share the exact same `_processStartCounter` base.
**3. Host RDTSC optimization:**
- Fixed `CreateRdtscReader()` to copy stack-allocated opcode bytes into host `VirtualAlloc` memory via `unsafe { Buffer.MemoryCopy(...) }`. This completely gets rid of the redundant `.ToArray()` allocation on the hot path.
**Out of scope:** `sceKernelGettimeofday` / POSIX `gettimeofday` partial-write hardening; stricter clock validation in `sceKernelClockGettime`.
Read guest C strings in page-bounded chunks without heap allocations.
Return false when the buffer fills without a null terminator. Route exit
and _exit through RequestProcessExit.
* GUI: redesign library as a cover-art grid with game management
Replace the sidebar game list with a full-width grid of cover tiles.
Cover art is loaded automatically from each game's sce_sys/icon0.png
(pic0.png fallback) and decoded off the UI thread; games without art
get a deterministic gradient placeholder with the title's initials.
- New layout: search/scan toolbar, tile grid with hover and selection
states, bottom launch bar with cover thumbnail, collapsible launch
options and console panels (console auto-opens on launch)
- Right-click context menu on tiles: launch, open game folder, copy
path/title ID, remove from library
- Removed games persist in an ExcludedGames settings list; re-adding
a folder restores any removed games beneath it
- Search now also matches title IDs
- Fix: placeholder brushes were constructed on the scan thread, which
throws in Avalonia and was silently swallowed, yielding empty scans
* GUI: show full install folder size instead of eboot.bin size
The library previously displayed the size of eboot.bin alone, which
wildly understates a game's real footprint. The install folder is now
totaled recursively in the existing background pass (after cover art,
which is cheaper and more visible), and each tile updates live once
its size is ready.
* GUI: selection backdrop, smaller tiles, controller navigation
Address review feedback on the library redesign:
- Selecting a game fades its key art (sce_sys/pic0.png, pic1.png
fallback) in as the window backdrop, dimmed by a gradient scrim;
decoded off the UI thread and cached per entry
- Cover tiles reduced from 156px to 128px
- The library can be driven with a DualSense: d-pad/left stick moves
the selection (hold-to-repeat, row-aware), Cross launches, Circle
stops; input is ignored while the launcher window is unfocused.
Reuses the pad HID reader by compile-linking its dependency-free
sources instead of referencing all of SharpEmu.Libs
* Pad: native DualSense support via raw HID
Read a real DualSense (or DualSense Edge) controller directly over
Win32 HID and feed its state into scePadRead/scePadReadState, replacing
the keyboard-only input path. No new dependencies.
- Device discovery by Sony VID/PID through setupapi/hid.dll, with
hot-plug: disconnects fall back to keyboard and reconnect
automatically
- USB input report 0x01 and Bluetooth extended report 0x31 (activated
via the feature report 0x05 handshake) are both parsed
- Full mapping to SCE_PAD_BUTTON conventions: face buttons, d-pad hat,
L1/R1/L2/R2 digital bits, analog triggers, L3/R3, Options, touchpad
click, both sticks
- Controller and keyboard input merge: buttons OR together, controller
sticks win past a small deadzone, triggers take the max
* Pad: rumble and lightbar output for DualSense
Wire scePadSetVibration, scePadSetLightBar and scePadResetLightBar to
real DualSense output reports. The output payload follows the same
layout as the Linux hid-playstation driver: both rumble motors,
lightbar RGB and the player LED indicator.
- USB uses output report 0x02; Bluetooth uses the 0x31 wrapper with a
sequence tag and CRC32 (0xA2-seeded) trailer, transport detected
from the first input report
- Output goes through a dedicated device handle so writes never
contend with the blocking input read loop
- On connect the controller gets a default state (blue lightbar,
player 1 LED); rumble state resets on disconnect
Verified on hardware over USB: lightbar color cycling and both motors.
Bluetooth output is implemented per spec but not yet hardware-tested.
- FileLogSink: thread-safe file writer with AutoFlush, FileShare.Read for
concurrent read access (tail -f), automatic parent directory creation,
full date-time timestamps, IDisposable for graceful shutdown
- CompositeLogSink: fan-out to multiple sinks with per-sink exception
isolation (one broken sink cannot silence the others), IDisposable
propagates to children
- SharpEmuLog: ResolveSinkFromEnvironment() reads SHARPEMU_LOG_FILE and
creates CompositeLogSink(console + file) when set; Sink setter now
disposes the previous IDisposable sink to prevent file handle leaks;
Shutdown() flushes and disposes the active sink
- Program.cs: Main wrapped in try/finally to guarantee SharpEmuLog.Shutdown()
runs on all exit paths (GUI, mitigated child, normal, exception)
Co-authored-by: Hermes Atlas <hermesatlas@example.com>
* [agc] Add shader type 4 (GS) and register defaults v13 support
Astro Bot (#11) crashes on boot due to two missing GPU features:
1. Shader type 4 (Geometry Shader) — SPI_SHADER_PGM_LO/HI register
offsets 0x8A/0x8B were missing. Added constants and switch cases
for shader type 4 in GetExpectedSpiShaderPgmLo/Hi. Also added
type 4 to IsEsGeometryShaderType (2 or 4 or 6).
2. Register defaults version 13 — was not recognized as supported.
Added RegisterDefaultsVersion13 constant and included it in
IsSupportedRegisterDefaultsVersion.
* [kernel] Add POSIX pthread_cond_timedwait export
SILENT HILL (#4) and Poppy Playtime (#3) crash on boot due to
missing POSIX pthread_cond_timedwait (NID 27bAgiJmOh0).
The Sony wrapper scePthreadCondTimedwait (NID BmMjYxmew1w) was
already implemented, but the raw POSIX symbol was not exported.
Added [SysAbiExport] for pthread_cond_timedwait delegating to
existing PthreadCondWaitCore with timed: true.
* [memory] Fix FlushInstructionCache null process handle
PhysicalVirtualMemory.cs called FlushInstructionCache with null as the
process handle in two places (SetProtection and TryWriteExclusive).
On Windows, a null handle does not reliably resolve to the current
process — the correct call is GetCurrentProcess() (pseudo-handle -1).
Also corrected the P/Invoke signature:
- Changed return type from void to bool with [return: MarshalAs(Bool)]
- Added SetLastError = true
- Added GetCurrentProcess() P/Invoke import
This matches the pattern already used in DirectExecutionBackend.cs
which correctly passes GetCurrentProcess() to all FlushInstructionCache
calls.
* [hle] Distinguish NOT_FOUND from NOT_IMPLEMENTED and log duplicate NIDs
Three diagnostic improvements to the HLE dispatch path:
1. ModuleManager.RegisterFromAssembly — duplicate NID registration was
silently skipped (dispatchTable first-wins, exportTable last-wins,
causing metadata divergence). Now logs a warning with the NID and
export name so conflicts are visible.
2. ModuleManager.TryDispatch — generation mismatch returned
ORBIS_GEN2_ERROR_NOT_FOUND, conflating 'function does not exist'
with 'function exists but not for this generation'. Now returns
ORBIS_GEN2_ERROR_NOT_IMPLEMENTED for generation mismatch, matching
the existing convention in CpuDispatcher. Also adds debug logging
for both NOT_FOUND and NOT_IMPLEMENTED paths.
3. DirectExecutionBackend.Imports.cs — the import dispatch else-branch
(the actual hot path that bypasses ModuleManager.TyDispatch via
cached export) had the same conflation. Split into:
- else if (export exists but generation mismatch) → NOT_IMPLEMENTED
- else (no export at all) → NOT_FOUND
This makes runtime diagnostics correctly distinguish missing exports
from generation-unsupported exports.
* [cpu] Check VirtualProtect return values in all stub creation paths
9 VirtualProtect calls in DirectExecutionBackend.cs had unchecked
return values. If VirtualProtect silently fails, memory protection
remains incorrect — stubs allocated with PAGE_EXECUTE_READWRITE (0x40)
never get downgraded to PAGE_EXECUTE_READ (0x20), or guest thread
entry stubs never get upgraded to writable. This causes access
violations on next execution or silent data corruption.
Fixed all 9 sites with proper error handling:
- 6 stub creation methods (return 0 on failure + log error)
- 2 guest thread entry methods (set reason + return Exception)
- 1 guest entry method (set LastError + return MEMORY_FAULT)
Stub creation sites fixed:
- CreateImportDispatchStub (line ~1683)
- EnsureTlsHandler (void, log + return)
- CreateUnresolvedReturnStub (return 0)
- CreateGuestReturnStub (return 0)
- CreateExceptionHandlerTrampoline (return 0)
- CreateTlsStoreHelperStub (return 0)
Guest thread entry sites fixed:
- StartGuestThreadNativeCall (return Exception)
- StartGuestContinuationNativeCall (return Exception)
- RunGuestEntryPoint (return MEMORY_FAULT)
* [kernel] Remove unused duplicate _nextFileDescriptor field
KernelExports.cs declared _nextFileDescriptor but never used it.
The actual field used for file descriptor allocation lives in
KernelMemoryCompatExports.cs (lines 1314, 1337). This was a dead
duplicate causing CS0414 warning.
Build is now 0 errors, 0 warnings.
---------
Co-authored-by: Hermes Atlas <hermesatlas@example.com>
* [gui] Add Avalonia desktop frontend
Adds SharpEmu.GUI, a dark-themed desktop frontend that drives the
SharpEmu CLI as a child process:
- Game library with folder scanning for eboot.bin, search, and
persisted settings (%APPDATA%/SharpEmu/gui-settings.json)
- Launch options mapped to CLI flags (log level, strict dynlib
resolution, import trace limit)
- Live console with severity color-coding, bounded buffer, and
crash-safe deferred auto-scroll
- EmulatorProcess launches the CLI via CreateProcessW with the same
CET/CFG mitigation opt-outs the CLI applies to its own relaunched
child (suppressed via SHARPEMU_DISABLE_MITIGATION_RELAUNCH so
output is not lost to a detached console), inheritable pipes for
stdout/stderr capture, a kill-on-close job object, and a fallback
to an unmitigated launch on Windows builds that reject the policy
bits
Also pins Tmds.DBus.Protocol 0.21.3 (transitive of Avalonia.Desktop)
to fix GHSA-xrw6-gwf8-vvr9.
* [gui] Integrate GUI into the SharpEmu executable
Per review feedback, the GUI is no longer a separate application.
SharpEmu.exe now opens the desktop frontend when started without
arguments and behaves exactly as the existing CLI when given any
argument:
- SharpEmu.GUI becomes a class library exposing GuiLauncher.Run(),
hosted by SharpEmu.CLI
- The console window is hidden in GUI mode only when the process is
its sole owner (double-click launch), never a terminal the user
launched from
- In GUI mode the frontend spawns this same executable (with
arguments) as the emulator child process, so the existing launch,
piping, and mitigation machinery is unchanged
* [gui] Address review feedback: no console, single-file, param.json, portable settings
- Switch SharpEmu.exe to the GUI subsystem so no console window appears
at startup. CLI mode attaches to the parent terminal console (or
allocates one when started with arguments but no terminal) and
rebinds missing std handles to CONOUT$; piped/redirected output is
used as-is, so scripted and GUI-spawned runs are unaffected.
- Publish as a true single file: native libraries are embedded and
self-extracted, with glfw kept as the only loose DLL next to the
executable.
- The game library reads sce_sys/param.json and shows the game title
with the title id beneath it, falling back to the folder name.
- GUI settings and the crash log now live next to the executable,
matching the emulator convention, instead of %APPDATA%.
* [build] Add win-x64 sections to package lock files
Generated by dotnet publish -r win-x64 with locked restore enabled.
* [build] Regenerate lock files from project configuration
dotnet restore --force-evaluate; removes the win-x64 runtime sections
that a local RID-specific publish had written into projects that do
not declare a runtime identifier, which broke locked-mode restore in
CI. Verified with dotnet restore -p:RestoreLockedMode=true.
---------
- Enable VertexPipelineStoresAndAtomics/FragmentStoresAndAtomics:
fixes vkCreateGraphicsPipelines() rejecting guestBuffers storage
descriptor as NonWritable in vertex/fragment stages.
- Enable ShaderInt64: fixes vkCreateShaderModule() rejecting SPIR-V
using 64-bit integer capability.
- Query GetPhysicalDeviceFeatures first and only enable what the GPU
actually reports as supported, with a warning fallback otherwise.
Also adds optional Vulkan Validation Layers (SHARPEMU_VK_VALIDATION=1)
to surface these VUID errors during development instead of silent
VK_ERROR_DEVICE_LOST.
* [shader-decoder-part1] Implemented a shader decoder for Gen5 shaders, including IR generation, metadata reading, scalar evaluation, and SPIR-V translation. Updated related exports and video output components to support the new shader decoding functionality.
* [shader decoder] correct RDNA2 operands, fixing synchronization problems
* [shader-decoder] RDNA2 decoder improvements
* [shader-decoder] fix RDNA2 shift masking and sprite draws
* [shader-decoder] improve RDNA2 shader decoder to support more instructions and fix some issues with the previous implementation.