Every import reads its stack arguments through a region query, which on
POSIX takes the global region lock and scans the view regions. With many
guest threads this was the most contended lock in the process (about 36k
contentions per second in Poppy Playtime) and HLE calls averaged ~59 us.
Keep the last readable range per thread for the import path and reuse it
until any POSIX mapping or protection changes. The signal handlers keep the
uncached query, since they must not touch thread-static storage.
* refactor(videoout): isolate host buffer code
Move pooled host-visible Vulkan buffer management into a dedicated presenter partial.
The new location makes ownership clear.
Execution behavior does not change.
* refactor(videoout): isolate draw state code
Move guest draw-state conversion into a dedicated presenter partial.
This change only improves code organization.
Keep runtime behavior unchanged.
* refactor(videoout): isolate texture format support code
Move Vulkan image-format capability and render-target mapping into the texture-format presenter partial.
This move changes code ownership only.
Runtime behavior stays the same.
* refactor(videoout): isolate presentation image code
Move presentation-target selection and offscreen presentation-image creation into a dedicated presenter partial.
The new location makes ownership clear.
Execution behavior does not change.
* refactor(videoout): isolate HDR presentation code
Move HDR presentation resources, pipelines, and command recording into a dedicated presenter partial.
This change only improves code organization.
Keep runtime behavior unchanged.
* refactor(videoout): isolate draw execution code
Move offscreen draw, clear, guest-image write, and render-pass execution into a dedicated presenter partial.
This move changes code ownership only.
Runtime behavior stays the same.
* refactor(videoout): isolate guest submission code
Move guest GPU batching, submission, retirement, and visibility waits into a dedicated presenter partial.
The new location makes ownership clear.
Execution behavior does not change.
* refactor(videoout): isolate render loop code
Move presenter work waiting, queue draining, frame acquisition, and work dispatch into a dedicated partial.
This change only improves code organization.
Keep runtime behavior unchanged.
* refactor(videoout): isolate draw recording code
Move translated draw recording, image transitions, draw tracing, and resource retirement into a dedicated presenter partial.
This move changes code ownership only.
Runtime behavior stays the same.
* refactor(videoout): isolate guest work queue code
Move guest GPU work submission, scheduling, backpressure, and completion into a dedicated partial.
The new location makes ownership clear.
Execution behavior does not change.
* refactor(videoout): place storage image contracts code with its owner
Move SPIR-V storage image contract parsing and validation into the compute storage-image partial.
This change only improves code organization.
Keep runtime behavior unchanged.
* refactor(videoout): place ordered guest flips code with its owner
Move ordered guest flip capture and completion into the presentation-frame partial.
This move changes code ownership only.
Runtime behavior stays the same.
* refactor(videoout): place frame lifetime code with its owner
Move presentation frame waits and flip-version retirement into the presentation-frame partial.
The new location makes ownership clear.
Execution behavior does not change.
* refactor(videoout): place texture cache resolution code with its owner
Move cached texture resolution and CPU refresh into the texture-cache partial.
This change only improves code organization.
Keep runtime behavior unchanged.
* refactor(videoout): place barycentric pipeline code with its owner
Move the fullscreen barycentric shaders and pipeline creation into the pipeline partial.
This move changes code ownership only.
Runtime behavior stays the same.
* refactor(videoout): place swapchain draw resources code with its owner
Move presentation render-pass, image-view, and framebuffer setup into the swapchain partial.
The new location makes ownership clear.
Execution behavior does not change.
* refactor(videoout): place feedback snapshot creation code with its owner
Move color feedback snapshot creation beside its pool lifecycle and telemetry.
This change only improves code organization.
Keep runtime behavior unchanged.
* refactor(videoout): place texture format conversion code with its owner
Move real-format conversion and its transfer scratch images into the texture-format partial.
This move changes code ownership only.
Runtime behavior stays the same.
* refactor(videoout): place guest image diagnostics code with its owner
Move guest image tracing and readback diagnostics beside the guest image registry.
The new location makes ownership clear.
Execution behavior does not change.
* refactor(videoout): place guest submission execution code with its owner
Move ordered actions, cache operations, pooled-data returns, and guest-work descriptions beside guest submission lifetime.
This change only improves code organization.
Keep runtime behavior unchanged.
* refactor(agc): isolate initialization exports code
Move AGC initialization and versioned register-default materialization into a focused partial.
This move changes code ownership only.
Runtime behavior stays the same.
* refactor(agc): isolate driver resource exports code
Move AGC driver resource-registration exports and their private machinery into a focused partial.
The new location makes ownership clear.
Execution behavior does not change.
* refactor(agc): isolate event exports code
Move AGC event signaling exports and their private machinery into a focused partial.
This change only improves code organization.
Keep runtime behavior unchanged.
* refactor(agc): isolate shader state exports code
Move AGC shader-pipeline state exports and their private machinery into a focused partial.
This move changes code ownership only.
Runtime behavior stays the same.
* refactor(agc): isolate packet patching exports code
Move AGC command-packet patching exports and their private machinery into a focused partial.
The new location makes ownership clear.
Execution behavior does not change.
* refactor(agc): isolate control flow exports code
Move AGC command-buffer control-flow exports into a focused partial.
This change only improves code organization.
Keep runtime behavior unchanged.
* refactor(agc): isolate register packet exports code
Move AGC register-programming packet exports and their private machinery into a focused partial.
This move changes code ownership only.
Runtime behavior stays the same.
* refactor(agc): isolate draw packet exports code
Move AGC draw-command packet exports and their private machinery into a focused partial.
The new location makes ownership clear.
Execution behavior does not change.
* refactor(agc): isolate DMA packet exports code
Move AGC DMA packet exports into a focused partial.
This change only improves code organization.
Keep runtime behavior unchanged.
* refactor(agc): isolate compute fast paths code
Move CPU semantic replacements for recognized compute kernels into a focused partial.
This move changes code ownership only.
Runtime behavior stays the same.
* refactor(agc): isolate compute dispatch code
Move translated compute dispatch handling into a focused partial.
The new location makes ownership clear.
Execution behavior does not change.
* refactor(agc): isolate draw translation code
Move translated guest draw construction into a focused partial.
This change only improves code organization.
Keep runtime behavior unchanged.
* refactor(agc): isolate draw state code
Move AGC render-state decoding into a focused partial.
This move changes code ownership only.
Runtime behavior stays the same.
* refactor(agc): isolate submitted geometry code
Move submitted index and vertex retention into a focused partial.
The new location makes ownership clear.
Execution behavior does not change.
* refactor(agc): isolate texture transport code
Move guest texture transport into a focused partial.
This change only improves code organization.
Keep runtime behavior unchanged.
* refactor(agc): isolate PM4 decoding code
Move submitted PM4 stream decoding into a focused partial.
This move changes code ownership only.
Runtime behavior stays the same.
* refactor(agc): isolate GPU wait lifecycle code
Move submitted GPU wait suspension and resumption into a focused partial.
The new location makes ownership clear.
Execution behavior does not change.
* refactor(agc): isolate orphan preamble recovery code
Move orphan-preamble recovery into a focused partial.
This change only improves code organization.
Keep runtime behavior unchanged.
* refactor(agc): isolate submission runtime code
Move submitted command execution into a focused partial.
This move changes code ownership only.
Runtime behavior stays the same.
* refactor(agc): isolate draw diagnostics code
Move translated-draw diagnostics into a focused partial.
The new location makes ownership clear.
Execution behavior does not change.
* refactor(agc): isolate command packet code
Move general command-buffer packet builders into a focused partial.
This change only improves code organization.
Keep runtime behavior unchanged.
* refactor(agc): place multi-DCB export in submissions
Place the multi-DCB submission handler beside the queue parser and submission lifecycle.
This move changes code ownership only.
Runtime behavior stays the same.
* refactor(agc): place driver configuration exports with its owner
Place tessellation driver configuration handlers beside the other driver resources.
The new location makes ownership clear.
Execution behavior does not change.
* refactor(agc): place software present path in events
Place software presentation beside the AGC flip and event handlers.
This change only improves code organization.
Keep runtime behavior unchanged.
* refactor(agc): place color-control decode in draw state
Place the CB color-mode and hardware-resolve helpers with the other draw-state code.
This move changes code ownership only.
Runtime behavior stays the same.
* refactor(agc): place translated draw buffers in draw translation
Place the translated draw buffer builders with the draw translation pipeline.
The new location makes ownership clear.
Execution behavior does not change.
* refactor(agc): place wait packet helpers in command packets
Place WAIT_REG_MEM encoders and command-packet trace counters with their only consumers.
This change only improves code organization.
Keep runtime behavior unchanged.
* refactor(agc): place draw translation helpers with its owner
Place pixel-input translation helpers and their trace state with the draw translation pipeline.
This move changes code ownership only.
Runtime behavior stays the same.
* refactor(agc): place frame packet trace setting in pm4
Place the frame-packet trace setting with its PM4 consumers.
The new location makes ownership clear.
Execution behavior does not change.
* refactor(agc): place guest memory transfer helpers in submissions
Place guest memory copy and fill helpers with their submitted-command consumers.
This change only improves code organization.
Keep runtime behavior unchanged.
* refactor(agc): place packet identity helper in packet patching
Place packet identity decoding with its packet-patching consumers.
This move changes code ownership only.
Runtime behavior stays the same.
* refactor(agc): place duplicate target trace state in draw state
Place the duplicate-target trace counter with its draw-state consumer.
The new location makes ownership clear.
Execution behavior does not change.
* style(renderer): remove extra spacing from split files
Remove excess blank lines left by the AGC and Vulkan partial extractions.
This cleanup changes formatting only.
Runtime behavior stays the same.
* refactor(agc): keep rebased state in the split renderer
Keep color-metadata state with draw translation after the file split. Restore the complete PM4 helper set. Retain frame publication and metadata tracking that arrived during the rebase.
* fix(gpu): keep acquire memory cache ranges
Keep acquire memory operations separate when their ranges or cache semantics differ.
Merge only matching operations that overlap or touch.
Submit the exact operations as one backend work item to limit queue growth without widening invalidation ranges.
Add focused tests for the changed behavior.
* fix(vulkan): scope guest cache barriers to tracked resources
Use exact buffer and depth-image ranges for ranged guest cache operations. Use a global barrier when the range or image layout is unknown, when no resource matches, or when the operation covers all memory. Record cached texture spans and test each fallback.
* fix(cpu): handle guest image write faults in native code
Keep tracked-page write faults inside the Windows VEH path.
Restore page access, queue dirty pages, and defer managed tracker work until safe execution.
This prevents CLR fail-fast crashes and avoids full tracked-page scans.
Add focused tests for the changed behavior.
* fix(agc): track constant fills as managed writes
Call the managed-writer tracker after the constant-fill fast path writes guest memory. Do not protect a range that the managed memory layer already reports. This prevents an immediate write fault on the same pages.
* fix(cpu): make exception memory reads safe
Probe diagnostic addresses before reading them.
Use ReadProcessMemory for unstable data and keep direct reads only for executable bytes that are active during dispatch.
This prevents the crash reporter from causing a second access violation while it reports a guest fault.
Add focused tests for the changed behavior.
* fix(loader): protect the guest red zone on Windows
Patch faultable memory instructions in System V red-zone functions to run through nearby trampolines.
The trampoline moves RSP while Windows handles a write fault, so the handler cannot overwrite live guest values below the stack pointer.
Add focused tests for the changed behavior.
* fix(audio): correct AJM job argument and size handling
Read the gapless result pointer from the fifth ABI argument and keep reset as the fourth argument.
Use the split-job base size before adding buffer descriptors.
This keeps batch cursors and result writes aligned with AJM.
Add focused tests for the changed behavior.
* fix(vulkan): use all attachments for framebuffer identity
Clamp the framebuffer extent to every color and depth attachment.
Include the color format and view in the depth-framebuffer cache key.
This prevents invalid reuse when one guest image changes attachment views or formats.
Add focused tests for the changed behavior.
* fix(videoout): align captures with complete guest frames
Start a capture at a guest-frame boundary and keep it active across presenter ticks.
End the capture after the next guest flip completes.
Discard interrupted or timed-out captures so later requests can continue.
* fix(shader): keep forward branches after program end markers
Allow a forward scalar branch to target reachable code after S_ENDPGM.
Preserve instruction boundaries and reaching definitions across the program-end marker.
Add a regression test for this control-flow form.
* fix(shader): apply fragment export validity
Apply the EXP.VM flag when a fragment export is conditionally valid.
Suppress invalid color and depth exports in both shader backends.
Add translation and output-mask tests.
* fix(vulkan): declare graphics subgroup operations
Enable subgroup capabilities only for graphics modules that use subgroup instructions.
Declare the required SPIR-V capabilities and execution modes.
Add interface validation tests for vertex and fragment stages.
* fix(vulkan): use flat fragment subgroup inputs
Decorate integer fragment subgroup built-ins with Flat so generated SPIR-V satisfies Vulkan interface validation.
Add focused tests for the changed behavior.
* fix(storage): return usable storage capacity
Add the temporary-data capacity export and saved-data search alias, then report total and free blocks using the platform ABI.
Add focused tests for the changed behavior.
* fix(videoout): send capture requests to guest-frame control
Send the capture hotkey request to the guest-frame capture state machine.
Do not start a host-present capture directly from the window event.
This keeps one request aligned with one complete guest frame.
* fix(videoout): apply metadata-backed image clear patterns
Track metadata fills and constant-buffer fills with their full 16-byte pattern and physical image size.
Decode clear values by target format, including repeated half-float texels.
Apply pending clears when the guest image becomes available.
Add tests for tiled allocation sizes, metadata state, and clear patterns.
* chore(videoout): trace selected image synchronization paths
Add address-filtered traces for compute destinations, guest-image overlaps, and sampled-image binds.
Keep the traces off unless the related environment option is set.
Use the output to compare image synchronization without broad logging.
* fix(vulkan): require a compatible wave size for graphics subgroups
Enable graphics subgroup lowering only when the device reports a compatible native wave size.
Pass the selected policy into shader translation and shader cache keys.
Add policy and interface tests.
* fix(agc): preserve composite depth target extents
Decode attachment width and height from composite depth binding packets and carry them separately from independent context-register state.
Detach irreconcilably mismatched depth attachments instead of shrinking color passes, with focused coverage for packet parsing and fallback behavior.
* fix(cpu): preserve full-width guest callback results
Return the complete 64-bit value from direct and worker-backed guest calls instead of truncating it to 32 bits.
Add fourth-argument support for guest callbacks and cover both ABI behaviors in the native return smoke test.
* fix(shader): key translated programs by checksum
Include programmed shader checksums in decode and compiled-pipeline cache identities so replaced code at a reused guest address cannot resolve to stale translations.
Propagate checksums through compute, graphics, and submitted-geometry translation and cover address reuse with a regression test.
* fix(agc): skip rectangle draws without parameter exports
Track enabled shader parameter exports and reject only non-indexed rectangle draws that have no vertex inputs or parameter exports but still request interpolated pixel inputs.
Treat the rejection as intentional and cover the guarded and preserved draw shapes with focused tests.
* diagnostics(agc): trace video draw chains
Track decoded video planes through recent render-target dependencies and report texture payload summaries, generations, blend state, and viewport data for targeted analysis.
Keep the trace flag, rectangle-skip visibility, and flip-bounded diagnostic state together in this commit.
* fix(agc): snapshot rotating video buffers per draw
Recognize registered decoded-video buffer addresses independently of tracing and bypass address-only upload and texture-content cache shortcuts for those ranges.
This preserves the texels associated with queued draws when the decoder later reuses a rotating guest buffer.
* fix(video): queue decoded frames and honor seek state
Start video decoding with playback, buffer decoded frames on a bounded worker queue, and distinguish pending data from end of stream instead of blocking guest polling.
Preserve pause state across jumps, seek audio and video decoders to the requested timestamp, offset reported times, and deliver the completion warning through the event callback ABI.
* fix(video): load replacement-backed sources through callbacks
Read replacement-backed sources through the guest open, size, offset-read, and close callbacks, materializing a temporary host file for decoding.
Fall back to the ordinary resolved path when the optional replacement interface declines a source, and clean up owned temporary files when sources or players are released.
* fix(video): report decoded stream metadata
Preserve display aspect ratio, color range, primaries, transfer characteristics, frame pitch, and crop information when reporting decoded video streams and frames.
Use the stream's fallback frame rate when its average rate is unavailable, and cover the extended ABI field layout with focused tests.
* fix(video): report extended audio stream format
Populate channel count and sample rate in extended stream details so clients configure decoded PCM output correctly. Add ABI coverage for the audio union layout and duration.
* fix(shader): preserve full LDS single-address offsets
Combine both encoded offset bytes for single-address data-share operations while retaining independent scaled offsets for paired forms. Apply the correction to both shader backends and add decoder and generated-module regression coverage.
* fix(shader): preserve depth comparison filter semantics
Decode the sampler comparison function instead of assuming one operation, and evaluate linear LOD-zero depth filtering per texel before interpolation. Add focused generated-module coverage for comparison functions and the four-tap filtering path.
* fix(agc): create native interpolant mappings
Implement dbOlWdppb4o as sceAgcCreateInterpolantMapping2 and emit packed SPI_PS_INPUT_CNTL register pairs from matched shader semantics. Fill unused entries with identity mappings and cover identity, matched, default, flat, custom, and f16 modes.
* fix(agc): construct primitive state registers
Build context and user-config primitive state independently, merge optional hull-stage state, and select the correct output primitive source. Cover hull handling and derived versus shader-owned output primitives.
* fix(agc): emit native indirect register packets
Emit and parse native indirect context, shader, and user-config register packets. Patch native address and count fields without clobbering control bits, retain legacy packet compatibility, and apply flagged depth-size entries to the correct state.
* fix(agc,video): support guest depth-stencil state
Decode guest stencil attachment, clear, mask, reference, compare, and operation state. Create compatible Vulkan depth-stencil resources and preserve their aspects through render passes, pipeline caching, feedback copies, and barriers.
* chore(diagnostics): add focused guest graphics tracing
Add canonical draw-state summaries with optional descriptor detail filters. Improve guest instruction sampling with thread selection and per-window accounting, and trace register-default handoff provenance.
* fix(video): publish cache identity for depth aliases
Reuse the exact sampled-texture content identity when a depth-backed image resolves successfully. Publish its sampler and write generation so later submissions avoid redundant guest-memory snapshots that the presenter would discard.
* chore(diagnostics): profile guest thread execution
* chore(diagnostics): profile graphics command processing
* chore(diagnostics): profile texture preparation
* chore(diagnostics): profile shader evaluation
* chore(diagnostics): profile address synchronization
* chore(diagnostics): unify performance profiling switches
* fix(video): disable face culling for rectangle primitives
Keep expanded rectangle draws visible regardless of triangle winding. Preserve culling and all other raster settings for other primitive types.
Add regression coverage for each culling combination and unchanged non-rectangle raster state.
* fix(agc): keep depth clears separate from color targets
Remove the color-clear request triggered by the depth-clear control bit. Keep the existing depth, stencil, and color-metadata clear paths unchanged.
* fix(shader): honor pixel input counts and mapped locations
Read only the programmed pixel input controls and use identity mappings beyond that range. Share duplicate-location resolution between both shader backends.
Test input-count bounds, zero-input state, identity fallback, duplicate mappings, and location limits.
* chore(diagnostics): trace interpolant packet and draw mappings
Add opt-in packet fingerprints, register pairs, and consumed draw mappings through SHARPEMU_TRACE_AGC_INTERPOLANT_FLOW.
Limit packet output and unique draw records to 1024 entries. Stop packet scans after the trace limit and keep diagnostic state bounded.
* feat(memory): add GPU memory tracking foundations
Track mapped ranges and page access state.
Keep unresolved faults on the existing error path.
Report memory counters once when shutdown starts.
* feat(memory): map direct memory through shared backing
Create portable host views over a persistent guest backing object.
Route direct and flexible mappings, protection, queries, unmaps, and aliases through one owner.
Preserve private-memory behavior and cover lifecycle, overlap, and failure paths.
* feat(gpu): schedule submissions with timeline completion
Route graphics and compute work through one queue and scheduler. Replace per-submit fences with timeline ticks and preserve batch accounting on every submission path.
Add synchronous worker relay, ordered completion callbacks, and shutdown tests. Keep optional video frame polling nonblocking to prevent a relay deadlock.
* fix(gui): drain pending logs before closing the file
Save all queued output at shutdown without the display batch limit.
Keep console output when file logging is disabled. Add tests for complete and batched drains.
* fix(cpu): bypass managed handlers for debug output
* fix(vulkan): correct image barriers and release texture resources
Include attachment reads and select the source stage for presentation uploads.
Release cached textures at shutdown and retain ownership of sampled image views.
* fix(kernel): service guest exceptions during mutex waits
Deliver pending exceptions outside the mutex lock and resume the wait.
Test delivery without granting ownership and isolate the shared scheduler state.
* feat(gpu): replace buffer snapshots with a tracked buffer cache
Keep guest buffers in device memory and upload changed ranges on use.
Recover CPU access through GPU downloads and preserve guest page permissions.
Manage buffer lifetime through submission completion and remove the old writeback path.
Add buffer, tracking, fault recovery, and descriptor synchronization tests.
* fix(vulkan): use cached buffers for GPU-written geometry
Read current vertex and index data from the buffer cache instead of stale CPU snapshots.
Preserve buffer offsets and complete allocation merges before resolving draw handles.
Add tests for index routing, vertex bindings, and overlapping geometry allocations.
* feat(diagnostics): trace GPU submissions and guest memory reads
Keep a bounded submission history and report memory mappings when buffer reads fail.
Trace scalar loads for the selected shader and reset operation details for each recording.
Add tests for submission history and memory-range reports.
* feat(gpu): replace image snapshots with a tracked image cache
* fix(shaders): bound scalar load memory ranges
* fix(shaders): preserve image bindings across branch paths
* fix(videoout): use the active presentation target
* feat(diagnostics): report image cache and presenter costs
* perf(agc): skip unused context updates during geometry capture
* perf(gpu): skip image uploads before full color clears
* perf(gpu): wake the presenter when submissions complete
* perf(agc): reuse retained vertex data before capture
* feat(diagnostics): report image upload preparation costs
* feat(diagnostics): report vertex snapshot and prepass costs
* feat(gpu): replace command processing and label handling
* test(gpu): use asynchronous waits in the image lock test
* fix(memory): finish GPU work before taking mapping locks
* perf(memory): avoid temporary segments for single-mapping reads
* perf(shader): cache scalar analysis query results
* perf(shader): cache scalar load bounds and batch component reads
* feat(diagnostics): report draw and scalar evaluation costs
* fix(videoout): widen the performance overlay and align it right
* test(videoout): isolate flip state and limit port cleanup
* refactor: remove unused fields and unreachable branches
* fix(kernel): use a private lock for event waiter completion
* feat(gpu): replace draw and compute translation
* fix(memory): select the first available guest address
* fix(gpu): invalidate tracked memory across partial ranges
* perf(gpu): stream repeatedly written buffer pages
* fix(shader): preserve image array coordinates
* fix(shader): order shared memory access across wave lanes
* perf(gpu): cache decoded shader instruction metadata
* fix(gpu): preserve command failures when error logging fails
* feat(profiling): add detailed render and submission timings
* feat(profiling): add optional presentation frame history
* fix(gpu): use storage images for stencil writes
* fix(gpu): support compressed image sampling on macOS
* fix(gpu): check graphics subgroup stage support
* fix(cpu): preserve pending waits during signal delivery
* fix(memory): avoid reserved graphics addresses on macOS
* fix(cpu): preserve vector registers during macOS signal recovery
* fix(loader): protect guest memory accesses on macOS
* fix(avplayer): preserve the playback clock during video catch-up
* fix(kernel): write the complete local time conversion result
* feat(http): parse URI components into guest memory
* feat(profiling): separate GPU wait and submission cleanup time
* feat(profiling): add GPU command completion intervals
* fix(profiling): use the configured shader dump directory
* feat(diagnostics): add Windows crash dump capture
* fix(gui): save console placement and hide it on Options
* fix(renderdoc): use F12 for capture and show the shortcut
* feat(gui): add crash dump controls and enable app0 writes by default
* feat(gui): add overlay modes, corner controls, and GPU usage
* fix(cpu): remove unsafe SSE4a instruction rewrites
* fix(cpu): preserve call width and registers in TLS load patches
* fix(loader): copy TLS initialization bytes after relocation
* fix(memory): extend retained reservations through free ranges
* fix(memory): retry faults after backing view restoration
* perf(memory): use binary search for mapped ranges
* perf(memory): track direct allocations and free ranges
* perf(gpu): reuse completed drains when no work is pending
* fix(gpu): identify image upload failures
* feat(diagnostics): profile guest memory operations
* feat(gui): add performance profiling options
* fix(cpu): allow concurrent native fault callbacks
* fix(cpu): respect instruction boundaries in TLS patches
* fix(cli): preserve the assembly path during relaunch
* fix(cpu): recognize time reads in import loop checks
* fix(diagnostics): capture native thread state safely
* fix(agc): validate shader headers and direct register exports
* fix(gpu): apply bounded embedded vertex offsets
* test(shader): verify unsigned difference instructions
* fix(shader): separate global memory source and destination registers
* fix(debugger): restrict frontend requests and validate tokens
* feat(gui): add the community link
* fix(shader): preserve buffer descriptors across branches
Keep incoming register values for alternate resource paths. Resolve each vertex fetch once and preserve shared bindings. Add branch regression tests and a gated invalid-address trace.
* fix(diagnostics): handle Windows debugger breaks during crash capture
Identify debugger breaks from the system module and thread entry. Resume only verified first-chance breaks and preserve application exception handling. Add regression tests for repeated breaks and crash dumps.
* fix(memory): recover late writes after page protection is removed
Track write-access restoration for each watched page. Retry a late write only when the mapping and host permissions still allow it. Reject repeated faults and stale mapping evidence. Add page-watch and native fault regression tests.
* feat(gpu): replace shader and pipeline caches
Resolve shader resources with a cached value graph. Share binding layouts between Vulkan and Metal. Keep descriptors until each GPU submission completes. Add shader access to device addresses and global data share memory. Correct typed buffer formats. Remove the replaced code paths.
* fix(shader): add signed 24-bit multiplication
Decode signed 24-bit multiplication in both instruction formats. Sign-extend the low 24 bits of each input. Store the low 32 bits of the product. Preserve the destination when its lane is inactive. Add Vulkan and Metal translation support and regression tests.
* fix(shader): add signed 16-bit packing
Decode signed 16-bit packing in the extended instruction format. Clamp each signed input to the 16-bit range and pack both results into one register. Add Vulkan and Metal translation support. Preserve inactive destinations and add regression tests.
* fix(shader): add 64-bit shared-memory reads
Decode single and paired 64-bit reads. Load local or global shared memory with the required offsets. Preserve the source address when destination registers overlap it. Keep inactive destination registers unchanged. Add Vulkan and Metal translation support and regression tests.
* fix(shader): add paired 64-bit shared-memory writes
Decode both paired-write forms. Write independent source-register pairs to local or global shared memory. Apply eight-byte or 512-byte offset scales. Use only the first source pair when offsets are equal. Preserve memory for inactive lanes and add regression tests.
* fix(shader): add thread-indexed local-memory writes
Decode the thread-indexed write instruction. Form each address from the low 16 bits of M0, the byte offset, and four times the lane index. Preserve memory for inactive lanes. Enable the required Vulkan lane input and add regression tests for both shader backends.
* fix(shader): handle traps without an installed handler
Decode the shader trap instruction and retain its eight-bit trap ID. Treat the instruction as a no-op under the current no-handler model on Vulkan and Metal. Preserve shader state and continue execution. Keep unknown-opcode checks and add regression tests.
* perf(gpu): avoid allocations in small image queries
Store up to 16 image identifiers inline and use overflow storage for larger queries. Replace the capturing owner callback with an indexed loop. Preserve query order, duplicate filtering, and snapshots during image removal. Add allocation and query regression tests.
* perf(avplayer): reuse private video frame buffers
Recycle a delivered frame only after a new frame is available. Keep reusable storage separate for each playback and drain queued frames before reporting completion. Reuse the conversion buffer after its pending bytes are consumed. Add frame-lifetime and storage-reuse tests.
* perf(agc): copy register packet payloads in bulk
Copy separate register ranges through the guest memory interface. Keep forward word copies for overlapping ranges or when bulk copying fails. Leave null-source payloads unchanged for the caller to fill.
* perf(memory): avoid segment lists for single-mapping transfers
Write and copy through the backing alias when each range fits one mapping. Preserve range checks, locking, and overlap handling. Keep the existing path for transfers across mappings.
* perf(memory): allow independent protection updates
Use address-range locks for transient protection updates. Keep mapping changes and disposal exclusive. Preserve lock order, release locks on failure, and reject protection requests after disposal.
* perf(cpu): wake ready threads with queue notifications
Replace ready-thread polling with notifications under the scheduler lock. Notify the dispatcher when work is queued, an executor is released, or shutdown starts. Finish slice accounting before releasing executor ownership.
* fix(videoout): validate output settings and report refresh codes
Use refresh-rate codes in output status. Check configuration arguments and reject unavailable output modes. Preserve validation errors and output buffer boundaries.
* fix(videoout): share vblank counts across waits and events
Use one display clock per port for vblank status, waits, and events. Report counters for the latest vblank boundary. Wake the event worker when subscriptions change or shutdown starts.
* fix(videoout): apply per-port flip mode timing
Use each port refresh rate to pace flips. Apply window margins and keep ASAP flips unrestricted. Let multiple-flip requests share the next vblank boundary after readiness without applying the flip rate. Cancel CPU waits when the port closes.
* test(agc): cover register copies across backing views
Verify register payload bytes, the returned packet address, and the command-buffer cursor when the source and destination span separate backing views.
* feat(diagnostics): report slow window event polls
Record poll totals and the four longest calls per report interval. Require frame tracing and an active render scope. Preserve event handling and omit event types when no event is returned.
* feat(diagnostics): profile register packet writes
Measure import dispatch, packet setup, and payload copies. Count copy paths and emitter results. Require performance profiling and frame tracing, and report cumulative inclusive times.
* feat(diagnostics): profile shader resource resolution
Measure resource resolution phases, managed allocations, and source activity. Require performance profiling and frame tracing. Report cumulative inclusive times with invariant decimal formatting.
* feat(diagnostics): save shader planning inputs
Save decoded instructions and resource graphs before descriptor validation. Record planning failures under the existing shader dump switch and address filter. Report file errors without replacing the shader rejection.
* feat(diagnostics): save shader variant inputs and modules
Save cache comparisons before translation and pair each variant with its compiled module. Capture indirect image failures under the existing shader dump controls. Create failure callbacks only when the dump gate matches.
* perf(memory): avoid copies in dirty-page range checks
Test intersecting page-mask words directly instead of creating a masked copy. Preserve half-open range bounds and existing region validation.
* feat(diagnostics): profile buffer uploads
Report buffer upload ranges, byte counts, and slow synchronization calls under frame tracing. Associate device-address uploads with shader program hashes. Read hot-page byte counts under the region lock. Keep counters bounded and report decimals in a fixed format.
* feat(diagnostics): trace guest thread handoffs
Record bounded thread transitions, mutex handoffs, and semaphore signals under frame tracing. Preserve thread identities and wake results. Reset traces at session start and write them at shutdown. Keep trace output failures from interrupting native cleanup.
* feat(diagnostics): trace command submission flow
Record bounded submission, queue, and presenter wait events under frame tracing. Correlate records by queue and submission identifiers. Reset the trace at session start and close it at shutdown. Keep trace output failures from interrupting cleanup.
* feat(diagnostics): profile memory faults and protection
Record fault, protection, and lock timings under frame tracing. Separate tracker and image-cache activity. Prepare thread-local state before guest execution. Report cumulative measurements without changing memory protection or lock ownership.
* feat(gui): expose strict shader mode and enable it by default
Add the strict compute switch to global and per-game debug options. Stop on shader rejections unless skip mode is explicitly selected. Preserve disabled overrides and apply the saved choice at launch. Document the default and skip behavior.
* fix(shader): implement unsigned vector xor-add
Decode V_XAD_U32 and apply XOR followed by wrapping addition in Vulkan, Metal, and resource evaluation. Add tests for literal sources, overlapping destinations, and inactive execution lanes.
* fix(gpu): replace incompatible image backing types
Replace single-row image backings when a view requires a different dimensional type. Preserve cached subresources, current contents, and deferred release. Copy between 1D and 2D images through a GPU buffer. Add cache and binding regression tests.
* fix(shader): add thread-indexed local-memory reads
Decode the thread-indexed read instruction. Form each address from the low 16 bits of M0, the byte offset, and four times the lane index. Preserve inactive destination registers. Add Vulkan and Metal translation support and regression tests.
* test(stdio): synchronize concurrent file operations
Run blocking file operations on dedicated threads. Check that close and seek block before releasing the read. Join workers before cleanup and identify failed synchronization checkpoints.
* fix(cpu): read Linux diagnostic memory safely
Use process_vm_readv to read host memory outside the allocation tracker. Reject incomplete reads and test access across a protected page.
* fix(cpu): defer native callback allocation
Create the import callback thunk when it is first needed. Reject native execution outside an x64 process and declare that requirement in backend tests.
* fix(memory): use address-space protection granularity
Keep the native page-size requirement and let test address spaces declare their granularity. Use one host-memory backend for tracker allocation and queries. Keep the test fatal handler active through cleanup.
* test(cpu): isolate POSIX signal recovery state
Prevent signal recovery tests from overlapping other test collections. Restore the previous backend after each test.
* test(metal): resolve fixture buffer descriptors
Materialize buffer descriptors before compiling compute fixtures. Check the resolved formats and update the matching shader snapshots without changing expected device results.
* test(memory): require supported native page protection
Declare the 4 KiB host page requirement for image tracking and backing-view fault tests. Skip these tests on unsupported hosts without changing production checks.
* fix(memory): isolate write-tracker warm-up pages
Use a dedicated host mapping for protection warm-up. Release the mapping after removing its tracker entry. Check native page permissions in the tracker tests.
* fix(memory): track POSIX backing-view query state
Share view mapping and protection records across host memory queries. Preserve committed state for inaccessible pages and round partial-page changes to host pages. Update protection records without allocating during faults.
* test(memory): use valid portable guest ranges
Probe free addresses within the guest range instead of relying on fixed or host-selected addresses. Respect guest and host alignment. Allocate output storage independently of fixed guest image addresses.
* fix(memory): preserve execute permissions during writes
Request writable protection without execute permission for non-executable private memory. Add a regression check that rejects unnecessary executable protection. Restore the original protection after the write.
* fix(cpu): resolve Linux TLS through libpthread
Load Linux thread-local storage functions from libpthread.so.0. Resolve the native TLS lookup from the same library to support glibc versions before the libc merge. Keep macOS imports unchanged.
* fix(kernel): connect sockets without thread-pool waits
Use synchronous TCP connection handling for the blocking guest call. Remove the fixed task wait that could reject connections under thread-pool load. Add tests for occupied workers, refused connections, and descriptor lifetime.
* fix(gpu): prepare device memory and guard inactive loads
Keep active buffers resident and upload read-only device-address ranges before use. Preserve pending faults when the output buffer is full. Prevent inactive lanes from loading global memory.
* feat(gpu): trace device-address memory faults
Select the first fault page when memory tracing is set to auto. Record the shader, instruction, and address for a fault. Trace buffer registration, preparation, and collection for the selected page.
* feat(gpu): trace buffer readback callers
Record buffer readback callers, ranges, byte counts, and elapsed time. Bound the collected ranges and report calls beyond the limit. Enable these details only when both performance profile switches are set. Add tests for caller separation, report gates, and counter limits.
* perf(kernel): skip occupied ranges during address search
Check kernel reservations before asking the backing store to reserve an address. Keep aligned gaps and reusable reservation hints. Add tests for occupied ranges, alignment, and address overflow.
* fix(gpu): correct shader resource selection and data sharing
Support data-share swizzles on Vulkan and Metal. Bound indirect resource selectors from wave-mask inputs. Resolve sampled image variants with their resource types and include selector state in program identity. Add compiler and device regression tests.
* refactor(gpu): centralize guest buffer ownership and lifetime
Track buffer identity, page ownership, recency, and retirement in one registry. Separate upload preparation, download planning, merge bounds, and collection policy. Preserve GPU synchronization and add registry and device regression tests.
* fix(shader): support unsigned 16-bit packing
Clamp each unsigned input to 16 bits. Pack the first input into the low half and the second input into the high half on Vulkan, Metal, and the resource evaluator.
* fix(memory): reject overlapping fixed allocations
Reject committed pages when an exact allocation shares a host reservation. Keep adjacent allocations valid and preserve existing memory regions.
* fix(kernel): implement AIO waits and correct array arguments
Return recorded completion states for single-request waits. Use the correct argument order for array waits and polls. Validate request IDs and guest memory accesses.
* fix(shader): implement scalar signed absolute value
Decode S_ABS_I32 and emit it on Vulkan and Metal. Preserve the minimum signed value and update the scalar condition flag. Match these results in resource evaluation.
* fix(shader): implement three-input vector XOR
Decode V_XOR3_B32 and combine all three inputs on Vulkan and Metal. Apply the same operation during resource evaluation.
* fix(shader): implement scalar bit clear
Decode S_BITSET0_B32 and clear the selected destination bit on Vulkan and Metal. Preserve the condition flag and retain the destination input for scalar bit updates.
* fix(gpu): keep depth export format from enabling pixel shaders
Use shader control flags to detect depth and coverage effects. Do not activate a pixel shader for a depth-only draw because an export format remains set.
* feat(runtime): trace failed imported data writes
Report whether a failed relocation target is readable and list its tracked memory regions. Keep the details under the existing data-rebind logging switch.
* feat(kernel): trace guest-tracked mutex self-locks
Include adaptive mutex self-lock failures in the existing fast-path trace. Keep the lock behavior and return codes unchanged.
* feat(savedata): trace failed mount requests
Report the directory and mount mode when a save mount is missing or busy. Use the existing save-data logging switch.
* feat(gpu): trace pixel shader draw inputs
Include the pixel shader address, hash, and user data in the existing AGC trace.
* feat(gpu): trace pixel register writes
Log pixel shader register writes when AGC tracing is enabled. Include the packet or table address and the shader address.
* feat(gpu): report sources of invalid shader resources
Include shader and descriptor details when a buffer starts in unmapped memory or a sampler has an invalid anisotropy ratio. Keep the existing validation checks.
* fix(kernel): correct AMPR event filter identifiers
Use the required filter identifiers for AMPR and AMPR system events. Add a regression test for both values.
* fix(gui): add missing Azerbaijani option text
Add labels and descriptions for crash dumps, performance profiling, strict shader checks, and the performance display.
* fix(kernel): implement APR ResolveFilepathsWithPrefixToIdsAndFileSizes
Resource streamers resolve relative paths against a shared prefix; without
this HLE every call returned NOT_FOUND and assets never got real ids/sizes.
* fix(remoteplay): stub Initialize and GetConnectionStatus as disconnected
Titles probe Remote Play during pad/network bring-up; unresolved imports
returned NOT_FOUND. Report initialized + disconnected so callers take the
normal offline path.
* fix(agc): accept Gen5 hull shaders that omit PGM_LO/HI in CreateShader
Type-5 headers can start with RSRC1/RSRC2; rejecting them left null handles
and Main Thread AVs. Scan the SH table and skip PGM patch when absent.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(kernel): reject getdents on file fds and emit . / .. for empty dirs
Returning rax=0 for non-directory or empty listings looked like EOF and
let GTA treat the fd as a pointer (fiWriteAsyncDataWorker AV at 0xB1).
* fix(hle): enable GuestImageWriteTracker CPU sync on Windows
Windows previously hard-disabled the tracker, so CPU-written guest
planes never marked dirty and host textures stayed empty. Arm pages
with VirtualProtect, handle write AVs in VEH, and warm/test on
VirtualAlloc memory so protect cannot poison the CRT heap.
* fix(agc): skip CB metadata draws for EliminateFastClear/Fmask/DCC
CB_COLOR_CONTROL modes 2/5/6 are colour-buffer metadata ops; applying
the bound shader as a normal colour draw corrupts subsequent composites.
Decode MODE from bits [6:4] and return before translate.
* fix(agc): merge Prospero attrib-table formats onto IR vertex inputs
IR-discovered BufferLoadFormat often keeps a stale float sharp format;
patch DataFormat/offset from the AGC attrib table (semantic index),
allow offen fetches, and map quirks 113/121 through NarrowVk for host
vertex input.
* fix(audio): harden AudioOut2 stack out-buffer writes against canary smash
Titles that stack-allocate AudioOut2 outs next to the frame canary were
corrupted by oversized or mistyped HLE writes; keep ContextPush pacing.
* Revert "fix(memory): reserve only large regions (#608)"
This reverts commit 8f9456229a.
* fix(gpu): decode Gen5 R16 and RG32 render-target formats
* fix(audio): AudioOut2 host beds, deeper waveOut queue, AJM MP3
GTA V Enhanced routes intro/menu audio through AudioOut2 and FMOD's AJM
MP3 path. Wire PortCreate/PortSetAttributes/ContextPush to dual host
stereo streams, deepen WinMM queue to 128KiB, and decode AJM codec 0
with a stateful NLayer helper so menu music is not silent.
* fix(agc): map PS interpolants via SPI_PS_INPUT_CNTL semantics
Identity ATTR→param wiring ignored hardware remapping, so UI draws
got wrong (or empty) interpolants. Pack CNTL from matched PS/GS
semantics, thread it into Vulkan/Metal as Location/Flat, and fingerprint
it in the graphics shader cache key.
* fix(agc): rect-list/NGG strips, Index8 expand, and GE_INDX_OFFSET
NGG single-rect UI needs triangle-strip expansion; Prospero Index8 must
expand to host u16; glyphs need base vertex from GE_INDX_OFFSET. Skip
param-less rect-lists instead of inventing colour draws.
* fix(np): report GTA Story Mode addcont entitlements as owned
NpEntitlementAccess was returning an empty add-on list, so GTA V Enhanced offered Buy Story Mode. Publish the installed license labels and stub premium-event registration so offline sessions take the owned path.
* fix(cpu): prefer native workers for all guest entry stubs
Route thread entry, continuation, and main entry through RunGuestEntryStub so guest stubs are not invoked above CLR-managed frames (UnmanagedCallersOnly FailFast). Keep requireNativeWorker for tbb_thead; other paths prefer workers with calli fallback.
* fix(agc): implement Rewind/Jump writers and IT_REWIND waits
GTA Subrender AVs came from AcbJumpGetSize / DcbRewind returning NOT_FOUND as packet sizes. Add IT_REWIND and INDIRECT_BUFFER writers, patch SetRewindState into the GPU wait registry, and nest-parse 4-dword jumps.
* fix(gpu): use AddrLib ExactXor for Gen5 Standard256B (mode 1)
Mode 5 already had Standard4K ExactXor; mode 1 still used the generic StandardSwizzle block table, which mis-detiles Gen5 UI atlases.
* Revert "fix(cpu): prefer native workers for all guest entry stubs"
This reverts commit 31c4db0d3886dbc51cc6cbc1a4a5432d678ab113.
* fix(memory): commit-first large maps; reserve only on failure
Replace the #608 always-reserve-only exact-map path with allocate-first and lazy reserve fallback when a huge non-exec commit cannot be satisfied. Prime and widen GetPointer commit so the fallback path is safer for native walkers. Drops the need for a hard #608 revert.
* [Agc] Implement fused shader half exports
* fix(agc): accept optional hull state in CreatePrimState
Port the CreatePrimState hull-optional path from #583 so fused HS pipelines (GTA) are not rejected with INVALID_ARGUMENT. Geometry-derived CX/UC writes are unchanged; hull is traced only.
* fix(videoout): restore thread-safe VulkanHostBufferPool (#564)
The 6db095e wipe dropped CasualcoderDev's lock-ordering-safe pool. Concurrent Return/TryTake without the gate races after the first present and can hang the submit path.
* Revert "fix(agc): implement Rewind/Jump writers and IT_REWIND waits"
This reverts commit bec77bf083dd4037455721e6874023bd05fbdb79.
* test(memory): align lazy-commit expectations with commit-first policy
Fake hosts must reject Allocate so reserve-only paths still run, and GetPointer asserts the 32 MiB prime range including AlignUp spill.
* diag(gpu): log guest-queue backlog breakdown under backpressure
Rate-limit top work types and ordered debugName prefixes when the Vulkan guest work queue stalls, so North Yankton logs show acquire/label vs draw traffic instead of only VulkanOrderedGuestAction.
* perf(agc): coalesce acquire flushes and batch non-DMA label wakes
Flush pending ACQUIRE_MEM invalidation at draw/dispatch/dma/flip boundaries instead of before every packet, and complete release/write-data producers in the same ordered action so load paths enqueue far fewer VulkanOrderedGuestAction items.
* perf(gpu): wait for ordered-action fences and keep draining sync
On Windows/Linux, block briefly for queue-visibility fences instead of deferring the whole logical queue for the tick. Prefer ordered sync/flip heads under backlog pressure, and keep macOS non-blocking defer behavior.
* perf(gpu): raise sync-item ceiling above payload guest-work cap
Apply SHARPEMU_PENDING_GUEST_WORK_ITEMS mainly to compute/draw/image payload work, and allow a higher SHARPEMU_PENDING_GUEST_SYNC_ITEMS ceiling for zero-payload ordered actions and flip markers. Keep the byte budget as the RAM safety valve.
* fix(gta): stub Voice ports and implement sceKernelCheckReachability
Resolve North Yankton-path Voice Create/Delete/Connect/Disconnect/End NIDs and EnumerationThread reachability checks so leftover unresolved imports are not on the critical path.
* diag(gta): arm flip/present/wait probes after North Audio
Rate-limited load_progress TRACE for flip submit, ordered flip enqueue, present taken/not-taken, and GPU wait backlog so North Yankton freezes can be classified without full AGC tracing.
* fix(ampr): restore sequential offset=-1 reads for streamer packs
Re-wire PakDirectoryTracker into sceAmprAprCommandBufferReadFile (dropped in #216) so RAGE sequential pack reads no longer fail while the North Yankton UI keeps flipping. Also rate-limit CheckReachability miss paths for EnumerationThread diagnosis.
* fix(hle/videoout): Windows GuestImage opt-in and keep GTA intro without sync
Default the tracker off on Windows to avoid VirtualProtect thrash, gate AGC
texel-copy skips on Enabled so guest Bink planes keep shipping pixels, and
drain CPU-written images on the present thread when sync is opted in.
* fix(videoout): probe guest content when tracker off so UI can skip copies
Restores upload-known/texture-cache skips for Dead Cells menus, and uses a
sparse guest-memory fingerprint when GuestImageWriteTracker is disabled so
CPU-updated Bink planes still force texel copies for GTA intro.
* fix(audio): keep 128KiB host queue AudioOut2-only
Restore the default 32 KiB (~171 ms) PCM bed for classic AudioOut so
titles like Dreaming Sarah stay in sync; only AudioOut2 opens the deeper
queue needed for bursty FMOD Push on GTA.
---------
Co-authored-by: samto6 <123419830+samto6@users.noreply.github.com>
Windows previously hard-disabled the tracker, so CPU-written guest
planes never marked dirty and host textures stayed empty. Arm pages
with VirtualProtect, handle write AVs in VEH, and warm/test on
VirtualAlloc memory so protect cannot poison the CRT heap.
Co-authored-by: Cursor <cursoragent@cursor.com>
* [Core/Dlsym] Restore normalize-dlsym-arguments and deferred bootstrap tracing from PR #94
PR #216 regressed two critical features from PR #94:
1. NormalizeKernelDynlibDlsymArguments — handles argument reordering
when standalone bootstrap loaders call sceKernelDlsym through the
bridge with (symbol_ptr, handle, out) instead of the standard
(handle, symbol_ptr, out). Without this, payloads like elfldr-ps5
and websrv-ps5 fail with a deterministic UnmanagedCallersOnly
fail-fast.
2. Deferred bootstrap tracing — ring-buffered import logging that
drains after the hot path, avoiding per-call Console.Error I/O.
Also restored:
- CompleteKernelDynlibDlsymFailure — centralized error handling
- IsPlausibleDynlibSymbolPointer — pointer bounds validation
- COW snapshot of _importEntries in ProbeReturnRip
- ResetLazyDlsymStubState and lazy-dlsym field infrastructure
- DraftDrainDeferredBootstrapTraces in Execute() finally block
Fixes#530, fixes#531
* fix: remove orphaned _importNidHashCache.Clear() reference
The field _importNidHashCache no longer exists on main (removed post PR #94).
The 3-way merge incorrectly restored the .Clear() call without the field
declaration, causing a build failure on all platforms.
---------
Co-authored-by: tru3 <tru3@tru3.com>
* [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.
* [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
* [HLE] Stop allocating on the memcpy/memset and trace hot paths
memcpy/memmove no longer allocate a bounce buffer sized to the whole
copy (large copies previously landed on the LOH); they loop through a
single pooled 256 KB rental, copying high-to-low when the destination
overlaps above the source so memmove semantics survive the chunking.
memset reuses a shared zero chunk for the dominant zero-fill case and
rents/fills only min(length, 16K) bytes for non-zero values instead of
allocating and filling a fresh 16 KB array per call; the map-time
zero-fill loop shares the same zero chunk.
SHARPEMU_LOG_SEMA / SHARPEMU_LOG_VIDEOOUT are now read once into cached
bools and every TraceSemaphore/TraceVideoOut call site is guarded, so
trace messages are no longer interpolated (and the env var no longer
queried) on every semaphore op and every flip with tracing off. Trace
output when the flags are set is unchanged.
* [HLE] Remove per-frame allocations from the vblank/flip/equeue plumbing
The 60 Hz vblank pump no longer allocates per edge: PumpVblanks reuses a
pump-thread-only port list instead of a LINQ Where/ToArray, and
SignalVblank/SubmitFlip snapshot their event registrations into pooled
rentals instead of copying the List on every edge and every flip (the
snapshot must still be taken, since triggers run outside _stateGate and
a per-port reusable buffer would race the pump thread against a guest
thread's first-edge signal).
sceKernelWaitEqueue delivery rents the dequeue buffer from the pool
instead of allocating an array per wait, and event-queue wake keys are
formatted once per handle (cached in a ConcurrentDictionary, dropped on
queue delete) instead of building the string on every enqueue. The
semaphore wake key moves onto KernelSemaphoreState at creation, the
same pattern the pthread mutex state already uses, removing the
per-signal/per-wait formatting. SHARPEMU_LOG_EQUEUE is read once into a
cached bool like the sema/videoout flags.
* [HLE] Read guest C-strings without per-call buffer allocations
CpuContext.TryReadNullTerminatedUtf8 allocated a byte[capacity] and
issued one TryRead per byte for every string-argument import. It now
reads through a stack buffer (pooled above 512 bytes) in 128-byte bulk
chunks, falling back to per-byte reads only when a chunk touches an
unreadable range so a terminator sitting just before unmapped memory
still resolves exactly as before. The chunk bound also keeps the
overread past the terminator smaller than the old loop's worst case is
wide, so no fault can appear where the byte loop succeeded.
TryReadAsciiZ (dlsym/symbol resolution) drops its List<byte> + ToArray
round-trip for the same stack/pooled buffer, keeping the byte-by-byte
TryReadByteCompat reads because their Marshal.ReadByte fallback must
probe exactly up to the terminator. Only the final string is allocated
on either path now.
* [HLE] Replace blocking-wait closures with waiter continuation objects
Every wait that actually parked a guest thread allocated two capturing
lambdas (plus their display classes) for the scheduler's resume/wake
callbacks. RequestCurrentThreadBlock and the backend's blocked-thread
state now carry a single IGuestThreadBlockWaiter instead of the
Func<int>/Func<bool> pair: TryWake keeps the run-under-the-scheduler-
gate contract and Resume still produces the guest's RAX on the woken
thread. The waiter stays attached through the wake transition (the old
code nulled only the wake handler there) and is consumed at resume.
The existing waiter objects absorb the captured state as fields, so a
blocking wait now allocates exactly one object: SemaphoreWaiter,
PthreadMutexWaiter, and EventFlagWaiter implement the interface
directly, and the equeue, cond, and rwlock waits get small waiter
classes replacing their closures. Handler bodies delegate to the same
static methods with the same arguments as before; the untimed event
flag wait's mutable captured result becomes a field on its waiter.
* [HLE] Back pending event queues with a ring deque instead of LinkedList
LinkedList<KernelQueuedEvent> allocated a node object on every
non-coalesced enqueue — one per vblank/flip edge per registered queue,
60+ times a second in steady state. KernelEventDeque is a grow-only
ring buffer over a KernelQueuedEvent[] with the three operations the
queue actually uses (AddLast, RemoveFirst, find-and-update-in-place by
ident/filter), so steady-state enqueue/dequeue allocates nothing and
the coalescing update writes the struct back through an indexer instead
of a node reference. All accesses stay under _eventQueueGate, matching
the LinkedList usage it replaces.
* [HLE] Cap memcpy chunk iterations at the requested size, not the rented length
Address Copilot review: ArrayPool.Rent may return a larger array than
requested, so sizing each iteration by chunk.Length let the copy
granularity depend on pool bucketing internals instead of the intended
256 KB chunking. Behavior was already correct for any chunk size (each
iteration re-reads the source, and the overlap ordering is size-
independent), but the loop now mins against the requested chunkLength,
matching what memset already does.
* [HLE] Skip the flip/vblank snapshot rental when no events are registered
Address Copilot review: SignalVblank and SubmitFlip rented (and
returned) a pooled snapshot even with zero registrations — steady
per-frame pool traffic for games that never register flip events and
only poll flip status. Zero-count signals now skip the rental, the
copy, and the trigger loop entirely, which also retires the
Math.Max(count, 1) minimum-rent guard.
* [Host] Introduce host platform abstraction with IHostMemory
Add SharpEmu.HLE/Host with IHostPlatform/IHostMemory interfaces, neutral
page-protection/region enums, and a HostPlatform.Current factory that
resolves the Windows backend (or throws PlatformNotSupportedException on
other OSes, matching today's de-facto behavior). WindowsHostMemory wraps
the exact VirtualAlloc/VirtualFree/VirtualProtect/VirtualQuery calls used
across the engine today, with identical MEM_*/PAGE_* constants.
Migrate StubManager as the first consumer: its private kernel32 P/Invokes
and enums are replaced by IHostMemory calls that issue the same two
native operations (RWX commit+reserve of the PLT arena, release on
Dispose). No behavior change.
This is the first step toward supporting non-Windows hosts; subsequent
commits move the remaining direct P/Invokes in Core and Libs behind the
same seam.
* [Host] Route PhysicalVirtualMemory through IHostMemory
Replace the class's private VirtualAlloc/VirtualFree/VirtualProtect/
VirtualQuery P/Invokes with IHostMemory calls. Every site maps 1:1 onto
the exact native call it issued before: MEM_COMMIT|MEM_RESERVE ->
Allocate, MEM_RESERVE -> Reserve, fault-path commits -> Commit, and
MEM_RELEASE -> Free, with identical protection values produced by the
Windows backend.
IHostMemory gains ProtectRaw so the save/restore protection sequences in
TryWriteExclusive and TryTemporarilyProtectForRead round-trip the raw OS
protection word (including modifier bits the neutral enum cannot
represent) exactly as before. Raw PAGE_* constants remain only for the
internal region-classification helpers, which only ever see values this
class itself assigned.
The exact-address free-on-mismatch, lazy reserve-only threshold, prime
loop, and all trace strings are unchanged.
* [Host] Add IGuestAddressSpace and retire the reflection-based allocator lookup
Introduce IGuestAddressSpace in SharpEmu.HLE (fixed-address AllocateAt /
TryAllocateAtOrAbove and guest mprotect via TryProtect) with signatures
copied from PhysicalVirtualMemory, which now implements it. TryProtect
reproduces the read/write/execute decomposition that
KernelMemoryCompatExports.ResolveHostProtection performs, yielding the
same PAGE_* values through the Windows backend.
KernelVirtualRangeAllocator previously located AllocateAt via cached
MethodInfo reflection (because SharpEmu.Libs cannot see Core types) and
walked wrapper memories through an untyped 'Inner' property. Both are
now typed: ICpuMemoryWrapper exposes the decorated memory (implemented
by TrackedCpuMemory, whose Inner property already existed) and the
allocator type-tests for IGuestAddressSpace with the same bounded
unwrap depth. Failure paths keep the exact [LOADER][TRACE] strings.
* [Host] Move Kernel HLE memory exports off direct kernel32 P/Invokes
KernelMemoryCompatExports loses its private VirtualQuery/VirtualProtect/
VirtualAlloc/VirtualFree declarations and MemoryBasicInformation struct:
- Guest mprotect (sceKernelMprotect/sceKernelMtypeprotect) now routes
through IGuestAddressSpace.TryProtect resolved from ctx.Memory. The
orbis read/write/execute decomposition moves into a GuestPageProtection
conversion whose mapping is value-identical to the removed
ResolveHostProtection.
- The guarded libc heap and host-page accessibility checks go through
IHostMemory (same commit+reserve/protect/free sequence; guard-page and
protection-mask checks compare HostRegionInfo.RawProtection against the
same PAGE_* literals as before).
- HostMemory is exposed as a property so merely loading the type never
resolves the platform backend on non-Windows hosts.
KernelRuntimeCompatExports' RDTSC stub allocates its 16-byte RWX page via
IHostMemory.Allocate; the OperatingSystem.IsWindows() gate returning null
is unchanged.
* [Host] Abstract thread, TLS, and symbol primitives in the execution backend
Add IHostThreading (native TLS slots, current-thread id, affinity, raw
thread create/join, diagnostic register capture) and IHostSymbolResolver
(enum-keyed host function addresses baked into emitted stubs), with
Windows implementations wrapping the exact kernel32 calls the backend
made directly before.
DirectExecutionBackend takes an optional IHostPlatform (defaulting to
HostPlatform.Current) and routes every TlsAlloc/TlsFree/TlsSet/GetValue,
GetCurrentThreadId, SetThreadAffinityMask, GetModuleHandle/GetProcAddress
and the suspend+GetThreadContext diagnostic snapshot through it. The
snapshot moves wholesale into WindowsHostThreading (including the Win64
CONTEXT size/flags/offsets, which are Windows-specific by nature) and
returns a neutral HostCapturedRegisters.
NativeGuestExecutor resolves WaitForSingleObject/SetEvent/ExitThread via
the symbol resolver — the same addresses end up in the emitted run loop,
so stub bytes are unchanged — and creates/joins its raw worker thread
through IHostThreading with the same stack-reservation semantics. The
run-loop emitter itself does not move.
Marshal.GetLastWin32Error() in the affinity-failure log still observes
SetThreadAffinityMask's error because the wrapper makes no intervening
SetLastError call.
* [Host] Move fault handling and remaining backend memory ops behind the seam
Add IHostFaultHandling (handler-thunk creation, first-chance handler
install/remove, unhandled-filter set) with WindowsFaultHandling in a new
Cpu/Native/Windows/ folder. The exception-handler trampoline emitter
moves there whole — same pre-filtered NTSTATUS codes, same TEB gs:[8]/
gs:[0x10] stack-limit reads, same host-RSP TLS switch — parameterized
only by (managed callback, TLS slot, TlsGetValue address), which is
exactly what SetupExceptionHandler passed it before. Handler
installation order, the AddVectoredExceptionHandler(first=1) flag, the
SHARPEMU_DISABLE_RAW_HANDLER gate, and all install/teardown log strings
are unchanged.
Every remaining VirtualAlloc/VirtualProtect/VirtualFree/VirtualQuery/
FlushInstructionCache in the backend partials routes through IHostMemory
with 1:1 call mapping (RWX emit -> RX downgrade -> flush for stub
emission, reserve/commit for the PRT aperture and lazy-commit fault
path, raw-protection round-trips via ProtectRaw). HostRegionInfo gains
RawState/RawAllocationProtection so the lazy-commit trace lines and
protection-mask checks keep printing and comparing the exact native
values.
Windows semantics leaked as bare literals become named constants with
identical values: NTSTATUS codes (WindowsFaultCodes) and Win64 CONTEXT
byte offsets (Win64ContextOffsets, with the existing CTX_* constants
aliased to it and handler-local numeric offsets replaced by the names).
* [Host] Resolve the host platform explicitly at the composition root
SharpEmuRuntime.CreateDefault() now resolves HostPlatform.Current once
and passes it explicitly to PhysicalVirtualMemory and (via a new
optional CpuDispatcher parameter) to DirectExecutionBackend, replacing
the implicit default-argument fallbacks. On unsupported OSes boot now
fails at the root with PlatformNotSupportedException and a clear
message instead of on the first native call. A future Linux/macOS
backend plugs in by returning a different IHostPlatform here.
* [Host] Convert the platform backends to source-generated P/Invokes
Replace [DllImport] with [LibraryImport] in the four Windows backend
files added by this branch (WindowsHostMemory, WindowsHostThreading,
WindowsHostSymbolResolver, WindowsFaultHandling). Marshalling stubs are
now generated at compile time instead of JIT-emitted at runtime, which
fits the pre-JIT-everything boot model and keeps the backends
NativeAOT/trimming ready.
Interop stays zero-copy: all signatures are blittable, GetModuleHandleW
now pins the managed string via Utf16 marshalling instead of copying,
and GetProcAddress names marshal through a stack-allocated Utf8 buffer.
Implicit contracts become explicit where LibraryImport requires it:
TlsFree/TlsSetValue gain [MarshalAs(UnmanagedType.Bool)] (the 4-byte
Win32 BOOL DllImport assumed silently), and GetModuleHandle targets the
W entry point directly since LibraryImport never probes suffixes.
The CONTEXT snapshot buffer stays a NativeMemory allocation rather than
stackalloc: CONTEXT requires 16-byte alignment, now documented at the
call site. Native call sequences are unchanged.
* [Host] Address Copilot review: harden failure paths, honor injected platform
- Free the handler thunk page when the RX protection downgrade fails
(the leak predates this branch, but the failure path is boot-fatal so
releasing the page is unobservable).
- TraceThreadMode and the static diagnostics helpers now resolve host
primitives through the backend bound to the current thread, falling
back to HostPlatform.Current only when no run is active (identical on
supported configs, honors injection everywhere a backend exists).
- HostPlatform.Create additionally requires an x64 process so native
Windows ARM64 fails with the promised PlatformNotSupportedException
instead of emitting x86-64 stubs into an ARM64 process.
* [HLE] Fix guest-thread sync and boot for Unreal Engine titles
Silent Hill: The Short Message (and other UE titles) now boot the full
engine thread graph instead of hanging early. Four related fixes:
- pthread cond/mutex semantics: retain a signal raised with no waiter as
pending, and key block/wake on the state's identity rather than a
resolved address that could differ between lock and unlock. This ends
the ~1.5M-call cond_wait busy-spin.
- Warm HLE type initializers and force-JIT their methods on a host thread
at Freeze(). A .cctor or first-time JIT running on a guest thread's
hijacked stack fail-fasts the CLR as "Invalid Program: attempted to
call a UnmanagedCallersOnly method from managed code".
- Guest thread scheduling: pump after a wake so a readied thread actually
runs, add a dispatcher thread for when every guest thread is parked,
and make the pump-depth guard an atomic CAS.
- Route mutex/rwlock lock/unlock off the non-blocking leaf-import fast
path so a contended lock can deschedule its guest thread.
Ported from the unreal-boot-fixes branch.
* [HLE] Keep mutex/rwlock unlock on the leaf-import fast path
The previous change routed all mutex/rwlock lock and unlock NIDs off the
leaf fast path so a contended lock could deschedule its guest thread. But
unlock never blocks, and taking it off the fast path made it slow enough
that Demon's Souls' job workers livelocked in a guest spinlock (millions
of mutex_unlock calls, no import progress, main thread stuck in
sceKernelWaitEventFlag).
Only *lock* needs to leave the leaf path. Restore the four unlock NIDs
(mutex + rwlock) so guest spinlocks stay cheap, while lock/rd/wrlock
remain off it for the blocking case Silent Hill needs.
* [HLE] Gate pthread_mutex_lock guest-thread blocking (fixes Demon's Souls)
Re-enabling cooperative deschedule on a contended pthread_mutex_lock
regressed Demon's Souls: its job workers run on libSceFiber, and blocking
a guest thread mid-fiber left sceFiberSwitch returning ESRCH followed by
a null fiber-context deref (0xC0000005). Bisect confirmed the pthread
change as the cause; the game reaches the same point as before it once
the block is skipped.
Gate the block behind SHARPEMU_MUTEX_LOCK_BLOCKING (off by default) so
contended locks fall through to the synchronous host-thread wait. The
rest of the pthread fixes (cond_wait pending signals, identity wake keys)
are unaffected.
* fix(core): implement 4-tier lazy dlsym stub materialization and argument normalization
Enforce transactional and thread-safe resolution for standalone ELF bootstrapper pipelines. - Implement a 4-tier additive fallback cascade (T0: runtime symbols, T1: import entries scan, T2: Aerolib mapping, T3: runtime slack-pool lazy stub allocation at 0x7000_0000_0000). - Fix UnmanagedCallersOnly CLR runtime crashes on second bootstrap by adding NormalizeKernelDynlibDlsymArguments to detect and swap mirrored (symbol, handle) register inputs via rigorous pointer bounds verification. - Protect failure paths via CompleteKernelDynlibDlsymFailure, cleanly zero-filling target outputAddress buffers and returns Rax = -1 with zero managed logging execution in hot native paths.
* fix(core): harden lazy-stub diagnostics with COW snapshots and deferred bootstrap logging
Follow-up to lazy stub pool copy-on-write publishing in TryGetOrCreateLazyImportStub. - Snapshot _importEntries in ProbeReturnRip before near-call and PLT import lookup loops to prevent torn iteration during concurrent array replacement. - Defer SHARPEMU_LOG_BOOTSTRAP output: hot path records raw register slots in a ring buffer under lock; TryReadAsciiZ and Console.Error run only after import handler completion via DrainDeferredBootstrapTraces. - Normalize bootstrap dynlib register order at DispatchImport gateway entry before any logging or trace reads, so swapped RDI/RSI on Import#2 cannot fault the native gateway when bootstrap tracing is enabled. - Resolve lazy stub pool bounds from the full SelfLoader-mapped import region via VirtualQuery instead of a hardcoded 4 KiB cap. - Use ConcurrentDictionary for runtime symbol registration during concurrent dlsym. - Emit distinct [LOADER][WARN] reasons when import stub region resolution fails versus lazy stub pool exhaustion.
* [agc] WAIT_REG_MEM suspend/resume, draw packet fixes, new HLE exports, debug cleanup
Rebased onto upstream 79a7437 (par274/sharpemu, rewritten history).
- GpuWaitRegistry: DCBs suspended on unsatisfied WAIT_REG_MEM are re-polled
against guest memory on every submit; fixed 64-bit and standard packet parse
offsets, apply the mask, treat PM4 compare function 0 as "always".
- TryReadSubmittedDrawCount: accept the 5-dword ItDrawIndex2 form emitted by
DcbDrawIndex (count at +4); menu draws were silently discarded before.
- sceAgcDriverSubmitMultiDcbs: reversed ABI (rdi=address array, rsi=dword
sizes, rdx=count).
- VideoOut: vblank events, sceVideoOutGetFlipStatus, buffers registered via
sceVideoOutRegisterBuffers are valid flip targets.
- New HLE: libc stdio (fopen/fread/fseek/ftell/fclose/fgets), Dinkumware
_Getpctype ctype table, NpTrophy2 stubs, AMPR PAK sequential-read tracker,
MsgDialog lifecycle, NGS2 alt NIDs + dummy vtable for handle objects,
guarded memset intrinsic, abort()/strcasecmp null-arg recovery.
- Removed investigation-only code (INT3 breakpoints, qfont/mcpp dumps,
error-candidate printf traces, unconditional debug logs).
First rendered frame: Quake (PPSA01880) presents a 1920x1080 guest frame.
* Implemented a guarded native intrinsic (rep movsb) in DirectExecutionBackend to bypass HLE dispatch overhead, while preserving memory safety checks.
* [hle] clock_gettime clock ids, AudioOut2 canary fix, NID rebinds, new offline stubs
- clock_gettime (lLMT9vJAck0): support CLOCK_SECOND and the *_PRECISE/*_FAST
variants instead of returning EINVAL, which games treated as fatal and
retried in a tight loop.
- AudioOut2: context param writes shrunk to the guest-observed layout (the
old 0x80-byte reset smashed the stack canary at +0x60 and killed audio
init); ContextQueryMemory writes the single u64 the caller expects.
- NGS2: dropped wrong alt-NID aliases (they hash to sceImeUpdate,
sceMouseRead, sceSystemGestureUpdateAllTouchRecognizer - now bound in
their real libraries); added sceNgs2PanInit; fixed VoiceGetState NIDs.
- New verified stubs: sceUltInitialize, sceNpUniversalDataSystemDestroyHandle,
sceNpGetOnlineId, sceNpGetNpReachabilityState, sceImeKeyboardOpen,
sceImeKeyboardGetResourceId, sceMouseOpen, sceKernelAprGetFileSize.
- Import gateway: unwind guest workers at dispatch during backend teardown;
env-gated SHARPEMU_LOG_THREAD_MODE tracing.
* [cpu] Isolate guest execution on native worker threads
Guest entry stubs no longer run above CLR-managed frames: each run is handed
to a pooled raw OS thread whose loop is emitted native code. While guest code
executes there is not a single managed frame on the thread and it stays in
preemptive GC mode, so the GC never walks a frame chain interleaved with
guest stubs that carry no CLR unwind info (the ReversePInvokeBadTransition /
UnmanagedCallersOnly FailFast class of crashes on pumped guest threads).
- NativeGuestExecutor: CreateThread + emitted run loop (WaitForSingleObject,
UnmanagedCallersOnly prologue/epilogue, entry stub call, SetEvent). The
prologue rebinds guest TLS, the host-RSP slot, thread affinity and the
Active* ambient per run, so workers carry no guest identity and pool
freely; the orchestrating managed thread parks in a preemptive wait.
- All three entry sites route through RunGuestEntryStub: guest thread
entries, blocked-continuation resumes, and the main ExecuteEntry.
- Teardown stops workers before any executable stub or TLS index they
reference is freed; a worker that will not stop leaks its loop instead of
freeing running code.
- Kill switch: SHARPEMU_DISABLE_NATIVE_GUEST_WORKERS=1 restores the inline
calli path.
* [cpu] Implement SysV variadic float ABI (xmm0-7 capture, float returns, printf %f)
The import trampoline spilled only xmm0 and never reloaded a return xmm0. The
guest uses the System V AMD64 ABI: variadic float args pass in xmm0..xmm7 and
float/double returns come back in xmm0. As a result variadic float args past
the first were unavailable to HLE handlers, float returns never reached the
guest, and direct printf read %f/%e/%g from GP registers instead of XMM,
printing garbage and desynchronizing every following argument.
- Trampoline: spill xmm0..xmm7 into a 0x80-byte save area below the GP argpack
(r12 stays at the argpack base) and reload the return xmm0 in the epilogue.
- Gateway: read xmm0..7 from the save area into CpuContext and write the
handler's xmm0 back. XMM is caller-saved in SysV, so restoring xmm0 on return
is safe for non-float imports too.
- RegisterPrintfArgumentSource: read float args from xmm0..7 with independent
GP/FP counters and a shared stack-overflow cursor.
Every emitted byte was decoded; a unit test confirms float args read xmm0..7
(not GP) and interleaved "%d %f %d %f" stays synchronized. Build 0/0.
* [cpu] Document the scalar-only leaf-import constraint at its registration site
- IsLeafImport: spell out the no-XMM-args / no-XMM-return invariant the fast
path relies on and what breaks if it is violated; record the 2026-07-11 audit.
- Name every previously uncommented NID in the leaf list (mutex lock/unlock,
usleep, the Ampr/Apr command-buffer block, the unknown AGC packet NID).
- IsNoBlockLeafImport: document that it is a sub-filter of IsLeafImport and
that its five extra entries currently take the full gateway path; fix the
mislabeled K-jXhbt2gn4 comment (pthread_mutex_trylock, not
scePthreadMutexTrylock, which is upoVrzMHFeE).
- Point the DispatchImport call-site note at the audited list.
Comment-only change: the comment-stripped diff is empty and the solution
builds with 0 warnings / 0 errors.
* [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>