* 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.
AjmModuleUnregister/AjmFinalize were pure no-ops (always returned success
without touching state); they now validate the context and actually remove
the codec registration / context entry, returning a real error when the
context is unknown. AjmModuleUnregister traces whether the codec was
actually registered, to help spot a title unregistering something it never
registered.
MaxCodecType was hardcoded to 25 based on known Sony codec ids, incorrectly
rejecting valid Gen5 codec types (e.g. 24). Registration is pure bookkeeping
(HashSet.Add); the only real constraint is that codecType must not overflow
the 32-bit instanceId it gets packed into, i.e. codecType < 2^18. Named the
instanceId bit-packing constants (InstanceIdSlotBits/InstanceIdSlotMask) so
the four call sites that used to hardcode 14/0x3FFF independently can't
drift out of sync, and MaxCodecType's formula is self-evident.
Accept sceAcmBatchInitialize/InitializeLite/Start/StartMultiple/Process as
successful no-ops -- the emulator runs no ACM DSP jobs, but Scream's workers
trap on int 0x41/0x42 asserts whenever a submission call reports failure.
Accept sceAudioOut2MasteringInit/Set3DLatency as no-ops -- the host mixer
has no mastering/object pipeline to tune, but returning failure makes
titles tear down their whole ACM context and abort audio arena bring-up.
Tested on Ghost of Yotei (PPSA26344): sceAudioOut2MasteringInit/Set3DLatency
unresolved-import warnings go from 2 to 0, unblocking 5 audio-related guest
threads that never spawned before (MovieDecoder, snd_stream_parsing_thread,
snd_stream_reader_thread, Psn, NCA::PumpThread), watchdog stall errors from
1 to 0. This alone gets the title past its Scream audio-init stall into
further boot, but it still hits an unrelated infinite retry loop in
sceVideoOutGetFlipStatus shortly after -- fixed by the separate
videoout-agc-hle-misc change; combined, the title renders and presents a
real GPU frame.
Regression-checked on Demon's Souls, Astro Bot, Outer Wilds, Cult of the
Lamb, Ghost of Tsushima, GTA, Minecraft, Quake: 0 calls to any export
touched by this change on any of them, byte-for-byte identical to
upstream/main.
* [VideoOut/Vulkan] Fix boot deadlock, writeback stall, and presentation bugs
- Presenter thread now starts on the compute dispatch path too, fixing
a boot deadlock when a title's first GPU work is compute (Ghost of
Yotei G-Buffer clear).
- Guest render-target format swaps between sibling pixel formats now
reinterpret in place instead of recreating blank, preserving
GPU-written content.
- Vectorized the guest-buffer writeback scan (equal-byte skip + coarse
per-page pre-check), fixing multi-second stalls on fragmented buffers
that starved JobWorker completion signals.
- _presentedSequence now advances on every Render() early-return path,
fixing an unthrottled busy loop on stale/dropped presentations.
* Remove unnecessary Silk.NET.Windowing dependency
- Fixed guest mappings now go through a granule-aware allocator so
adjacent PS5 16 KiB pages sharing a 64 KiB Windows allocation
granule no longer collide and fail.
- TryBackFixedRange routes free/reserved gaps through the same
granule-safe path, fixing strays that stranded the rest of a granule.
- NORMAL pthread mutex self-relock reverted to real EDEADLK instead of
silent compatibility recursion, which was starving other threads.
- TryResolveMutexState now checks the handle-keyed lookup before
falling through to "not found" on a fresh, never-cached address.
Three defects found while bringing up a PS5 title. None are title-specific.
SPI_SHADER_PGM_LO_GS / HI_GS were 0x8A/0x8B, which are actually
SPI_SHADER_PGM_RSRC1/RSRC2_GS. Reading them as an address produced a
58-bit value (observed live: 0x30004622C008300). The correct offsets are
0x88/0x89, consistent with SPI_SHADER_PGM_CHKSUM_GS = 0x80 and
SPI_SHADER_PGM_LO_ES = 0xC8 already in the table.
Draw translation dropped any RECT_LIST draw whose vertex program exported
no parameters while the pixel shader had interpolated inputs. A
disposition census over a real run measured this deleting ~620 of every
5000 draws (12%). Rect lists are what AMD drivers emit for clears, blits
and resolves, so the guard was deleting clears and leaving previous frame
contents on screen as trails. Rendering a draw whose interpolants are
undefined is strictly better than deleting it.
sceAgcDcbDrawIndexIndirectMultiGetSize was unimplemented while
sceAgcDcbDrawIndexIndirectMulti emits an eight-dword packet. A title that
sizes its command buffer from the missing export under-reserves by three
dwords. NID derived with Ps5Nid.Compute, which reproduces the committed
NIDs of the neighbouring exports.
Tests: AgcContextRegisterTests and AgcShaderStageRegisterTests drive real
PM4 packets through sceAgcDriverSubmitDcb and assert what the parser
retained for the context and SH register dictionaries, via two new
internal accessors; neither dictionary had any test surface, which is why
register questions previously cost five-minute game runs.
* VideoOut: track guest-flip FPS and label load/stall gaps
Headline FPS follows VideoOut submit cadence rather than host presents, and long gaps show LOAD/STALL instead of a stale multi-second MS average.
* Metal: skip waitUntilCompleted when the command buffer is already Completed
Tiny write-back batches often finish before the wait; checking status avoids redundant ordered-queue round-trips.
* Metal: opt-in long-edge drawable cap via SHARPEMU_METAL_CAP_DRAWABLE
Default presentation resolution is unchanged; set SHARPEMU_METAL_CAP_DRAWABLE=1 to cap the drawable long edge at 1920.
* Pad: implement scePadGetTriggerEffectState under its own NID
NID znaWI0gpuo8 was mapped to sceUserServiceGetUserName as a "title-captured
alias". It is not that symbol. Recomputing the NID of every catalogued name
(base64 of the reversed first eight sha1 bytes of name+salt) resolves
znaWI0gpuo8 to scePadGetTriggerEffectState, and sceUserServiceGetUserName
hashes to 1xxcMiGu2fo instead. Auditing all 1087 export declarations the same
way found this to be the only NID whose declared name is wrong.
The consequence was not a missing export but a wrong one: the user-service
handler rejected the pad's arguments and returned
SCE_USER_SERVICE_ERROR_INVALID_PARAMETER about eighteen thousand times per
run in PPSA10112, so every poll fell back to a cached button bitmask. It
also hid the calls from every search for pad activity, which is why this
title was believed never to touch scePad at all.
The state size is taken from the caller's own frame rather than assumed: the
guest points the out-param at rbp-0x30 and stores its stack cookie at
rbp-0x28, leaving eight bytes for the state. Writing the sixteen the frame
superficially suggests would land on the cookie and fail the guest's stack
check - the same failure this codebase has already hit three times from
oversized HLE writes - so the test pins the size by asserting the cookie
survives.
No host pad exposes DualSense adaptive-trigger feedback, so the neutral
all-zero state is reported as success, which lets the caller take its normal
path instead of the fallback.
* Apply SDWA ABS/NEG as float sign-bit, not integer, modifiers
SDWA's ABS and NEG source modifiers are floating-point sign-bit
operations on GCN: ABS clears the sign bit, NEG flips it. We applied
them as integer operations instead - SAbs, and a two's-complement
negate of the raw bit pattern. That turns 1.0 into -4.0 and -3.0 into
1.5.
UE4 compiles the final line of DrawRectangle, OutPosition.xy *=
float2(1,-1), into a single V_MOV_B32 with SDWA NEG, so every UE
fullscreen pass had its clip-space Y silently skewed. The canonical
fullscreen triangle (1,-1) (-3,-1) (1,3) became (1,-4) (-3,-4) (1,1.5),
which covers 6/11 of the viewport instead of all of it.
That reproduces the measured defect exactly, on four independent
quantities: hypotenuse slope 8/11, crossings of y=+1 and y=-1 at
x=+7/11 and x=-9/11, and covered area 6/11 = 54.55% of the 2304x1296
viewport. It also explains why the edge was resolution-independent and
identical across six unrelated shaders - it is the same instruction in
every one of them.
The distinguishing evidence is the transform's fixed point. A wrong
scale would hold NDC -1 in x and +1 in y; the observed transform holds
the opposite corner in both. Independently, and using only the measured
line rather than any assumed vertex position: a wrong multiplier alone
leaves a residual of -18 whatever the multiplier, and a wrong addend
alone forces slope 1, not 8/11. Both terms had to be wrong at once,
which only a Y-only sign-bit corruption produces.
Float instructions are unaffected: GetFloatSource passes
applySdwaIntegerModifiers: false and applies its own modifiers, so this
path only ever fed raw-source reads - where the hardware behaviour is
the sign-bit one regardless of the opcode being a bit-move.
The sign bit is selected by the SDWA source-select width so a 16-bit
select flips bit 15 rather than bit 31.
Verified: emitted SPIR-V for the same shader changes from
OpISub %uint %uint_0 %2147 to OpBitwiseXor %uint %2147 %uint_2147483648;
25-program synthetic conformance gate passes; 805 tests green; three
100-110s live runs with no crashes and no new shader failures. The
end-to-end pixel re-measurement is NOT yet closed - see task #26.
* gpu: size single-channel 16-bit and two-channel 8-bit formats
GetFormatCompatibilityClass listed only R16Sfloat in the 16-bit class, so
GetVulkanImageByteCount computed zero bytes for R16Unorm, R16SNorm, R16Uint,
R16Sint and the R8G8 family. UploadGuestImageInitialData treats a zero
expected size as an incompatible upload and drops it, which leaves the
texture blank for the rest of the run rather than failing loudly.
Silent Hill uploads R16Unorm at 144x81, 240x135, 256x256, 512x512 and
1024x1024, and every one was rejected: the guest supplied exactly
width*height*2 bytes each time (23328 for 144x81) against an expected zero.
Also adds R8SNorm to the 8-bit class, which was missing for the same reason.
* Vulkan: enable textureCompressionBC when the device supports it
Guest BC1–BC7 textures can be sampled directly when the feature is available; warn when it is not.
* Share one guest image across sRGB/UNORM aliases
Ported from origin/fix/view-compatible-guest-images 7fb8fdf.
Rendering as sRGB and ImageLoad/Store-ing as UNORM at the same guest
address are the same surface accessed through different number formats.
Recreating the guest image per number format ping-pongs content between
two VkImages and loses the rendered pixels on every transition; the
mutable-format image now accepts the counterpart identity and serves it
through alias views. The commit names AvPlayer movie copies as the
pattern that needs this.
Adapted for this base: GetOrCreateGuestImage has since grown resolution
scaling and 3D/array support, so the alias accept is folded into the
current predicate (LogicalWidth/LogicalHeight/LogicalDepth/Type) rather
than the old Width/Height pair, and the storage-counterpart widening is
placed before the physical-dimension computation. The helper functions it
relies on (GetStorageImageFormat, IsCompatibleViewFormat) already existed.
* fix(gpu): one vertex attribute per guest stream view
The scalar evaluator gave every buffer_load_format instruction its own
attribute location. Two things multiply those: the CFG walk visits one
instruction on several paths, and an uber vertex shader fetches the same
stream from every material branch. UE's larger shaders reached 56 bindings
from 8 distinct views, and one reached 701 from 5.
Metal caps a vertex function at 31 attributes, so MoltenVK failed the MSL
compile with "'attribute' attribute parameter is out of bounds" and the
surrounding vkCreateGraphicsPipelines returned ErrorInitializationFailed.
Every draw using those pipelines was dropped, which is why Silent Hill:
The Short Message rendered a black scene. The vertex buffer count drove
Metal's buffer indices out of range too, giving the companion
"cannot reserve 'buffer' resource location at index 0" failures.
Key attributes by the guest stream view they read - absolute element
address, record stride and format - and alias every other fetch that
resolves to the same view onto that binding, so both translators map
those instruction PCs to one input variable. On PPSA10112 this takes the
worst shader from 56 attributes to 8 and pipeline failures from 840 to 0.
* AGC: deliver compute-queue completion events at the queue fence
sceAgcDriverSubmitAcb submissions never produced a completion interrupt.
NotifySubmittedDcbCompleted returned early for anything that was not the
graphics queue, so an ACB reaching its ordered-queue fence published
nothing. UE 4.27's dynamic-resolution GPU-timing heuristic parks the game
thread on exactly that interrupt, so the render side never advanced and
Silent Hill: The Short Message deadlocked after its first frame.
Give every queue a CompletionEventId: 0 for graphics (what it already
published) and the owner handle from sceAgcDriverSubmitAcb rdi for a
compute queue, which is the same value the guest passes to
sceAgcDriverAddEqEvent. Publish under that ident from the existing fence
point, which both PumpSubmittedQueue and ResumeSuspendedDcb already reach
only after the submission is fully parsed.
Delivery is synchronous on the ordered guest-action queue rather than on a
ThreadPool hop with a sleep. That action runs after the logical queue has
flushed and waited for its latest fence, which is the moment hardware
would raise end-of-pipe. Deferring past it can only make the interrupt
late and reorder it against registration changes.
Gating: the per-queue completion event is unconditional, because
completion interrupts do fire on real hardware and because delivery is
registration-gated -- TriggerRegisteredEvents only queues onto equeues
that registered this exact (ident, graphics filter) pair, and
sceAgcDriverAddEqEvent is the only producer of graphics registrations. A
title that never registers its ACB owner handle observes no change.
SHARPEMU_AGC_SUBMIT_COMPLETION_EVENT is left to gate only the broad
ident-ignoring fan-out (TriggerRegisteredEventsDistinct), which is a
compatibility guess rather than hardware behavior; it also stays scoped to
the graphics queue where it was measured, so enabling the flag does not
newly fan out across compute queues.
* fix(gpu): reflect guest CPU writes into large and render-target-aliased images
Ports the still-applicable half of the archived fork's stale-texture fix
(a42ccae) onto current main. Silent Hill: The Short Message (PPSA10112)
shows both faces: black title-screen UI (glyph atlas frozen at its first
upload) and stale/garbage rows on the brightness screen (a 3840x2160 UI
sheet whose backing bytes were never re-read).
1. Write tracking is armed under a byte budget, not a resolution cap.
GetOrCreateGuestImage armed GuestImageWriteTracker only when
target.Width <= 1920 && target.Height <= 1080. Silent Hill renders at
3840x2160, so every one of its render targets was excluded from
CPU-write tracking and no guest rewrite of one could ever invalidate
it: SyncCpuWrittenGuestImages (the flip / ACQUIRE_MEM re-upload path)
only ever visits ranges the tracker armed.
The cap presumably existed as a perf guard, but resolution is the
wrong proxy for the cost. Arming is one mprotect over the range, and
the fault handler unprotects the whole range on the first store, so a
write burst costs one fault regardless of size. What actually scales
with the surface is the dirty re-upload: one byte[byteCount]
allocation plus a full guest-memory read per dirty flip. So the guard
is now a byte budget, set equal to the 128 MiB limit that
SyncCpuWrittenGuestImages itself enforces before re-uploading. Above
that, arming can only cost faults; it can never produce a re-upload.
That is generous for 4K (RGBA8 32 MiB, RGBA16F 63 MiB, RGBA32F
127 MiB all fit) while still excluding volume textures that a
resolution cap could not see at all (512^3 RGBA8 is 512 MiB behind a
"512x512" surface).
Both sites now also arm the exact extent recorded in
_guestImageExtents (GetTextureByteCount) instead of
Width*Height*depth*GetTextureBytesPerPixel, so the armed range and
the range the sync path reads back are the same bytes; the old
expression over-counted block-compressed and unknown formats.
2. The CPU-texture refresh path no longer gates on IsCpuBacked alone.
TryCreateCpuTextureRefreshResource bailed on !guestImage.IsCpuBacked.
That flag is a latch: it flips false the first time an address is
used as a render target and never flips back. A surface that was
rendered into once and is afterwards rewritten by the guest CPU was
therefore frozen at its last GPU content forever, even when the parse
thread had already shipped fresh texels for it.
The gate is replaced by ShouldRefreshGuestImageFromCpu: CPU-backed,
or the parse-time write generation is above zero and differs from the
generation recorded by the last upload. Keeping the positive-
generation requirement preserves the pure GPU-feedback case (render
into an image, then sample it) that IsCpuBacked used to protect: such
a surface is now tracked (change 1) but never CPU-written, so its
generation stays zero and its live image is left alone. This matters
more than it did in the fork, precisely because change 1 arms
tracking on far more render targets. Dropping the gate outright, as
the fork did, would let a target sampled under a format tag that the
availability map does not match be overwritten once with whatever
sits in guest memory.
The existing content fingerprint still suppresses redundant uploads,
and MarkSampledImagesInitialized records the uploaded generation, so
a rewritten surface re-uploads exactly once per guest write burst.
Not ported: the fork's third part added a PeekDirty guard to the
parse-time snapshot fast path in AgcExports. It is superseded. That path
now calls IsGuestImageUploadKnown, which already compares
_cpuBackedUploadGenerations against the tracker's write generation - a
monotonic value that survives another owner consuming the dirty flag,
unlike PeekDirty, which both EvictDirtyCachedTextures and
SyncCpuWrittenGuestImages clear. Guest images with no generation entry
are covered instead by SyncCpuWrittenGuestImages. Adding a non-consuming
PeekDirty there would also make every draw between a CPU write and the
next flip fall through to a full texel re-read of the surface (33 MiB
for a 4K sheet), since Track re-arms without clearing the dirty flag.
The fork's promotion-path Track ("vulkan.cpu-backed-image") is likewise
superseded: AgcExports already arms every sampled texture's backing
extent as "agc.decoded-texture" before reading its texels.
Both decisions are extracted as pure internal predicates so they can be
unit-tested; the Vulkan device code around them needs a real device.
* Kernel: correct equeue event delivery and waiter lifetime
Ports the event-queue rework from the archived silent-hill-minimal branch
(968e9606, 9e3abb12, 2be9cfbf, f157a115) onto current upstream. The equeue
implementation had not been touched upstream since that branch forked, so
none of it had landed.
Behaviour fixed:
- Per-waiter event reservation. A blocked waiter used to wake on "the queue
has any pending event" (TryWake => HasPendingEvents) and then re-read the
queue on resume, so a woken waiter could find the event already drained by
another waiter and park again with the wake consumed. Events are now
reserved to the waiter they are delivered to.
- Level-triggered events are preserved instead of being cleared by an
unrelated read; only events that declare clear-on-read reset their trigger
state.
- Queued interrupts are bound to the registration generation that produced
them, so an event registered after a queue was reused cannot consume an
interrupt raised for the previous registration.
- Deleting an equeue now terminates its waiters instead of leaving them
blocked on a handle that no longer resolves.
- sceKernelTriggerUserEvent stores its third argument in the event's udata
(0x18) rather than its data word (0x10). The guest reads it back with
sceKernelGetEventUserData, which loads 0x18, so every triggered user event
previously read back as 0. This matches the reference behaviour in shadPS4,
where TriggerEvent takes udata and sceKernelGetEventUserData returns
ev->udata. The upstream test asserting the data word is updated, since it
encoded the inconsistency rather than the ABI.
KernelPthreadState gains TryGetCurrentThreadIdentity and a new
KernelSyncTraceFormatter carries the shared, opt-in diagnostic formatting the
ported code calls; both are gated behind the existing trace flag and do no
work when it is off.
Tests: 662 pass, 0 fail (SharpEmu.Libs.Tests 588 -> 598).
* Implement VOP3 0x149 V_BFE_I32 and 0x36A V_CVT_PKRTZ_F16_F32
PPSA10112 dropped three shaders per run on two unimplemented VOP3
opcodes. The translator fails a whole shader on an opcode it does not
know, so each one costs a dropped draw rather than wrong pixels.
0x149 sits between 0x148 V_BFE_U32 and 0x14A V_BFI_B32, and 0x36A
between 0x369 V_CVT_PKNORM_U16_F32 and 0x36D V_ADD3_U32; the
surrounding table entries already match the canonical map densely on
both sides of each gap. V_CVT_PKRTZ_F16_F32 needed no emitter - it was
already implemented for the VOP2 form at 0x2F and its VOP3 alias at
0x12F, and only the VOP3-only opcode number was missing.
V_BFE_I32 mirrors its unsigned sibling, masking offset and width to 5
bits, and differs only in extracting through a signed type so the field
sign-extends. GCN defines width 0 as returning 0 where SPIR-V leaves a
zero Count unspecified; VBfeU32 has the same gap, so this matches it
deliberately rather than diverging - fix both together if it matters.
Also widen ReportGuestPointerSplit, which filtered to an incoming value
of exactly 1. The crash being hunted leaves 0x0000007000000000, whose
low dword is 0, so the one detector built to catch this bug class could
never have reported it.
Verified: unsupported-opcode errors 3-4 per run -> 0, over a 130s run
that survives to the same stage. Metal translator still lacks VBfeI32;
Vulkan/MoltenVK is the macOS path so it is a divergence, not a blocker.
* AGC: retain active label producer records
Ported from the archived silent-hill-minimal branch (274ccfdf).
RegisterLabelProducer bounded its history with RemoveRange(0, 1024) once it
reached 4096 entries, which evicts the oldest records regardless of whether
their label write has completed. Those records are not a diagnostic cache:
a suspended DCB resolves its wait_reg_mem by finding the producer that will
write the watched label. Dropping an active record hides an earlier
same-submission label write, so a legitimate in-stream fence suspends
forever and the graphics queue stops.
Compact only completed history, and let the list exceed the soft bound when
every record is still active — correctness over a diagnostic limit.
Two hardening changes over the ported version, because a suspended queue is
exactly when every record is active:
- compaction is a single order-preserving pass instead of repeated RemoveAt,
which would shift the tail per eviction (quadratic) while the label gate is
held;
- when a pass frees nothing the bound is raised to twice the current count, so
registration does not rescan the whole list on every subsequent add, and it
is reset once compaction can make progress again.
Tests: 664 pass, 0 fail (SharpEmu.Libs.Tests 598 -> 600).
* AGC: keep produced label values a suspended wait still needs
GpuWaitRegistry.RecordProduced dropped the entire produced-value table once it
reached 8192 entries:
if (_lastProduced.Count >= 8192) { _lastProduced.Clear(); }
Those entries are release state, not a cache. CollectDeadlockBroken is the only
way out for a DCB suspended on a WAIT_REG_MEM whose label the guest has since
recycled for other data: it replays the value a real producer already wrote to
that label. Clearing the table wholesale erases exactly the records live waiters
depend on, so every such waiter is stranded permanently — the suspended graphics
queue never resumes, and with it the render thread and the whole engine thread
graph park.
That is what Silent Hill (PPSA10112) hits. Its final unsatisfied waits watch
labels holding guest allocator metadata (each reads a pointer into its own
region rather than the expected 1), i.e. recycled memory, which is precisely
the case the deadlock breaker exists to handle — yet agc.deadlock_break fires 0
times across a run with 490 wait suspensions and 1068 successful release_mem
writes, because the producing values had already been cleared.
Prune only values no registered waiter is watching, and let the table exceed the
soft bound while they are all watched. Same reasoning as the label-producer
history in the preceding commit: correctness of synchronization state takes
precedence over a diagnostic bound.
Tests: 666 pass, 0 fail. The regression test fails against the previous
wholesale Clear() and passes with the prune, verified by reverting the fix.
* Correct VOP3 0x36A: V_CVT_PK_U16_U32, not V_CVT_PKRTZ_F16_F32
a2d186e mapped 0x36A to V_CVT_PKRTZ_F16_F32 on the strength of a gap in
our own opcode table. That was wrong, and wrong in the worst available
way: an emitter for V_CVT_PKRTZ_F16_F32 already existed, so instead of
failing loudly like an unknown opcode, the mapping would have emitted
float-pack semantics for an integer-pack instruction and produced
silently incorrect results.
LLVM is unambiguous:
defm V_CVT_PK_U16_U32 : VOP3Only_Real_gfx10<0x36a>;
defm V_CVT_PKRTZ_F16_F32 : VOP2_Real_gfx6_gfx7_gfx10<0x02f>;
so on Gen5 the float pack is VOP2 0x2F with VOP3 alias 0x12F - both of
which our table already had - and there is no VOP3-only encoding of it
to add. 0x36A sits with the other integer/normalised pack conversions
at 0x368/0x369/0x36B.
silent-hill-minimal-rebased had this right all along.
The V_BFE_I32 half of a2d186e stands: LLVM confirms 0x149, and that
branch maps it identically.
Lesson, since I had just warned someone else about exactly this: a gap
in a table is evidence about numbering, not about identity. Inference
from neighbouring entries is fine for narrowing candidates and worth
nothing as a conclusion - especially when a plausible emitter already
exists to swallow the mistake quietly.
* AGC: report release-label writes that never reach guest memory
Both release_mem handlers recorded the produced label value only on success:
if (wroteData && dataSelection is 1 or 2) GpuWaitRegistry.RecordProduced(...)
with no else. A failed write is not benign here. That packet is the producer a
suspended WAIT_REG_MEM is waiting for, so when it fails the label is neither
written nor recorded, CollectDeadlockBroken has no value to replay, and the
graphics queue stays suspended forever — the render thread and the engine
thread graph park behind it with nothing in the log to say why.
Measured on Silent Hill (PPSA10112): the fatal AccessViolation lands exactly
here, on the presenter thread, in ApplySubmittedReleaseMem's label write into a
protected guest page. The faulting variant kills the process; the
returns-false variant wedges the GPU silently. Only the first was ever visible.
Report the failure (rate-limited: first 16, then powers of two) instead of
dropping it. This does not fix the underlying write failure — it makes a
permanently suspended queue diagnosable rather than silent.
Tests: 666 pass, 0 fail.
* CPU: gate periodic import logs and fast-path memcpy/memmove leaves
SHARPEMU_LOG_IMPORT_PERIODIC=1 re-enables periodic Import# tracing. memcpy/memmove use a thin TryCopy leaf that skips register marshalling.
* Ampr: cooked-id index preload and host FD LRU cache
Preload the app0 APR index during bind and bound the open host-file cache so streaming reads stay responsive under large title archives.
* Vulkan: abandon timed-out guest fences without blocking later frames
Move fence-timeout submissions out of the blocking queue, keep GPU objects alive until the fence signals, and retire them from an abandoned list so one hung dispatch cannot re-block capacity waits.
* AGC: follow command-buffer branches across arena switches
Implement sceAgcCbBranch and walk INDIRECT_BUFFER so submissions that continue in a linked buffer keep their flip and end-of-frame labels.
Ports the event-queue rework from the archived silent-hill-minimal branch
(968e9606, 9e3abb12, 2be9cfbf, f157a115) onto current upstream. The equeue
implementation had not been touched upstream since that branch forked, so
none of it had landed.
Behaviour fixed:
- Per-waiter event reservation. A blocked waiter used to wake on "the queue
has any pending event" (TryWake => HasPendingEvents) and then re-read the
queue on resume, so a woken waiter could find the event already drained by
another waiter and park again with the wake consumed. Events are now
reserved to the waiter they are delivered to.
- Level-triggered events are preserved instead of being cleared by an
unrelated read; only events that declare clear-on-read reset their trigger
state.
- Queued interrupts are bound to the registration generation that produced
them, so an event registered after a queue was reused cannot consume an
interrupt raised for the previous registration.
- Deleting an equeue now terminates its waiters instead of leaving them
blocked on a handle that no longer resolves.
- sceKernelTriggerUserEvent stores its third argument in the event's udata
(0x18) rather than its data word (0x10). The guest reads it back with
sceKernelGetEventUserData, which loads 0x18, so every triggered user event
previously read back as 0. This matches the reference behaviour in shadPS4,
where TriggerEvent takes udata and sceKernelGetEventUserData returns
ev->udata. The upstream test asserting the data word is updated, since it
encoded the inconsistency rather than the ABI.
KernelPthreadState gains TryGetCurrentThreadIdentity and a new
KernelSyncTraceFormatter carries the shared, opt-in diagnostic formatting the
ported code calls; both are gated behind the existing trace flag and do no
work when it is off.
Tests: 662 pass, 0 fail (SharpEmu.Libs.Tests 588 -> 598).
Ports the still-applicable half of the archived fork's stale-texture fix
(a42ccae) onto current main. Silent Hill: The Short Message (PPSA10112)
shows both faces: black title-screen UI (glyph atlas frozen at its first
upload) and stale/garbage rows on the brightness screen (a 3840x2160 UI
sheet whose backing bytes were never re-read).
1. Write tracking is armed under a byte budget, not a resolution cap.
GetOrCreateGuestImage armed GuestImageWriteTracker only when
target.Width <= 1920 && target.Height <= 1080. Silent Hill renders at
3840x2160, so every one of its render targets was excluded from
CPU-write tracking and no guest rewrite of one could ever invalidate
it: SyncCpuWrittenGuestImages (the flip / ACQUIRE_MEM re-upload path)
only ever visits ranges the tracker armed.
The cap presumably existed as a perf guard, but resolution is the
wrong proxy for the cost. Arming is one mprotect over the range, and
the fault handler unprotects the whole range on the first store, so a
write burst costs one fault regardless of size. What actually scales
with the surface is the dirty re-upload: one byte[byteCount]
allocation plus a full guest-memory read per dirty flip. So the guard
is now a byte budget, set equal to the 128 MiB limit that
SyncCpuWrittenGuestImages itself enforces before re-uploading. Above
that, arming can only cost faults; it can never produce a re-upload.
That is generous for 4K (RGBA8 32 MiB, RGBA16F 63 MiB, RGBA32F
127 MiB all fit) while still excluding volume textures that a
resolution cap could not see at all (512^3 RGBA8 is 512 MiB behind a
"512x512" surface).
Both sites now also arm the exact extent recorded in
_guestImageExtents (GetTextureByteCount) instead of
Width*Height*depth*GetTextureBytesPerPixel, so the armed range and
the range the sync path reads back are the same bytes; the old
expression over-counted block-compressed and unknown formats.
2. The CPU-texture refresh path no longer gates on IsCpuBacked alone.
TryCreateCpuTextureRefreshResource bailed on !guestImage.IsCpuBacked.
That flag is a latch: it flips false the first time an address is
used as a render target and never flips back. A surface that was
rendered into once and is afterwards rewritten by the guest CPU was
therefore frozen at its last GPU content forever, even when the parse
thread had already shipped fresh texels for it.
The gate is replaced by ShouldRefreshGuestImageFromCpu: CPU-backed,
or the parse-time write generation is above zero and differs from the
generation recorded by the last upload. Keeping the positive-
generation requirement preserves the pure GPU-feedback case (render
into an image, then sample it) that IsCpuBacked used to protect: such
a surface is now tracked (change 1) but never CPU-written, so its
generation stays zero and its live image is left alone. This matters
more than it did in the fork, precisely because change 1 arms
tracking on far more render targets. Dropping the gate outright, as
the fork did, would let a target sampled under a format tag that the
availability map does not match be overwritten once with whatever
sits in guest memory.
The existing content fingerprint still suppresses redundant uploads,
and MarkSampledImagesInitialized records the uploaded generation, so
a rewritten surface re-uploads exactly once per guest write burst.
Not ported: the fork's third part added a PeekDirty guard to the
parse-time snapshot fast path in AgcExports. It is superseded. That path
now calls IsGuestImageUploadKnown, which already compares
_cpuBackedUploadGenerations against the tracker's write generation - a
monotonic value that survives another owner consuming the dirty flag,
unlike PeekDirty, which both EvictDirtyCachedTextures and
SyncCpuWrittenGuestImages clear. Guest images with no generation entry
are covered instead by SyncCpuWrittenGuestImages. Adding a non-consuming
PeekDirty there would also make every draw between a CPU write and the
next flip fall through to a full texel re-read of the surface (33 MiB
for a 4K sheet), since Track re-arms without clearing the dirty flag.
The fork's promotion-path Track ("vulkan.cpu-backed-image") is likewise
superseded: AgcExports already arms every sampled texture's backing
extent as "agc.decoded-texture" before reading its texels.
Both decisions are extracted as pure internal predicates so they can be
unit-tested; the Vulkan device code around them needs a real device.
sceAgcDriverSubmitAcb submissions never produced a completion interrupt.
NotifySubmittedDcbCompleted returned early for anything that was not the
graphics queue, so an ACB reaching its ordered-queue fence published
nothing. UE 4.27's dynamic-resolution GPU-timing heuristic parks the game
thread on exactly that interrupt, so the render side never advanced and
Silent Hill: The Short Message deadlocked after its first frame.
Give every queue a CompletionEventId: 0 for graphics (what it already
published) and the owner handle from sceAgcDriverSubmitAcb rdi for a
compute queue, which is the same value the guest passes to
sceAgcDriverAddEqEvent. Publish under that ident from the existing fence
point, which both PumpSubmittedQueue and ResumeSuspendedDcb already reach
only after the submission is fully parsed.
Delivery is synchronous on the ordered guest-action queue rather than on a
ThreadPool hop with a sleep. That action runs after the logical queue has
flushed and waited for its latest fence, which is the moment hardware
would raise end-of-pipe. Deferring past it can only make the interrupt
late and reorder it against registration changes.
Gating: the per-queue completion event is unconditional, because
completion interrupts do fire on real hardware and because delivery is
registration-gated -- TriggerRegisteredEvents only queues onto equeues
that registered this exact (ident, graphics filter) pair, and
sceAgcDriverAddEqEvent is the only producer of graphics registrations. A
title that never registers its ACB owner handle observes no change.
SHARPEMU_AGC_SUBMIT_COMPLETION_EVENT is left to gate only the broad
ident-ignoring fan-out (TriggerRegisteredEventsDistinct), which is a
compatibility guess rather than hardware behavior; it also stays scoped to
the graphics queue where it was measured, so enabling the flag does not
newly fan out across compute queues.
The scalar evaluator gave every buffer_load_format instruction its own
attribute location. Two things multiply those: the CFG walk visits one
instruction on several paths, and an uber vertex shader fetches the same
stream from every material branch. UE's larger shaders reached 56 bindings
from 8 distinct views, and one reached 701 from 5.
Metal caps a vertex function at 31 attributes, so MoltenVK failed the MSL
compile with "'attribute' attribute parameter is out of bounds" and the
surrounding vkCreateGraphicsPipelines returned ErrorInitializationFailed.
Every draw using those pipelines was dropped, which is why Silent Hill:
The Short Message rendered a black scene. The vertex buffer count drove
Metal's buffer indices out of range too, giving the companion
"cannot reserve 'buffer' resource location at index 0" failures.
Key attributes by the guest stream view they read - absolute element
address, record stride and format - and alias every other fetch that
resolves to the same view onto that binding, so both translators map
those instruction PCs to one input variable. On PPSA10112 this takes the
worst shader from 56 attributes to 8 and pipeline failures from 840 to 0.
Ported from origin/fix/view-compatible-guest-images 7fb8fdf.
Rendering as sRGB and ImageLoad/Store-ing as UNORM at the same guest
address are the same surface accessed through different number formats.
Recreating the guest image per number format ping-pongs content between
two VkImages and loses the rendered pixels on every transition; the
mutable-format image now accepts the counterpart identity and serves it
through alias views. The commit names AvPlayer movie copies as the
pattern that needs this.
Adapted for this base: GetOrCreateGuestImage has since grown resolution
scaling and 3D/array support, so the alias accept is folded into the
current predicate (LogicalWidth/LogicalHeight/LogicalDepth/Type) rather
than the old Width/Height pair, and the storage-counterpart widening is
placed before the physical-dimension computation. The helper functions it
relies on (GetStorageImageFormat, IsCompatibleViewFormat) already existed.
NID znaWI0gpuo8 was mapped to sceUserServiceGetUserName as a "title-captured
alias". It is not that symbol. Recomputing the NID of every catalogued name
(base64 of the reversed first eight sha1 bytes of name+salt) resolves
znaWI0gpuo8 to scePadGetTriggerEffectState, and sceUserServiceGetUserName
hashes to 1xxcMiGu2fo instead. Auditing all 1087 export declarations the same
way found this to be the only NID whose declared name is wrong.
The consequence was not a missing export but a wrong one: the user-service
handler rejected the pad's arguments and returned
SCE_USER_SERVICE_ERROR_INVALID_PARAMETER about eighteen thousand times per
run in PPSA10112, so every poll fell back to a cached button bitmask. It
also hid the calls from every search for pad activity, which is why this
title was believed never to touch scePad at all.
The state size is taken from the caller's own frame rather than assumed: the
guest points the out-param at rbp-0x30 and stores its stack cookie at
rbp-0x28, leaving eight bytes for the state. Writing the sixteen the frame
superficially suggests would land on the cookie and fail the guest's stack
check - the same failure this codebase has already hit three times from
oversized HLE writes - so the test pins the size by asserting the cookie
survives.
No host pad exposes DualSense adaptive-trigger feedback, so the neutral
all-zero state is reported as success, which lets the caller take its normal
path instead of the fallback.
* [media] merge bink into shared ffmpeg bridge
* [avplayer] decode in process and fix stream info size
* [font] add glyph and teardown exports
* [build] bump ffmpeg runtime to 3b502d4
* [font] add glyph and teardown exports
* [build] bump ffmpeg runtime to 3b502d4
* [avplayer] decode in process
* [font] add glyph and teardown exports
* [build] bump ffmpeg runtime to 3b502d4
* 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>
* feat(gpu): GPU compute detile for guest tiled textures (Vulkan + Metal)
Move RDNA2 exact-XOR deswizzle (swizzle modes 5/9/24/27, 4bpp) off the CPU
onto a GPU compute pass. GnmTiling.GetDetileParams resolves the shared
addressing into DetileParams; the CPU fallback and both GPU kernels consume
the same params so they never disagree.
Vulkan (verified bit-exact on NVIDIA): SpirvFixedShaders.CreateDetileCompute
hand-emits the SPIR-V kernel; VulkanDetilePass.RecordDetile records the
dispatch into the async batch command buffer (never a blocking submit on the
render thread) with transients retired via fence; VulkanDetileSelfTest
(SHARPEMU_DETILE_SELFTEST=1) checks both entry points against the CPU detile.
Metal (Mac-untested): detile_compute.msl (detile_cs) + MetalDetilePass mirror
the Vulkan pass. The active Metal path CPU-detiles via the new
GnmTiling.DetileWithParams when a texture arrives packaged (empty RgbaPixels +
TiledSource/Detile), keeping Metal correct under default-on with no regression;
wiring MetalDetilePass live is the remaining on-device step.
Flags: GPU detile is default-on (SHARPEMU_GPU_DETILE=0 disables);
[GPU-DETILE] diagnostics gated behind SHARPEMU_LOG_GPU_DETILE=1.
Tests: 17 detile unit tests pass, incl. DetileWithParams and GetDetileParams
each matching TryDetile bit-for-bit across all supported modes/bpp, plus a
SPIR-V structural-validity test.
* feat(gpu): GPU compute detile for guest tiled textures (Vulkan + Metal)
Move RDNA2 exact-XOR deswizzle (swizzle modes 5/9/24/27, 4bpp) off the CPU
onto a GPU compute pass. GnmTiling.GetDetileParams resolves the shared
addressing into DetileParams that the CPU fallback and both GPU kernels
consume, so they never disagree; everything else keeps the CPU path.
Vulkan (verified bit-exact on NVIDIA): SpirvFixedShaders.CreateDetileCompute
hand-emits the kernel; VulkanDetilePass.RecordDetile records into the async
batch command buffer (never a blocking submit on the render thread) with
transients retired via fence, falling back to CPU detile on failure.
VulkanDetileSelfTest (SHARPEMU_DETILE_SELFTEST=1) checks both entry points.
Metal (Mac-untested): detile_compute.msl + MetalDetilePass mirror the Vulkan
pass; the active Metal path CPU-detiles via GnmTiling.DetileWithParams so it
stays correct under default-on. Wiring MetalDetilePass live is a follow-up.
Flags: default-on (SHARPEMU_GPU_DETILE=0 disables); diagnostics behind
SHARPEMU_LOG_GPU_DETILE=1. Adds 17 passing detile unit tests.
* Fix: added support layered texture support for the GPU-Detiling.
* Fix: Added support for BlockTable (1 / 4 / 8 (Morton/Z-order))
* feat: added support for 8 and 16 bpp (bytes per element)
* Fixed a build failure specific to this branch
---------
Vector-mesh UI text samples type-10 volume LUTs; treat MIMG DIM=2 as
Dim3D and transport depth through AGC and Vulkan so Z slices no longer
collapse into a single 2D plane.
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.
Co-authored-by: Cursor <cursoragent@cursor.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>
* 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.
Co-authored-by: Cursor <cursoragent@cursor.com>
* chore: retrigger gameplay CI for PR #536
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* 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.
Co-authored-by: Cursor <cursoragent@cursor.com>
* chore: retrigger gameplay CI for PR #534
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Titles that stack-allocate AudioOut2 outs next to the frame canary were
corrupted by oversized or mistyped HLE writes; keep ContextPush pacing.
Co-authored-by: Cursor <cursoragent@cursor.com>