mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-24 11:48:39 +08:00
fbafd3f429a882291d0f20137cbd6edf0347c4d3
33 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
fbafd3f429 |
[GUI] Add native Vulkan host surface support and more (#337)
* [GUI] Add native Vulkan host surface support and more * reuse * [GUI] set width session menu |
||
|
|
b9eee497aa |
[VideoOut] Scope the AMD integrated-GPU penalty to Windows (#339)
* [VideoOut] Prefer real integrated GPUs over software rasterizers (#325) Penalize only AMD integrated GPUs (the #97 vkCreateGraphicsPipelines crash) instead of all integrated devices, so Intel/Apple/Qualcomm iGPUs outrank Cpu-type software rasterizers (Mesa lavapipe). Hoist ScorePhysicalDevice to the outer class and add unit tests for the ordering. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * [VideoOut] Scope AMD iGPU penalty to Windows via a penalty helper Extract ComputeDevicePenalty (the value subtracted from a device's base score) and gate the #97 AMD-integrated penalty on Windows only. Mesa RADV on Linux (e.g. the Steam Deck's AMD APU) is a different, working driver and should keep its full integrated score. Add a Steam Deck test case and drop inline comments. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * [VideoOut] Move device-scoring helpers out of the const block Relocate ScorePhysicalDevice and ComputeDevicePenalty below the leading const cluster instead of splitting it, and trim the vendor-ID reference comment to adapters an x86-64 host can realistically enumerate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
dbd74654c4 | Vulkan: trim disabled draw diagnostics overhead (#307) | ||
|
|
8f405caebe | Vulkan: reduce guest buffer upload allocations (#301) | ||
|
|
dabf723b3e | [Vulkan] Honor guest depth clear state (#290) | ||
|
|
53d414e096 |
Bound Vulkan host buffer pool memory (#201)
Co-authored-by: Dafenx <196083014+Dafenxz0@users.noreply.github.com> |
||
|
|
c5a82c1065 |
[Perf] Behavior-preserving hot-path allocation/LINQ wins (#264)
* [Perf] Gate event-flag tracing so it allocates nothing when disabled TraceEventFlag built its interpolated argument (and, on the wait path, FormatFrameChain + a new StringBuilder(256) in FormatGuestWaitObject plus ~12 guest-memory reads) on every call, then checked the env var inside the method — so every sceKernelSetEventFlag/Clear/Poll/Wait paid a string allocation and an Environment.GetEnvironmentVariable P/Invoke even with tracing off. Cache the flag once in a static readonly bool and gate every call site, matching the semaphore/event-queue pattern. Behavior is unchanged when SHARPEMU_LOG_EVENT_FLAG=1. * [Perf] Hoist IsNoBlockLeaf classification to import-stub setup The leaf-dispatch path called IsNoBlockLeafImport(nid) — a ~30-literal string pattern match — on every leaf import. IsLeaf/NidHash were already precomputed on ImportStubEntry at stub setup; add IsNoBlockLeaf alongside them and read the field in the hot path. Behavior unchanged. * [Perf] Cache trace env-var flags read on hot paths Two SHARPEMU_LOG_* env vars were read via Environment.GetEnvironmentVariable (a P/Invoke + transient string) on hot paths: SHARPEMU_LOG_FIBER on every fiber context transfer, and SHARPEMU_LOG_DIRECT_MEMORY on every direct-memory op (~8 sites). Cache both once — _logFiber alongside the other backend _log* flags, and _traceDirectMemory behind the existing ShouldTraceDirectMemory helper. Behavior unchanged. * [Perf] Avoid per-iteration thread snapshot in the idle pump loop PumpUntilGuestThreadsIdle allocated a full GuestThreadState[] snapshot (via LINQ Values.ToArray()) on every spin just to tally three run-state booleans. Tally them under the lock with an allocation-free helper, and only materialize the snapshot inside the gated (default-off) diagnostic dump. SnapshotGuestThreads now uses Values.CopyTo instead of LINQ. Behavior unchanged. * [Perf] De-LINQ GetPixelColorExportMask on the per-draw path GetPixelColorExportMask ran a Select/OfType/Where/Aggregate chain over all shader instructions, allocating iterators + closures, and is called per render target (twice per draw via CreateRenderState and HasPixelColorExport). Replace with a manual scan producing the identical mask — no allocation, and it removes an authored-LINQ use the repo bans. * [Perf] De-LINQ per-draw render-target selection in AgcExports The bound-render-target selection used Where(...).OrderBy(...).ToArray() (plus a second Where/ToArray fallback) on every translated draw, allocating LINQ iterators + closures. Replace with an explicit filter into a pre-sized list + List.Sort by slot; slots are distinct so this matches the stable OrderBy. Same result, no per-draw LINQ allocations. * [Perf] De-LINQ per-draw render-target validation in the Vulkan presenter SubmitOffscreenTranslatedDraw validated its render targets with targets.Any(...) twice plus targets.Select(a=>a.Address).Distinct().Count() (a per-draw HashSet), and broadcast a single blend with Enumerable.Repeat(...).ToArray(). Targets are <= 8, so replace with manual scans (invalid-target check; combined dimension-mismatch + pairwise aliasing check) and Array.Fill. Same results, no per-draw LINQ allocations. * [Perf] Binary-search VirtualQuery region lookup (SortedList) _mappedRegions was an unordered Dictionary, so TryFindVirtualQueryRegionLocked scanned every region for containment/next — O(n) per sceKernelVirtualQuery and O(n^2) when an allocator walks the address space with the findNext flag. Store regions in a SortedList keyed by base address (every write already uses the region's own address as the key) and find the containing/next region with a binary search over the sorted keys. Also drops a now-redundant Values.OrderBy. Non-overlapping regions assumed (mmap semantics), so only the floor region can contain the query. Behavior-preserving; worth spot-checking VirtualQuery-heavy titles. * [Perf] Remove stray CLI packages.lock.json committed by mistake git add -A in an earlier commit swept in a regenerated src/SharpEmu.CLI/packages.lock.json. main tracks no lock files (central package management, no RestorePackagesWithLockFile), and REUSE.toml no longer covers packages.lock.json, so the committed file failed the REUSE Compliance check. Remove it. |
||
|
|
2196a1f786 |
Gate Vulkan texture upload traces (#220)
Co-authored-by: Dafenx <196083014+Dafenxz0@users.noreply.github.com> |
||
|
|
b4b95014f1 |
Fix/deadcells crash (#262)
* Boot compatibility fixes for UE titles, GUI toggles, and DeS render/boot work Checkpoint of the Monster Truck Championship and Demon's Souls boot work. Each piece is independently useful and verified against the titles. - playgo: scePlayGoGetLocus now returns BAD_CHUNK_ID for chunk ids outside the known set, matching real firmware. Titles enumerate chunk ids until that error; answering OK for every id made the scan wrap the ushort range and spin forever. Missing-sidecar and no-app0 fallbacks report a fully-installed single chunk 0 so scePlayGoOpen keeps succeeding. - kernel: restore the SHARPEMU_WRITABLE_APP0 opt-in. Unpackaged UE dumps write their Saved tree under /app0 during PS5 component init and treat the denial as a fatal boot error. - pad: accept handle 0 as the primary pad across all pad calls. Real firmware hands out small non-negative handles and some titles read state with handle 0. - bthid: env-gated experiment hooks for the Thrustmaster wheel middleware investigation (fail-only-RegisterCallback modes and a synthetic enumeration callback with a zeroed event struct). All default off. - gui: add SHARPEMU_LOG_IO and SHARPEMU_WRITABLE_APP0 toggles to the Environment tab. - videoout: per-swapchain-image render-finished semaphores (the shared semaphore raced the swapchain); whole-mip-chain layout init for offscreen guest images (sampled binds read mips stuck in Undefined); GPU-resident texture availability now canonicalizes through the texture format table and accepts compatibility-class aliases, cutting per-frame CPU texture re-reads (143 GB -> 55 GB per 300 s in Demon's Souls, 0.2 -> 0.5 fps). - hle: add sceSystemServiceGetNoticeScreenSkipFlag, sceSystemServiceGetMainAppTitleId (title id published from the runtime), and sceNpWebApi2CreateUserContext (refuses so the online layer backs off). - rtc: SHARPEMU_RTC_PROBE_RANGE diagnostic dumps the code around a busy-wait caller of sceRtcGetCurrentTick once; costs nothing when unset. * [ShaderCompiler] Fix VReadlaneB32 scalar destination field The scalar destination lives in the low vdst byte (bits 0-7); it was read from bits 8-14, the VOP3B carry-out field readlane does not have, sending every readlane result to s0. Verified against raw gfx10 encodings and LLVM's assembler tests (v_readlane_b32 s5, v1, s2 -> low byte 0x05). * [VideoOut] Survive device loss and flip-order asserts without dying Two ways a frame could take down the whole presenter: - Device loss between any two Vulkan calls in a frame unwound the window thread, and the Dispose-time fence check then threw again, masking the original error. Catch the loss at the frame boundary, retire presentations and guest submissions whose fences can never signal, and keep the window loop pumping so the game (audio, logic) carries on. - The ordered-flip capture invariant is violated ~100 times per run by Demon's Souls (PPSA01342); on debug builds the Debug.Assert fail-fasts the process with nothing in the log. Downgrade it to a once-per-version warning until the capture/wait ordering is understood. * Fix Dead Cells shader cache regression --------- Co-authored-by: StealUrKill <35749471+StealUrKill@users.noreply.github.com> |
||
|
|
7b91c964fc | [VulkanVideoPresenter] revert back icon | ||
|
|
864cbb0fa0 |
[AGC/Vulkan] Extend PS5 runtime and rendering compatibility (#216)
* [Core] Add POSIX native execution and PS5 SELF support Extend the native backend, guest TLS, fixed-address memory, and loader paths needed by PS5 titles on Windows, Linux, and macOS. Keep workstation GC so high-core-count hosts do not reserve over fixed guest image bases. * [HLE] Expand PS5 service and media compatibility Add the kernel, threading, save-data, networking, audio, video-codec, font, dialog, and service exports required by newer PS5 software. Preserve every SysAbi NID currently registered by main while adding the compatibility surface used by ASTRO BOT. * [AGC/Vulkan] Extend Gen5 shader and presentation support Expand PM4 handling, Gen5 shader translation, MRT and packed export support, guest image tracking, depth initialization, texture aliasing, and Vulkan presentation. Add the performance overlay and address-filtered diagnostics used to validate ASTRO BOT with original shaders. * [Core] Align static TLS reservation across hosts * [Pad] Align primary user ID with UserService * [Gpu] Preserve runtime scalar buffers across renderer seam * [AGC] Restore omitted command helper exports * [Vulkan] Reuse primary views for promoted MRT targets * [Vulkan] Preserve scratch storage bindings in compute dispatches |
||
|
|
30fdd8d6ed |
[Gpu] Backend-neutral shader compiler and guest-GPU renderer seam (#200)
* [ShaderCompiler] Extract the backend-neutral shader compiler project Move the Gen5 (gfx10) microcode decoder, the scalar evaluator, the shader IR, and the metadata reader out of SharpEmu.Libs/Agc into a new SharpEmu.ShaderCompiler project — the half of shader compilation every codegen backend (SPIR-V today; MSL and DXIL later) consumes. Types go public: they are the contract now. Nothing in the project may depend on a host graphics API; the SPIR-V-specific artifact types (Gen5SpirvShader, Gen5SpirvStage) stay beside the emitter in Libs. Three couplings surfaced by the move, each resolved at the right depth: GuestDrawKind was defined inside VulkanVideoPresenter despite being a guest-domain, decoder-produced concept — it moves to the shared project; the evaluator's one HLE dependency (the tracked-libc-heap read fallback) becomes an injectable hook that a Libs module initializer installs before any caller can reach the evaluator; and the inline- constant table is promoted to a shared Gen5InlineConstants so backends cannot drift on constant semantics (the SPIR-V translator now delegates to it). The ShaderDump tool drops its reflection over the moved types in favor of direct typed calls; only the SPIR-V emitter, still internal to Libs until it moves to its own backend project, is reached via reflection. Verified by a clean solution build, the existing test suite, and a full ShaderDump conformance run. * [ShaderCompiler] Move the SPIR-V emitter into SharpEmu.ShaderCompiler.Vulkan Gen5SpirvTranslator (with its ALU partial), SpirvModuleBuilder, SpirvFixedShaders, and the Gen5SpirvShader/Gen5SpirvStage artifact types move whole from SharpEmu.Libs/Agc into the first per-backend codegen project. Notably it needs no Vulkan bindings reference: emitters produce bytes from the shared IR; renderers own graphics APIs. Types go public as the backend's contract; AgcExports and the presenter consume them exactly as before. The ShaderDump tool drops its last reflection: with both halves of the pipeline public it drives decode and all three emit entry points with direct typed calls, retiring the PadWithDefaults invoke shim — and it no longer references SharpEmu.Libs at all, making the conformance tool emulator-independent by design. Verified by a clean solution build, the test suite, a full ShaderDump conformance run, and a locked-mode restore under the pinned SDK. * [Gpu] Extract the guest-GPU backend seam (IGuestGpuBackend) The AGC/VideoOut/SystemService export layers now reach the renderer through IGuestGpuBackend via GuestGpu.Current (mirroring HostPlatform), instead of calling VulkanVideoPresenter statics. The Vulkan backend is a thin adapter over the existing presenter, so the extraction stays mechanical; only the adapter and the presenter itself reference the presenter now. The types crossing the seam move to Gpu/GuestGpuTypes.cs and drop their Vulkan prefixes, which an audit showed were misnomers: every field is a neutral primitive or a raw guest value (guest addresses, format and number-type codes, CB_BLEND register bitfields, verbatim sampler descriptor dwords). The one genuine Vulkan value in the old surface — the Silk.NET Format inside VulkanRenderTargetFormat, which callers never read — stops crossing: TryDecodeRenderTargetFormat is replaced at the seam by TryGetRenderTargetOutputKind, which surfaces only the Gen5PixelOutputKind callers actually consume, keeping native formats a backend-internal concern. ToVulkanSampler in AgcExports is renamed ToGuestSampler to match what it always produced. Seam rules are documented on the interface: no host-API value crosses, and submission stays coarse-grained with synchronization internal to backends. Interim exception, resolved next: shader parameters are still SPIR-V blobs. * [Gpu] Move shader compilation behind the guest-GPU backend The seam's interim exception is gone: AgcExports no longer calls Gen5SpirvTranslator or handles SPIR-V bytes. IGuestGpuBackend gains the three TryCompile entry points, which take the backend-neutral (Gen5ShaderState, Gen5ShaderEvaluation) contract plus the flat per-role resource-slot bases a multi-stage draw needs, and return opaque IGuestCompiledShader handles that only the producing backend can submit — the Vulkan backend wraps its SPIR-V in VulkanCompiledGuestShader and rejects foreign handles loudly. Draw and dispatch submissions take handles instead of byte arrays; the shader caches in AgcExports store handles. IGuestCompiledShader.Payload exposes the backend-defined compiled bytes for exactly two callers: the diagnostics dump and the size trace — documented as never-interpret. The unused _pixelSpirvCache is deleted. With this, a Metal or DX12 backend plugs in by implementing IGuestGpuBackend with its own codegen; nothing in the export layers knows which shader format exists. Verified by a clean solution build, the test suite, and a full ShaderDump conformance run under the pinned SDK. * [Gpu] Fix rename collateral from the seam extraction Address review findings: a doc comment picked up the mechanical VulkanVideoPresenter -> GuestGpu.Current rewrite and ended up naming members that do not exist on the interface, and CreateVulkanIndexBuffer kept its Vulkan prefix while every sibling factory was de-Vulkanized — it produces the neutral GuestIndexBuffer, so it is CreateGuestIndexBuffer. * [Gpu] Label diagnostics dumps with the backend's payload extension Address the review's altitude finding on DumpSpirv: the dump helper's IR-disassembly half is backend-neutral and stays put, but writing the opaque payload to a hardcoded .spv interpreted bytes the seam says never to interpret. IGuestCompiledShader now declares its payload's file extension, and the renamed DumpCompiledShader takes the handle and writes honestly-labeled dumps whichever backend produced them. * [Gpu] Make the shader-cache hit path allocation-free and lock-free Every translated draw built its cache key with a LINQ Select feeding string.Join plus one interpolated string per render target — steady per-draw allocation whether or not the shaders were already cached. The output layout is now packed exactly into a ulong (guest slot in 6 bits + output kind in 2 bits per target, host locations being the byte positions, target count in the key beside it), and the Gen5PixelOutputBinding array is only materialized on a cache miss, where compilation dwarfs it. The graphics/compute shader caches switch from Dictionary guarded by _submitTraceGate to ConcurrentDictionary, making the per-draw and per-dispatch hit paths lock-free and decoupling them from the tracing gate they coincidentally shared. And the seam-shaped render-target list is built once when a translated draw is created instead of a Select/ToArray per submission of a cached draw. * [Gpu] Replace LINQ with explicit loops in code this branch introduced Project rule going forward: no LINQ — it allocates enumerators, closures, and delegates, and this codebase is GC-pause-sensitive. The pixel-output and guest-render-target array builds and the ShaderDump store-PC collection become plain loops; pre-existing LINQ elsewhere is left for changes that already touch those lines. * [ShaderCompiler] Suppress CA2255 on the evaluator hook installer The analyzer coverage that arrived with the rebase flags ModuleInitializer in library code; this is the rule's intended advanced scenario — the hook must be installed before any code path can reach the evaluator, and every such path enters through this assembly — so suppress with that justification rather than weaken the guarantee to a static constructor's lazier timing. * [Gpu] Resolve rebase artifacts onto main Dedupe the System.Collections.Concurrent using in AgcExports that the rebase merge duplicated (main and this branch each added it), and regenerate the lock files for the new shader-compiler projects and SharpEmu.Libs against main's current package graph so --locked-mode restore matches at the branch tip. * [CI] Comment per-platform build artifact links on PRs Adds a workflow_run workflow that, after "Build and Release" finishes a pull-request build, posts (and keeps updated in place) a single PR comment linking the Windows, Linux, and macOS artifacts from that run. It runs via workflow_run rather than in the build workflow because PRs from forks build with a read-only token that cannot comment; the follow-on run executes in the base-repo context with write access and without checking out fork code. GitHub only triggers workflow_run from the default branch, so this takes effect once merged to main. |
||
|
|
fa2616d224 |
Linux and macOS support (#47)
* [macos/linux] Cross-platform host memory, TLS, and ABI layer for POSIX Introduces the foundation for running SharpEmu on macOS (osx-x64 under Rosetta 2) and Linux (linux-x64). The CPU backend executes guest x86-64 code natively, so these targets run the whole process as x86-64; this commit replaces the Windows-only host primitives with platform-dispatched equivalents so the guest boots and services HLE calls off Windows. Memory (HostMemory.cs, new): a Win32-semantics facade over mmap/mprotect/munmap with a shadow region table answering VirtualQuery. PhysicalVirtualMemory, DirectExecutionBackend, StubManager, and the two Kernel*CompatExports now go through it instead of kernel32 P/Invokes. Exact-address requests use MAP_FIXED_NOREPLACE (Linux) / guarded MAP_FIXED (macOS) so they match Win32 "map there or fail" semantics. TLS + host helpers (PosixHostStubs.cs, new): pthread-backed TLS and Win64-ABI-compatible stubs for the kernel32 helpers the backend embeds into emitted x86-64 code (TlsGetValue, QueryPerformanceCounter, SwitchToThread, Sleep). A Win64->SysV thunk wraps managed callbacks, since .NET on POSIX compiles them for the SysV ABI while the emitted call sites use Win64. Guest address layout: the 0x7FFx window is Windows-only (dyld shared cache / Rosetta runtime live there on POSIX), so stack/TLS/stub regions relocate to 0x6FFx off Windows. Vectored exception handling is gated off on POSIX for now (guest faults are not yet recovered) — the signal-based bridge is the next step. Also adds osx-x64 to the RID list and a Docker-based Linux smoke-test script. Status: on both macOS (Rosetta) and Linux (amd64), the guest now boots, runs native x86-64 code, and dispatches HLE imports. macOS stops at a Rosetta translation-cache issue; Linux runs ~252 imports through C++ static-init before hitting the missing fault handler (SIGSEGV). * [posix] Bridge the vectored exception handler to sigaction(SIGSEGV/SIGBUS/SIGILL) Guest faults on macOS/Linux previously terminated the process because the recovery logic in DirectExecutionBackend.Exceptions.cs was Windows-only. This adds a POSIX front-end that reuses the existing handler bodies: - DirectExecutionBackend.PosixSignals.cs installs SA_SIGINFO handlers via an [UnmanagedCallersOnly] entry, rebuilds the Win64 EXCEPTION_POINTERS / CONTEXT view from the platform mcontext (Darwin __ss thread state via the mcontext pointer at ucontext+48, Linux glibc gregs at ucontext+40 -- offsets verified against the headers on both platforms), runs the same chain as the VEH path (TryRecoverUnresolvedSentinel trap-sentinel recovery, TryHandleLazyCommittedPage demand paging, VectoredHandler diagnostics incl. FS/GS TLS-fault detection), and writes register changes back into the mcontext so sigreturn resumes the repaired guest. Unrecovered faults chain to the previously installed handler so the .NET runtime keeps mapping its own faults to managed exceptions. - The whole recovery path is warmed up with fabricated inputs before the handlers are installed. This is required under Rosetta 2: the signal trampoline cannot enter x86 code that has never been executed (and so never translated) -- a cold handler is silently never invoked and the faulting instruction retries forever (reproduced and verified in an isolated .NET test under Rosetta for Linux). It also keeps first-fault JIT work out of the signal frame. - Handlers run without SA_ONSTACK: the runtime's alternate stacks are too small for the diagnostic path, while guest (2MB) and host thread stacks match where Windows dispatches exceptions anyway. - The raw reads in the shared fault diagnostics (stack qwords, RBP walk, code bytes at RIP) now probe the region table on POSIX before touching memory, since a nested SIGSEGV inside the handler would kill the process before diagnostics finish. Windows keeps its try/catch reads. - Escape hatches: SHARPEMU_DISABLE_POSIX_SIGNALS=1 skips installation, SHARPEMU_DISABLE_RAW_HANDLER=1 disables sentinel recovery (parity with Windows), SHARPEMU_LOG_POSIX_SIGNALS=1 traces every delivery (first 16 and every 1024th are always traced). Verified with the test game: Linux (amd64 container) previously died with SIGSEGV right after import #252; it now recovers/diagnoses signals and the run proceeds to the real next blocker, an unpatched negative-offset guest TLS read (fault at TLS base - 0x1708), which gets the full NATIVE EXCEPTION dump before terminating. macOS is unchanged: the bridge installs and the game still stops at the known Rosetta translation-cache error at import 12, which is the next work item. * [posix] Fix guest memory layout faults: TLS prefix, exact mmap, map search base Three fixes that take the test game from dying during libc init to running its full main loop on macOS and Linux: - Static TLS blocks live below the TCB (FreeBSD amd64 variant II) and libc.prx reaches past -0x1700, but only a 4KB prefix was mapped below the TLS base. The prefix is now 64KB on POSIX (Windows keeps 4KB); the fault was a read at TLS base - 0x1708 during libc init. - HostMemory exact allocation on macOS used MAP_FIXED, which silently maps over untracked host memory. The direct-memory allocator's address scan walked into the .NET runtime's JIT heap and replaced live code, which under Rosetta 2 surfaced as "no code fragment associated with the given arm pc". Exact placement now passes the address as a hint and fails on relocation, like MAP_FIXED_NOREPLACE does on Linux. - sceKernelMapDirectMemory/MapFlexibleMemory searched for free space starting at 4GB, which is the Mach-O image base on macOS. The default search base is 0x20_0000_0000 on POSIX, and TryAllocateAtOrAbove now asks the kernel for a placement instead of page-stepping through host- owned address space (Rosetta ignores mmap hints for whole VA windows), over-allocating when the caller needs more than page alignment. Windows behavior is unchanged; all divergences are platform-guarded. * [macos] Video presenter on the main thread, MoltenVK support, window keyboard input Gets the test game from a headless loop to a playable window on macOS: - AppKit traps with SIGILL ("NSUpdateCycleInitialize() is called off the main thread") when GLFW runs on a worker thread. The CLI now moves emulation onto a worker thread on macOS and parks the real main thread in HostMainThread.Pump(); the presenter posts its whole window loop there instead of spawning a thread, and a shutdown handler asks the render loop to close the window so the pump unwinds on guest exit. - MoltenVK: enable VK_KHR_portability_enumeration (+ the portability instance flag) and VK_KHR_portability_subset when advertised, and gate robustBufferAccess2 on the device actually supporting it (Metal does not; the old code keyed it off robustImageAccess2 and vkCreateDevice failed with ErrorFeatureNotPresent). - Input: pad exports polled user32 GetAsyncKeyState, so POSIX hosts threw DllNotFoundException per scePadReadState call. The presenter now attaches the window's keyboard via Silk.NET.Input into HostWindowInput, and the pad exports map the existing VK-code layout onto it off Windows. Headless hosts (Linux containers) report a disconnected keyboard and fall back to neutral pad data silently. GLFW needs an x86-64 Vulkan loader under Rosetta: place a universal libMoltenVK.dylib next to SharpEmu named libvulkan.1.dylib (Homebrew's arm64-only copy cannot load into the x86-64 process) and export DYLD_LIBRARY_PATH to that directory. Verified: Dreaming Sarah boots to a MoltenVK-backed 2560x1440 window on macOS (Apple M4, Rosetta 2), renders the intro, title, and menus, and keyboard input drives it into gameplay. Linux (amd64 container) runs the same build headless through millions of imports with no faults. Windows paths unchanged; arm64 and x64 builds clean. * [posix] CoreAudio playback, self-contained MoltenVK loading, input/log polish - Audio: sceAudioOut ports now play through an AudioQueue backend on macOS (stereo PCM16 with the same 32KB backpressure pacing as the WinMM path). The WinMM port and the new CoreAudio port share an IHostAudioPort interface and sample converter; hosts without a backend (Linux containers) keep the silent fallback. - MoltenVK: GLFW resolves Vulkan with dlopen("libvulkan.1.dylib"), which cannot see the app-local universal MoltenVK build, so the presenter now feeds vkGetInstanceProcAddr straight into glfwInitVulkanLoader (GLFW 3.4) before creating the window. No DYLD_LIBRARY_PATH needed; the CLI also preloads the dylib for Silk.NET and prints setup hints when it is missing. scripts/fetch-macos-moltenvk.sh stages the official universal dylib next to a build. - The virtual-range allocator's failure trace now names the address and length instead of "AllocateAt invocation threw". Investigated and documented (not port defects): the savedata transaction failure is identical on Linux and macOS (HLE argument-register mapping for sceSaveDataCreateTransactionResource), and the in-game tile speckling has no platform-specific code in its path - the one macOS-only delta is that MoltenVK lacks robustBufferAccess2, so out-of-bounds shader reads return garbage instead of zeros. Verified on macOS: window, audio backend, and keyboard input all come up with zero environment configuration; the game runs to gameplay. Linux headless run unchanged (silent audio, no faults). Windows paths untouched; arm64 and x64 builds clean. * [cpu] Preserve guest registers and flags across patched TLS accesses The TLS patch handler replaces guest `mov reg, fs:[...]` instructions, which preserve every other register and the flags - but the handler loaded the TLS index into ecx and called TlsGetValue (Win64: clobbers rcx/rdx/r8-r11) with `sub/add rsp` trashing the arithmetic flags. Guest code that keeps live values or comparison results across a TLS access computed garbage deterministically. The handler now saves rcx, rdx, r8-r11, and the flags around the call, keeping the same inner stack alignment. This applies to the load patches and both store-helper stubs, on every platform. Also in this change, from the rendering-artifact investigation: - The present blit picks linear filtering for any fractional scale (nearest only for integer upscales): a 3840x2160 guest frame blitted into a 2560x1440 swapchain with nearest silently dropped every third row/column. - ClampViewport no longer trims the guest viewport rectangle to the render target; trimming changed the guest's scale/offset and skewed texel addressing. Vulkan permits viewports beyond the framebuffer (the scissor confines rendering), so only spec bounds are enforced. - Env-gated diagnostics grown during the investigation: guest texture dumps (SHARPEMU_TEXTURE_DUMP_DIR), aliased guest-image readback dumps (SHARPEMU_TRACE_GUEST_IMAGES=alias), small-render-target write movies (SHARPEMU_TRACE_GUEST_WRITES=small), unattended input injection (SHARPEMU_AUTO_CROSS=secs,...), viewport nudging (SHARPEMU_VIEWPORT_EPSILON), chunked-draw toggle (SHARPEMU_DISABLE_CHUNKED_DRAWS), and rect-list/draw vertex traces. Known remaining issue (root cause narrowed, not yet fixed): the game's terrain texture pages are corrupted in guest memory before any GPU work - the mound's solid-fill 32x32 tiles decode to fully transparent texels and the grass page has deterministic gaps, byte-identical across runs. Ruled out: memcpy/memmove/memset/realloc HLE semantics, sampler wrap modes, texel-boundary rounding, chunked draws, viewport handling. Next step is auditing the Chowdren asset decode path (custom compressed images) against the emulator's import surface. * [linux] ALSA playback backend for sceAudioOut sceAudioOut ports on Linux now play through libasound instead of the silent fallback. The PCM device opens in blocking mode with ~170ms of device buffer (the time-equivalent of the 32KB queue the WinMM and CoreAudio ports keep), so snd_pcm_writei provides the same backpressure pacing without a managed queue. Underruns and suspend/resume go through snd_pcm_recover with one retry per submit; anything else drops the buffer rather than stalling the guest. The "default" device routes through PulseAudio/PipeWire on desktops and straight to hardware on bare ALSA; SHARPEMU_ALSA_DEVICE overrides it (the null device makes the path testable in containers). A missing libasound or device fails port creation and lands in the existing silent fallback. Verified in an amd64 container: the test game opens the port (backend=alsa, 48kHz stereo float32) and streams sceAudioOutOutput through the null device for a full run; without a usable device the port logs a warning and falls back to silent. Playback on real Linux audio hardware has not been tested. * [fixes] Address review feedback: commit bounds, CoreAudio shutdown, dump errors - HostMemory: a MEM_COMMIT that runs past its reservation now fails like Win32 instead of committing a prefix and reporting success. All current callers already clamp their ranges to the region, so this only guards future callers. - CoreAudioPort: Dispose wakes a submitter waiting on backpressure and the wait treats ObjectDisposedException as a timed-out wait, so closing a port during playback can no longer throw. A failed AudioQueueStart tears the queue down and fails fast instead of leaving an undrainable queue that stalls every later submit on its timeout. - AgcExports: texture dumping catches all write failures (bad path, permissions), logging a warning instead of crashing when SHARPEMU_TEXTURE_DUMP_DIR points somewhere unusable. Verified with the Linux container run: game boots and streams audio with the stricter commit check, and a dump dir under /proc produces warnings instead of taking the process down. * [ci] Build linux-x64 and osx-x64 archives Adds a build-posix matrix job (ubuntu-latest / macos-latest) mirroring the Windows build: locked restore, Release build, self-contained CLI publish, and a tar.gz artifact per RID (tar keeps the executable bit). The macOS archive also stages the universal MoltenVK dylib via scripts/fetch-macos-moltenvk.sh so the artifact runs without any manual Vulkan setup. The release job still only ships the Windows archive. * [cli] Keep POSIX glfw natives outside the single-file bundle The KeepGlfwOutsideSingleFile target only matched filenames starting with 'glfw', which covers Windows (glfw3.dll) but not libglfw.3.dylib / libglfw.so.3. Those got embedded into the single-file bundle, and Silk.NET's library loader does not probe the bundle extraction directory, so a published build died with "Couldn't find a suitable window platform" (and the glfwInitVulkanLoader wiring, which loads the library from AppContext.BaseDirectory, could not run either). Keeping the POSIX names loose next to the executable fixes both, the same way the Windows build already handled it. Found by running the CI-built osx-x64 archive: video failed while local loose-file builds worked. With the fix the published single-file build opens the MoltenVK window, wires the loader, and reaches gameplay. * [ci] Publish linux-x64 and osx-x64 release archives The build-posix artifacts now ship as per-RID GitHub releases on main pushes and manual dispatches, tagged the same way as the win64 ones (<rid>-<ref>-<sha>). Archives stay tar.gz so the executable bit survives extraction. * [cli] Fail early on non-x86-64 host processes The CPU backend executes guest x86-64 code natively, so the process must be x86-64 (win-x64/linux-x64 on x64 hardware, osx-x64 under Rosetta 2 on Apple Silicon). An arm64 process previously failed deep inside emulation startup, indistinguishable from MoltenVK, signal handler, or guest memory problems. CLI mode now checks the process architecture up front and exits with a message naming the supported execution model (and the Rosetta install command on macOS). The GUI-only path stays usable on arm64. * [video] Log the selected Vulkan device name and API version The presenter never named the GPU it picked, so a 'no video' report could not be told apart from a real windowing failure without guessing. It now logs the device name, type, and API version right after selection. A software rasterizer (llvmpipe/lavapipe/SwiftShader) shows up here and typically lacks the device features the translated shaders need, which is the likely cause when a window opens and presents frames but nothing draws. * [video] Steer GLFW to XWayland on Wayland sessions GLFW's native Wayland backend does not reliably map the Vulkan window with some drivers (NVIDIA in particular): frames present but the window never becomes visible, so the game runs with audio and no picture. A report on an RTX 5080 showed exactly this — all device features present, frames presenting, but the log had 'libdecor-gtk.so failed to init' and a 1.4x-scaled window, both Wayland tells. On a Wayland session that also exposes an X server (DISPLAY set), the presenter now clears WAYLAND_DISPLAY for its own process before GLFW initializes, so GLFW selects its dependable X11/XWayland backend. SHARPEMU_ENABLE_WAYLAND=1 opts back into native Wayland. Headless (no DISPLAY) and non-Linux hosts are unaffected. * [video] Force GLFW X11 backend via the platform init hint, log the platform The previous attempt cleared WAYLAND_DISPLAY to steer GLFW off Wayland, but a reporter still hit the native-Wayland path (the Wayland-only libdecor error persisted), so that env trick doesn't switch GLFW. Use GLFW's supported mechanism instead: glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_X11) before GLFW initializes, called into the same libglfw GLFW itself loads (the pattern InitializeMacVulkanLoader already uses). Still gated on a Wayland session with an X server present (DISPLAY set) so we never force X11 where XWayland can't catch it, and still overridable with SHARPEMU_ENABLE_WAYLAND=1. Also logs 'GLFW windowing platform in use: <backend>' after init via glfwGetPlatform, so a 'no window' report shows X11 vs Wayland outright. Verified on macOS: the readback correctly reports Cocoa and the presenter is unaffected (the fix is a no-op off Linux). * [video] Run the GLFW window on the main thread on Linux too GLFW requires window creation and event processing on the process main thread on every platform: initialization, window creation, and glfwPollEvents are main-thread-only, and X11 in particular has a single event queue that must be serviced there. A window created and polled on another thread may never map — which is why the game ran (audio, imports, even Vulkan present) with no visible window on Linux. macOS already routed the window loop to the main-thread pump (AppKit needs it); Windows is fine because it has a per-thread event queue. Linux was the gap: it spawned a background thread for the presenter. Extend the existing HostMainThread pattern to Linux — emulation runs on a worker, the main thread pumps the window work the presenter posts. Refs GLFW intro guide (thread-safety): init, window creation, and event processing are restricted to the main thread. Verified: macOS still boots to its window unchanged; the Linux headless container runs to millions of imports with no deadlock or regression. On-screen confirmation on a real Linux desktop is still pending, but this is the documented root cause for a windowless-but-running Linux session. * [posix] Skip Win32 native guest workers * [vulkan] Synchronize offscreen targets before present * [vulkan] Transition fresh textures from undefined layout * [vulkan] Report swapchain pixels before source readback * [vulkan] Emit requested guest image diagnostics * [agc] Diagnose guest texture fallbacks * [linux] Keep guest GPU mappings in low address space * [video] Reduce diagnostic stalls and drain complete frames * [memory] Harden packed GPU address handling * [readme] Document Linux and macOS release support * [posix] Integrate the host platform abstraction * [posix] Restore guest thread address window * [video] Run the performance HUD on POSIX hosts The FPS/CPU/work HUD bailed out unless the host was Windows; only the per-thread hottest-thread scan actually needs Windows APIs. Keep that scan Windows-only (POSIX reports 'idle') and let the rest of the HUD run everywhere — the title is already set from the render thread, which owns the window on macOS and Linux. * [posix] Implement native guest worker threads Guest entry stubs must not run above CLR-managed frames on CLR-created threads (see the NativeWorker preamble); the PR previously fell back to the inline calli path on POSIX, which reproduced the documented 'attempted to call a UnmanagedCallersOnly method from managed code' fail-fast (observed after Dreaming Sarah's menu select) and left the runtime's suspension machinery walking guest frames. Provide the missing POSIX half of the worker loop: - PosixHostStubs grows Win64-convention WaitForSingleObject/SetEvent/ ExitThread stubs backed by dispatch semaphores (macOS) / unnamed POSIX semaphores (Linux) plus pthread_exit, with EINTR retry in the wait. - Worker events are creatable/signalable/waitable from managed code too, so NativeGuestExecutor.Run keeps its handshake (AutoResetEvent stays on Windows byte-for-byte). - PosixHostThreading implements CreateNativeThread/WaitForThreadExit/ CloseThreadHandle over pthreads (liveness probed with pthread_kill(0), then joined). - RunPrologue/RunEpilogue are routed through the existing Win64->SysV thunks, so the emitted loop stays identical across platforms. * [macos] Disable concurrent GC under Rosetta's write-watch hazard Background GC's write-watch revisit (SoftwareWriteWatch::GetDirty -> FlushProcessWriteBuffers) calls thread_get_register_pointer_values on every thread; under Rosetta 2 that Mach call stalls indefinitely on threads executing translated guest code. The background mark phase then never finishes and every allocating or Monitor-taking thread wedges behind it — observed as Dreaming Sarah freezing at the menu/loading screen with FPS 0 in 5 of 7 runs, dispatcher/watchdog parked in Monitor.Enter and all BGC threads waiting in t_join. Non-concurrent GC never takes that path; a 5-minute soak now holds 22-31 fps in-game with zero stalls. Windows and Linux keep concurrent GC. * [diag] Periodic guest-thread snapshots with gate-owner tracking SHARPEMU_PERIODIC_SNAPSHOT_SECONDS=N dumps the stall snapshot every N seconds even while imports are progressing, for soft stalls where the game stops advancing but threads keep spinning. The periodic dump never touches the guest-thread gate (it must keep reporting when the gate is what's wedged): it reads a lock-free owner record — every gate acquisition now goes through LockGate(site), which notes site/thread — and walks the thread table without the lock, tolerating torn reads. SHARPEMU_PERIODIC_SNAPSHOT_FILE redirects the dump to a side file for the case where the console itself is wedged (frozen log mirror was one of the observed failure modes). * [nuget] Add osx-x64 RID targets to lock files * [cpu] Back off the guest join poll TryJoinThread polled the host thread at a fixed 1ms; a game main thread joining a long-lived worker (Dreaming Sarah parks there for the whole session) burned ~5% of managed CPU in Join/Sleep syscalls. Ramp the poll interval to 10ms once the join is clearly long-lived — exit detection latency for long joins moves from ~1ms to at most 10ms, and short-lived joins still resolve on the first 1ms polls. * [nuget] Add linux-x64/win-x64 RID targets to lock files * [posix] Keep guest stacks clear of the import-stub descent The import-stub region descends from 0x7000_0000_0000 on the same 16MB grid as the guest thread windows; moving stacks to 0x6FFF_E000_0000 put them inside the stub region's 64-module descent range (floor 0x6FFF_C000_0000), silently consuming the top ~32 stack slots on hosts with many loaded modules. Drop the POSIX stack base to 0x6FFF_A000_0000: 512MB below the stub floor, still 2.5GB above the TLS window. Windows keeps 0x7FFF_E000_0000 (its bands are ~15TB apart). * [pad] Read window gamepads on POSIX hosts XInput and the DualSense hid reader are Windows-only, which left macOS/Linux with keyboard input only. The presenter's Silk/GLFW input context already enumerates gamepads on both platforms, so track their state in HostWindowInput (event-driven on the window thread, snapshot guarded like the key set) translated to ORBIS conventions: GLFW's Xbox layout maps A/B/X/Y to Cross/Circle/Square/Triangle, sticks bias from -1..1 to 0..255 with Y growing down, and triggers rescale from GLFW's -1..1 resting-at--1 range with digital L2/R2 bits past 25%. The merge into ReadHostInputState is gated to non-Windows so a physical pad is never sampled twice through both a native reader and GLFW. Hotplug is handled via ConnectionChanged; with no pad connected the path is inert. Untested against a physical controller (none attached to the dev host); axis conventions follow the GLFW gamepad-mapping contract. * [nuget] Refresh lock files after cross-RID restores * [posix] Adopt the host audio/input seams from main Main's #192 abstracted audio output and pad/keyboard input behind IHostAudioOutput/IHostInput; re-express the POSIX backends behind them: - CoreAudioPort/AlsaAudioPort move to Host/Posix as PosixCoreAudioStream/PosixAlsaAudioStream implementing IHostAudioStream. The seam converts to stereo PCM16 before Submit, so the ports' own conversion (and IHostAudioPort/AudioSampleConverter) is gone; queueing and backpressure are unchanged. - PosixHostAudio selects CoreAudio (macOS) / ALSA (Linux) as the platform's IHostAudioOutput. - PosixHostInput implements IHostInput over an IPosixWindowInputSource that HostWindowInput registers when the presenter attaches the window's GLFW input context: keyboard with virtual-key translation, the window gamepad snapshot (now in seam HostGamepadState/HostGamepadButtons terms), and keyboard-connected as the focus signal. Rumble/lightbar no-op (GLFW has no such API). - PadExports drops its direct HostWindowInput gamepad merge — pads now flow through IHostInput.GetGamepadStates like every platform. - PosixHostThreading.RequestTimerResolution is a documented no-op. All three RIDs build; SharpEmu.Libs.Tests pass (26/26). * [nuget] Regenerate GUI lock file for RID-less locked restore Local cross-RID builds stamped a win-x64 runtimes section into SharpEmu.GUI's lock file; the project declares no RuntimeIdentifiers, so CI's 'dotnet restore --locked-mode' failed with NU1004 on every platform. Regenerated via a plain solution restore (--force-evaluate), matching what the workflow validates. |
||
|
|
081760be3f |
[AGC/Vulkan] Support multiple render targets (#149)
* [AGC] Support multiple typed pixel outputs Emit dense float, uint, and sint fragment outputs for sparse guest MRT slots. Preserve disabled components across partial exports, validate dense host locations, and retain the single-output compiler overload for compatibility. * [Vulkan] Execute translated draws with multiple color attachments Carry every active color target and its effective shader/register write mask through one Vulkan draw. Add per-attachment blending, independentBlend negotiation, device/format validation, multi-attachment synchronization, and safe image recreation after in-flight work completes. * [ShaderDump] Add MRT edge-case coverage Cover sparse mixed-type outputs, partial exports, merged partial exports, independent blend layouts, eight attachments, and invalid host locations. Run the synthetic shader suite in CI. --------- Co-authored-by: Dafenx <196083014+Dafenxz0@users.noreply.github.com> |
||
|
|
caf859cc52 |
Fix guest shutdown when VideoOut window is closed (#184)
Propagate Silk window close to runtime teardown so audio and CPU workers stop instead of continuing after the presentation window is dismissed. |
||
|
|
d8397b022e |
Performance Improvements and Optimization Tweaks (#156)
* Improve Gen5 rendering performance and compatibility * Pin .NET SDK for locked restore --------- Co-authored-by: Spooks4576 <Spooks4576@users.noreply.github.com> |
||
|
|
d43edc865a |
Agent/fix gen5 thread agc compat (#130)
* Fix Gen5 thread and AGC compatibility * Trim compatibility comments * Report selected Vulkan GPU * Clean up CPU title label * Improve emulator frame pacing and performance * Regenerate package locks with pinned SDK --------- Co-authored-by: Spooks4576 <Spooks4576@users.noreply.github.com> |
||
|
|
4600a2ed1f | Display game icon (icon0.png) in window title bar (#124) | ||
|
|
298ef01809 |
[VideoOut] Prefer NVIDIA/discrete GPUs over integrated (#97)
SelectPhysicalDevice took the first device exposing a graphics+present queue. On hybrid-graphics laptops that is the integrated GPU, so the discrete card went unused - and AMD's integrated driver access-violates inside vkCreateGraphicsPipelines while compiling some translated guest shaders, killing the process. The CLR surfaced that native AV as "Invalid Program: attempted to call a UnmanagedCallersOnly method from managed code", which made it look like a CPU/threading fault. Score the candidates instead: NVIDIA parts win, other discrete GPUs come next, and an integrated GPU is only chosen when nothing else can present. SHARPEMU_VK_DEVICE=<substring> pins a specific adapter, and the selected device is logged. |
||
|
|
e1cf5b13ef |
[AGC] Quake rendering progress: WAIT_REG_MEM, draw fixes, VideoOut, and HLE improvements (#68)
* [agc] WAIT_REG_MEM suspend/resume, draw packet fixes, new HLE exports, debug cleanup
Rebased onto upstream
|
||
|
|
70ec2928ea | [revert] Revert VulkanVideoPresenter.cs to previous version, added new screenshot, and updated packages.lock.json | ||
|
|
c618c116ba | [shader-decoder] Fix address calculation for SW linear textures (#45) | ||
|
|
9b9ca8f707 | [loader] cut import overhead (#32) | ||
|
|
db20387502 | [shader-decoder-part1-hotfix] New format support, maintenance8 support, robustness improvements, and bug fixes. This commit includes updates to the AGC exports, Gen5 SPIR-V translator, and Vulkan video presenter to enhance compatibility and performance. (#31) | ||
|
|
4b5b27e686 |
[vulkan] enable required PhysicalDeviceFeatures for translated shaders (#29)
- 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. |
||
|
|
2a784aa405 | [gpu-hotfix1] Cache improvements have been made (6x performance gain) (#18) | ||
|
|
52e17b5056 |
[shader-decoder-part1] Implemented a shader decoder (Part 1) (#12)
* [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. |
||
|
|
873f473b65 | [video] hide splash | ||
|
|
9a1a3789ef | [video] cap presenter ticks | ||
|
|
5fcc8eaa37 | [saveData] add dir search | ||
|
|
4ae778ef39 | [libs] Update system and video exports | ||
|
|
464422f23e | [video] Add Vulkan presentation | ||
|
|
5d204afd10 | [videoOut] add minimal Vulkan swapchain presenter |