Go to file
kuba 38f7196470
[GPU] Add internal render resolution scaling (#1038)
* [VideoOut] Add an internal render resolution scale option

Adds the host-side setting an internal-resolution implementation needs:
--render-scale on the command line, SHARPEMU_RENDER_SCALE for scripted
runs, and a global and per-game choice in the GUI. The value is a host
resolution multiplier of the guest render targets, normalized to a
hundredth in [0.25, 2] so the command line, the GUI and the environment
agree bit for bit; the renderer compares scales when it decides whether
two views of the same guest memory match.

RenderScalePolicy holds the decision rule. It is a pure function of the
guest image description, so every view, alias, copy and descriptor of
one guest range reaches the same answer without consulting the cache.
Only screen-class, single-level, single-sample, uncompressed 2D render
and depth targets scale; block grids, multisample footprints, HTile and
DCC coverage, mip chains, cube and array faces, asset tilings and small
surfaces (shadow maps, lookup tables, eye-adaptation readbacks) keep
their guest resolution. The environment variable wins over the stored
setting so test runs do not depend on the user's configuration.

No renderer consumes the scale yet; a scale of one is the current
behaviour everywhere.

* [GPU] Hold scalable guest images at a host render resolution

The backing of an image the scaling rules accept is created at
ceil(guest * scale) while its ImageDescription keeps the guest geometry,
so the cache, the overlap rules and the page tracker go on reasoning in
guest bytes.

Everything that moves guest bytes now goes through a guest-resolution
twin of the scaled image: an upload fills the twin from the copy regions
the tiler built and blits into the backing, a download blits the backing
into the twin and copies out of it. A copy whose two images disagree on
host resolution runs at guest resolution the same way, so callers keep
describing rectangles in guest pixels; the destination seeds its twin
first because a partial copy is blitted back whole. The multisample
depth conversion takes a guest-sized source for the same reason, and the
resolve region crosses into the destination's resolution instead of
silently resolving the top-left corner.

Two fallbacks keep correctness ahead of the saving. A format that cannot
blit keeps its guest resolution, since the twin could never reach it.
A storage image drops back to guest resolution the first time a compute
shader binds it: the dispatch grid does not shrink with the host image,
so the shader would write it with holes above 1.0 and redundantly below.
The guest range is remembered, so every later image over that memory is
created unscaled too.

* [GPU] Scale the render area, viewport and scissor with the attachments

A resolved target now reports the host extent of its attachment beside
the guest one, and the three places that size rasterization follow it:
the dynamic rendering area, which also bounds every load-op clear; the
guest viewport transform; and the guest scissor, whose edges round
outward so no guest pixel the game asked for loses host coverage.

All attachments of a pass share one rule, so the first bound target
decides the factor.

The clip-disable path needs care because the vertex program bakes the
viewport transform against a reference extent. Dividing that reference
by an upscale keeps the host viewport (reference x scale) inside the
device limit while the baked transform stays scale independent, so the
same program maps guest pixels onto host positions at either resolution.
At a scale of one the reference is the device limit, exactly as before.

* [SpirvTranslator] Translate pixel positions and image coordinates across the render scale

A program expresses its pixel position, its integer image coordinates
and the sizes it queries in guest pixels, but the host may hold the
image behind any of them at another size. Which images are scaled is a
per-draw fact, so the factors travel in shader data rather than in a
permutation: the coordinate factor, its reciprocal, a 64-bit mask of
scaled image resources and the factor the pixel position is divided by.

With that:

- gl_FragCoord is divided by the attachments' factor as it is loaded, so
  POS_X/POS_Y, POS_FIXED_PT and everything derived from them - screen
  UVs above all - stay in guest pixels.
- An integer image coordinate is mapped onto host texels through the
  bound image's factor. Only the two scaled axes move; an array layer or
  a volume slice is not a pixel.
- A resource-info query reports the guest size, because the program
  derives coordinates and loop bounds from it.

A select against the mask makes an unscaled binding cost one
instruction, and the layout only carries the dwords when the scale is
not one, so nothing changes at native resolution.

* [GPU] Keep one host resolution across the attachments of a pass

A rendering scope has one render area, one viewport and one scissor, so
its attachments have to agree on a host resolution. They disagree when
one of them cannot be scaled at all - a depth target with a stencil
plane next to a scalable colour target, say - and the pass then renders
a fraction of its area. The draw now drops every scaled attachment back
to guest resolution and resolves its targets again; the guest ranges are
remembered, so the decision converges after one draw and cannot
oscillate.

That fallback only works if the executor knows what the cache actually
gave it, which is not what the scaling rules would answer: a demoted
range still looks scalable to them. The resolved targets therefore carry
the image's own factor, and the render area, viewport, scissor and the
depth/stencil copy extent read it from there.

Two rules change with it. DCC only describes guest bytes the host never
stores, so a colour target that carries it can still be scaled; HTile
encodes guest depth blocks the renderer reads back as clear state and
stays native. And a storage image only drops back when the program
actually writes it, since a read-only load is mapped correctly.

Scaling now also requires a backend that installed the format
predicate - the Vulkan device - so the Metal host is unaffected.

* [Docs] Describe internal resolution scaling and its limits

Replaces the note saying arbitrary internal resolution scaling is not
implemented: it is, for screen-class render and depth targets. Records
what the renderer translates (rasterization, shader coordinates, guest
transfers, presentation), the exact rule for what scales, every case
that falls back to guest resolution, the artefacts measured on Silent
Hill, and the per-scope GPU times at 50, 100 and 200 percent.

* [SpirvTranslator] Preserve guest texel offsets at scaled resolutions
2026-10-07 11:47:58 +02:00
.github [readme] New screenshots 2026-10-06 19:07:06 +03:00
LICENSES [GUI] Redesign options page (#699) 2026-07-30 12:58:22 +03:00
assets/images [asset] upload transparent logo image 2026-08-03 10:43:43 +03:00
docs [GPU] Add internal render resolution scaling (#1038) 2026-10-07 11:47:58 +02:00
scripts Alpha Rebuild Progress (#887) 2026-09-20 04:09:27 +03:00
src [GPU] Add internal render resolution scaling (#1038) 2026-10-07 11:47:58 +02:00
tests [GPU] Add internal render resolution scaling (#1038) 2026-10-07 11:47:58 +02:00
tools Alpha Rebuild Progress (#887) 2026-09-20 04:09:27 +03:00
.editorconfig [dotnet] configure local nuget package cache 2026-07-04 19:12:18 +03:00
.gitignore [AGC] Fix arena/fence tracking stalls and recover lost GPU progress (#770) 2026-08-07 14:37:09 +03:00
CONTRIBUTING.md Enhance contribution guidelines with PR expectations 2026-07-23 01:40:00 +03:00
Directory.Build.props chore: bump version to 0.0.5-nexus (#1018) 2026-10-03 05:15:35 +03:00
Directory.Packages.props [Font] Fix font face creation (#1010) 2026-10-03 05:04:56 +03:00
LICENSE.txt initial commit 2026-03-11 15:48:28 +03:00
README.md [readme] New screenshots v2 2026-10-06 19:07:24 +03:00
REUSE.toml [GUI] Redesign options page (#699) 2026-07-30 12:58:22 +03:00
SharpEmu.slnx Sdl backend (#670) 2026-07-28 03:33:26 +03:00
global.json [dotnet] remove lock files (#419) 2026-07-19 01:26:01 +03:00
nuget.config [dotnet] configure local nuget package cache 2026-07-04 19:12:18 +03:00

README.md

SharpEmu

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


Join our Discord

Join our official Discord server for development updates, compatibility discussions, support, and community chat.


Support SharpEmu


[!IMPORTANT] Official channels: Only sharpemu.app and the links listed in this GitHub repository are affiliated with SharpEmu. Any other websites, accounts, or donation pages are unofficial and unauthorized.

[!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

Demon's Souls Remake ASTRO BOT
DeS screenshot Astro Bot
ASTRO's PLAYROOM Dead Cells
Astro's Playroom Dead Cells
God of War: Sons of Sparta Tomb Raider V Remastered
GoW SOS Tomb Raider V

Status

The emulator can currently load the eboot.bin of real games, execute native CPU instructions, and partially handle gpu-related functionality. Included 3D games.

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.

Or command line;

Windows PowerShell:

.\SharpEmu.exe "C:\path\to\game\eboot.bin" --log-to-file

Linux and macOS:

chmod +x ./SharpEmu

./SharpEmu "/path/to/game/eboot.bin" --log-to-file

SharpEmu supports environment variables that can be configured from the GUI. Undocumented variables are listed here: docs/sharpemu-gui-undocumented-env-vars.md

You can set them per game or globally in the GUI, or pass them directly through the CLI.

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