angleyanalbedo f8a826ec1b fix(agc,video): CMASK/DCC metadata state machine , remove heavy heavy motion trails in DeadCell (#836)
* fix(agc): add support for CMASK fast clear in rendering process

* fix(agc): prevent stale cross-frame label writes from bypassing WAIT_REG_MEM

Add frame-ID tracking to GpuWaitRegistry so that WAIT_REG_MEM in frame N+1
is not satisfied by a label written in frame N. Previously, a label that
persisted in guest memory from the previous frame could satisfy a new
WAIT_REG_MEM immediately, causing the waiting DCB to bypass its fence and
execute out of order.

Changes:
- GpuWaitRegistry: add _labelFrameIds, _currentFrameId, AdvanceFrame(),
  IsLabelFresh(); RecordProduced now stamps the frame ID on each write
- AgcExports: call AdvanceFrame() at RFlip (frame boundary);
  HandleSubmittedWaitRegMem checks IsLabelFresh before bypassing

This is one piece of the Dead Cells character visibility fix (issue #833).
The cross-frame label reuse could cause composite passes to execute before
character-layer passes, resulting in invisible characters.

* fix(video): simulate CMASK 'all clear' at frame boundary to prevent trails

On real PS5, CMASK is reset to 'all clear' at each frame boundary,
so render targets are effectively cleared. SharpEmu did not implement
this behavior, causing GBuffer targets to LOAD stale data from the
previous frame, resulting in visible trails/ghosting.

Reset Initialized=false for all offscreen guest images at the present
boundary (when _currentFrameSlot changes). This ensures every render
target starts each frame with LoadOp.Clear, matching the hardware's
CMASK behavior.

This is the trail fix for Dead Cells (issue #833), complementing the
cross-frame label staleness fix in GpuWaitRegistry.

* fix(video): only reset render targets (not textures) for CMASK simulation

Previous commit 89b4610 reset Initialized for ALL guest images, including
textures and storage images, causing a completely black screen. Only images
with a RenderPass (actual color render targets) should be reset, as CMASK
'all clear' only applies to color render targets, not sampled textures.

* Revert "fix(video): simulate CMASK 'all clear' at frame boundary to prevent trails"

This reverts commit 89b4610a015619848e4000372822dca1c08051ff.

* fix(agc): implement CMASK state machine for render target clearing

Implement CMASK (Color Mask) hardware behavior based on shadPS4's approach:

1. Track CMASK addresses from CB_COLORn_CMASK registers
2. Detect compute shaders that write to CMASK addresses (IsComputeMetaClear
   heuristic: no bitwise XOR in shader = clear shader)
3. Mark CMASK as 'all clear' when compute shader writes to it
4. EliminateFastClear mode now checks CMASK state before clearing

This addresses the trail/ghosting issue in Dead Cells (issue #833) where
642x362 GBuffer targets were never cleared after first use, causing stale
data from previous frames to persist.

Reference: shadPS4's IsComputeMetaClear + EliminateFastClear implementation.

* fix(agc): implement CMASK state machine for render target clearing

Based on shadPS4's PM4 implementation, add CMASK (Color Mask) hardware
behavior tracking:

1. TrackCmaskAddresses: Read CB_COLORn_CMASK registers to get CMASK addresses
2. CheckCmaskWrite: When DMA fill targets CMASK address with value 0,
   mark CMASK as 'all clear' (shadPS4's FillBuffer logic)
3. EliminateFastClear: Check CMASK state before clearing - only clear
   if CMASK is 'all clear', then mark as 'dirty'
4. DMA fill: Call TrackCmaskAddresses before processing to ensure
   CMASK addresses are registered when DMA fills happen

This addresses the trail/ghosting issue in Dead Cells (issue #833) where
642x362 GBuffer targets were never cleared after first use.

Reference: shadPS4's IsComputeMetaClear + EliminateFastClear + FillBuffer.

* refactor(agc): remove diagnostic CMASK traces from hot path

Remove 4 diagnostic TraceAgcShader calls that were added during CMASK
investigation:
- agc.cb_regs=[...] - allocated List<string> + string.Join on every draw
- agc.cmask_track - per-slot interpolated string on every draw
- agc.cmask_write - per-DMA-fill interpolated string
- agc.eliminate_fast_clear - per-draw interpolated string

These were debugging probes and are no longer needed.

* fix(agc): sync constant-fill zero writes to Vulkan render targets

Dead Cells GBuffer trails: the constant-fill compute kernel
(TrySubmitConstantFillKernel) wrote zeros to guest memory but never
invalided the host Vulkan GuestImageResource that backs the render
target, so the GBuffer pass kept LoadOp.Load stale previous-frame pixels.

After the guest write, request a guest color clear尷 ... clear for the
destination address (RequestAgentColorClear projection (clear)) so the next render pass
uses LoadOp.Clear. The pending clearandray mechanism already exists; the
fill kernel was simply bypassing it.

* Remove AGC lifecycle debug probes

Remove transient render-target lifecycle and indirect draw debug instrumentation from AgcExports. The change strips the noisy console probing while keeping the active render-target tracking logic intact for draw sequencing and validation.

* fix(video): clear frame-stale MRT groups at guest flip boundary

On hardware a colour surface whose fast-clear metadata is in reset
state reads back as the CB clear value instead of stale memory, so
games can leave per-frame MRT groups uncleaned and rely on that
implicit initialization. With no metadata layer, such a target keeps
whatever touched it last; when the group shares addresses with the
compositor's output, the entire finished previous frame bleeds
through every region the new frame does not repaint (Dead Cells
dungeon trails / ghosted characters).

Arm a reset at the guest's own flip command - the authoritative
frame boundary inside the submission stream - and let the first
multi-attachment colour group of the fresh frame consume it,
starting from LoadOp.Clear. One arm per flip yields exactly one
reset per guest frame regardless of CPU/GPU pipelining; later
groups keep load semantics so intra-frame pass chaining is
untouched. CPU-backed images are never touched.

Mirrors shadPS4's meta-state-driven attachment.is_clear at
render-pass begin (vk_rasterizer.cpp BeginRendering).

* fix(agc): correct CbColor0Cmask register offset and add EXT support

CbColor0Cmask was 0x320 (CMASK_SLICE, tile_max:14) instead of 0x31F
(CMASK_BASE_ADDRESS). TrackCmaskAddresses read the slice count instead
of the base address, so CMASK registration always produced garbage or
zero — the entire meta-state chain starved for every game.

Fix: 0x320 → 0x31F. Add CbColor0CmaskBaseExt (0x398) and decode the
full 48-bit address: ((ext & 0xFF) << 40) | ((low & 0x1FFFFFFF) << 8).

Phase 0 probe confirmed Dead Cells programs neither CMASK nor DCC
registers (all zeros) — it relies on unified memory semantics where
unwritten surfaces read as zero. The register offset fix is still
needed for games that do use CMASK metadata.

* feat(agc,video): CMASK/DCC meta-state machine with CLEAR WORD support

Replace the flat _cmaskClearedState dictionary with a proper meta-state
ledger that separates registration, clearing, and dirtying:

- MetaSurfaceInfo keyed by colour-buffer address (not meta address)
- Reverse map _cmaskToColorBuffer for fill/compute write detection
- TrackCmaskAddresses reads both CMASK (0x31F) and DCC (0x325) with
  EXT high-bit decoding; prefers CMASK, falls back to DCC
- CLEAR_WORD captured at registration time, passed through to
  BeginTranslatedRenderPass as VkClearValue
- EFC checks specific surface (not 'any cleared → clear slot0'),
  dirties only that surface (not entire table)
- CheckCmaskWrite uses reverse map for O(1) lookup
- Presenter bind loop queries IsMetaClearedForSurface → LoadOp.Clear
- _metaStateOverridesFlipArm flag gates flip-arm for gradual retirement

Phase 0 probe confirmed Dead Cells programs neither CMASK nor DCC
(all registers zero) — flip-arm remains the correct fix for that game.
The meta-state machine serves games that do use CMASK/DCC metadata.

* fix(agc,video): implement surface clearing at guest flip boundary

* refactor(video): remove flip-arm heuristic, meta-state machine fully replaces it

The flip-arm (_frameColorResetArmed) was a heuristic that cleared the
first multi-attachment colour group at guest flip boundary.  The
CMASK/DCC meta-state machine now handles all clearing: at flip time
MarkAllSurfacesCleared() marks every registered surface as cleared;
at bind time IsMetaClearedForSurface() triggers LoadOp.Clear and
consumes the state.  This replaces the flip-arm with a per-surface
state machine that correctly handles both explicit clears (DMA fill,
compute, EFC) and implicit frame-boundary resets.

Also fixed a bug where TrackCmaskAddresses overwrote IsCleared to
false on every call, defeating the frame-boundary reset.  Now
preserves existing IsCleared state when re-registering.

* Thread-safe meta-surface state & meta-clear decode

Add synchronization for metadata state: introduce _metaSurfaceGate and guard accesses to _metaSurfaces and _cmaskToColorBuffer in AgcExports to avoid concurrent-dictionary corruption and ensure small critical sections. Preserve cleared state only when metadata binding matches during re-registration. Make Gen5 texture format constants internal. Update logic to set/consume IsCleared under lock and check CMASK nearby windows safely.

Decode meta clear values in VulkanVideoPresenter: skip CPU-backed targets for meta clears, add UnpackMetaClearValue and HalfToFloat to convert CLEAR_WORD0/1 into proper ClearColorValue for R8G8B8A8_UNORM and R16G16B16A16_FLOAT formats (with an 8_8_8_8 fallback). This ensures correct clear colours and thread-safe metadata handling.
2026-08-24 13:56:44 +03:00
2026-08-18 00:00:28 +03:00
2026-07-28 03:33:26 +03:00
2026-07-19 01:26:01 +03:00
2026-03-11 15:48:28 +03:00
2026-07-30 12:58:22 +03:00
2026-07-28 03:33:26 +03:00

SharpEmu

An experimental PlayStation 5 emulator for Windows, Linux and macOS.


Support SharpEmu


Note

SharpEmu supports Windows x64, Linux x64, and macOS x64. Apple Silicon Macs can run the macOS x64 build through Rosetta 2, and Windows on ARM devices (e.g. Snapdragon) can run the Windows x64 build through Windows' built-in x64 emulation.

Warning

SharpEmu is an experimental PS5 emulator developed from scratch in C#. The current focus is on accuracy and infrastructure setup rather than game-specific compatibility.

Info

SharpEmu is an emulator project currently in its early stages of development.

This project is developed purely for research and educational purposes. There are no commercial goals associated with it. We enjoy learning about system architecture and reverse engineering.

SharpEmu focuses exclusively on the PlayStation 5.
Our goal is not to emulate PS4 games, as there is already an excellent emulator dedicated to that platform: ShadPS4.

Games Tested

Demons Souls Remake Dreaming Sarah
Bloodborne screenshot Dreaming Sarah
Void Terrarium Dead Cells
Void Terrarium Dead Cells

Status

The emulator can currently load the eboot.bin of real games, execute native CPU instructions, and partially handle kernel-related functionality. However, several critical components are still missing.

Current capabilities include:

  • Loading eboot.bin and .elf files
  • Executing native CPU instructions
  • Reading basic game metadata (title, version, etc.)
  • Loading system modules (prx / sys_module)
  • Partial support for some kernel functions
  • Fiber and AMPR exports
  • PlayGo scenarios
  • Initial loading game files
  • Shader/resource submits and AGC initial
  • Video outputs in some games

Some games have reached like sceVideoOut and AGC stages.

SharpEmu supports Windows, Linux, and macOS hosts. Video output uses Vulkan on Windows and Linux, and MoltenVK on macOS. Platform support is still experimental, so compatibility and performance vary by game, operating system, and GPU driver.

Using

Download the release archive for your operating system, extract it, and launch SharpEmu with the path to a legally obtained game's eboot.bin.

Windows PowerShell:

.\SharpEmu.exe "C:\path\to\game\eboot.bin" 2>&1 |
  Tee-Object -FilePath "SharpEmu.log"

Linux and macOS:

chmod +x ./SharpEmu

./SharpEmu "/path/to/game/eboot.bin" 2>&1 |
  tee SharpEmu.log

A Vulkan-capable GPU and current graphics driver are required. The macOS release includes the MoltenVK Vulkan implementation.

Important

This project does not support or condone piracy.
All games used during development and testing are dumped from consoles that we personally own.
Users are expected to use legally obtained copies of their games.

Build

  1. Install the .NET SDK version specified in global.json.
  2. Clone the repository: git clone https://github.com/sharpemu/sharpemu.git
  3. Open the solution file (SharpEmu.slnx) in VSCode.
  4. Build the project: dotnet build or dotnet publish
  5. Build artifacts will be located in the artifacts directory.

Disclaimer

SharpEmu is an experimental emulator intended for research and educational purposes.

This project does not contain any copyrighted system firmware, game data, or proprietary PlayStation assets.

Special Thanks

The following projects were extremely helpful during development:

  • ShadPS4
    Helped with understanding the basic architecture of the PlayStation 4.

  • Kyty
    One of the few PS5 emulator projects available and very useful for studying native code execution.

  • Ryujinx
    Provided valuable references for filesystem handling and low-level C# implementation patterns.

License

Support

Support SharpEmu via GitHub Sponsors or cryptocurrency. Every contribution helps fund ongoing development and long-term maintenance. GitHub Sponsors is the preferred way to support the project, but cryptocurrency donations are also appreciated.

ETH/USDT

0xF315F5d986c790bB3A58DbE60F1B2760997dEd82

BTC

bc1qmr9k8899njys5ny63xsues4jgmkk96erslrkmv

Contributing

Before opening an issue or pull request, please read our contribution guidelines:

CONTRIBUTING.md

The guide covers:

  • Coding style and formatting
  • AI-assisted contributions
  • Pull request expectations
  • Testing guidelines
  • Legal and reverse engineering policy
S
Description
Languages
C# 98%
Python 1.1%
JavaScript 0.3%
CSS 0.3%
HTML 0.2%