Quake (PPSA01880, Kex Engine) crashes at startup because
sceVideoOutIsOutputSupported (NID Nv8c-Kb+DUM) is unimplemented.
The game calls it to check video output capabilities before
initializing rendering.
Add HLE export stub: returns 1 (supported) for SceVideoOutBusTypeMain,
0 otherwise. The emulator renders via Vulkan and supports any pixel
format or aspect ratio on the main bus.
NID verified via Ps5Nid.Compute SHA1 algorithm.
Export name confirmed in scripts/ps5_names.txt.
VReadlaneB32 (VOP3 0x360) had two bugs:
1. Decode: VOP3 decode always set destinations = Vector(word & 0xFF).
For VReadlaneB32, bits 0-7 are unused — the scalar destination is
in bits 8-14. Now decodes as Scalar((word >> 8) & 0x7F).
2. Emission: VReadlaneB32 was in the VMovB32 fall-through group,
just returning GetRawSource(instruction, 0) — reading the current
lane's value. By ISA, sdst = vsrc0[lane(src1)], which requires
reading a different lane's value. Now uses SPIR-V
GroupNonUniformBroadcast(scope=Subgroup, value=src0, lane=src1)
when subgroup operations are available, with a fallback to the
current-lane simplification when not.
3. Routing: TryEmitVectorAlu called TryGetVectorDestination first,
which checks for VectorRegister kind. With the scalar destination
fix, VReadlaneB32 now routes to a new TryEmitReadlane handler
before the vector destination check.
4. Subgroup capability: UsesSubgroupShuffle now includes VReadlaneB32
so GroupNonUniform capability is enabled when needed.
Verified: dotnet build 0 errors/0 warnings, 26/26 tests pass,
ShaderDump all programs behaved as expected.
PR #200 moved shader files from SharpEmu.Libs/Agc/ to new projects
SharpEmu.ShaderCompiler and SharpEmu.ShaderCompiler.Vulkan. This
re-ports the VOP3 decode fix from PR #226 to the new file paths.
Decode table (Gen5ShaderTranslator.cs):
- 0x360: VMadU32U16 -> VReadlaneB32 (per RDNA2 ISA)
- 0x361: VMulLoU32 -> VWritelaneB32 (0x361 was a duplicate of 0x169)
- 0x373: added VMadU32U16 at its correct opcode
Emission (Gen5SpirvTranslator.Alu.cs):
- VWritelaneB32: per-lane conditional write via IEqual+Select,
stores with guardWithExec:false (writelane bypasses exec mask)
- VReadlaneB32: kept as GetRawSource(instruction, 0) simplification
(correct emission with src1 lane select is a follow-up)
Verified: dotnet build 0 errors/0 warnings, 26/26 tests pass,
ShaderDump all programs behaved as expected.
- 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>