sharpemu/src/SharpEmu.Libs/VideoOut
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
..
BufferUploadProfile.cs Alpha Rebuild Progress (#887) 2026-09-20 04:09:27 +03:00
FlipProgressTracker.cs Fix Vulkan presenter synchronization and frame handling issues (#747) 2026-08-03 00:36:33 +03:00
GuestBlendStateNormalizer.cs Vulkan: fix guest storage image and render-state handling (#332) 2026-07-18 02:54:52 +03:00
GuestImageUploadPayloadDiagnostics.cs A vplayer fix (#821) 2026-08-17 00:57:42 +03:00
HostDisplayCatalog.cs Sdl backend (#670) 2026-07-28 03:33:26 +03:00
HostVideoOptions.cs [GPU] Add internal render resolution scaling (#1038) 2026-10-07 11:47:58 +02:00
PerfOverlay.cs Alpha Rebuild Progress (#887) 2026-09-20 04:09:27 +03:00
PerformanceOverlayState.cs Alpha Rebuild Progress (#887) 2026-09-20 04:09:27 +03:00
PngSplashLoader.cs Fix PNG chunk CRC validation (#241) 2026-07-16 00:46:43 +03:00
RenderDocCapture.cs [GUI/CLI] Add option to disable Vulkan implicit layers (#900) 2026-09-23 16:08:19 +03:00
RenderPhaseProfile.cs Perf computed shaders (#1013) 2026-10-03 04:49:43 +03:00
SdlHostWindow.cs Alpha Rebuild Progress (#887) 2026-09-20 04:09:27 +03:00
SubmissionFlowProfile.cs Alpha Rebuild Progress (#887) 2026-09-20 04:09:27 +03:00
VideoOutDisplayClock.cs Alpha Rebuild Progress (#887) 2026-09-20 04:09:27 +03:00
VideoOutExports.FlipRequests.cs [macOS] Fix the Rosetta GC wedge, a CPU-flip buffer-wait deadlock and frozen host movies (#1051) 2026-10-07 11:02:17 +02:00
VideoOutExports.cs [GPU] Restore scene visibility and half-wave shuffles (#1025) 2026-10-07 11:21:15 +02:00
VulkanHostBufferPool.cs fix(gta): restore wiped GTA foundation and gameplay path (PPSA04264) (#650) 2026-07-27 01:58:55 +03:00
VulkanPipelineCacheStorage.cs Perf computed shaders (#1013) 2026-10-03 04:49:43 +03:00
VulkanStorageFeedbackTargetResolver.cs Fix for DS,Little Nightmares, Little Nightmares III and Astro Bot shader (#913) 2026-09-27 20:43:07 +03:00
VulkanVideoPresenter.CachedImages.cs [GPU] Add internal render resolution scaling (#1038) 2026-10-07 11:47:58 +02:00
VulkanVideoPresenter.CommandStream.cs [GPU] Avoid command-worker readbacks for clean bytes on GPU-dirty pages (#1059) 2026-10-07 11:21:09 +02:00
VulkanVideoPresenter.Descriptors.cs [GPU] Add internal render resolution scaling (#1038) 2026-10-07 11:47:58 +02:00
VulkanVideoPresenter.Device.Errors.cs Alpha Rebuild Progress (#887) 2026-09-20 04:09:27 +03:00
VulkanVideoPresenter.Device.Setup.cs [SpirvTranslator/Vk] Cheaper guest buffer loads and f16 conversion, gated on device probes (#1035) 2026-10-07 10:51:57 +02:00
VulkanVideoPresenter.Device.Teardown.cs Perf computed shaders (#1013) 2026-10-03 04:49:43 +03:00
VulkanVideoPresenter.Draws.Recording.cs Fix for DS,Little Nightmares, Little Nightmares III and Astro Bot shader (#913) 2026-09-27 20:43:07 +03:00
VulkanVideoPresenter.GuestBuffers.cs Alpha Rebuild Progress (#887) 2026-09-20 04:09:27 +03:00
VulkanVideoPresenter.GuestDraws.cs Alpha Rebuild Progress (#887) 2026-09-20 04:09:27 +03:00
VulkanVideoPresenter.GuestSubmissions.cs Perf computed shaders (#1013) 2026-10-03 04:49:43 +03:00
VulkanVideoPresenter.HostBuffers.cs Alpha Rebuild Progress (#887) 2026-09-20 04:09:27 +03:00
VulkanVideoPresenter.HostMovie.cs Astrobot / Demon's soul performance improvement (#955) 2026-09-30 18:14:21 +03:00
VulkanVideoPresenter.PipelineCacheShards.cs Perf computed shaders (#1013) 2026-10-03 04:49:43 +03:00
VulkanVideoPresenter.Pipelines.cs [SpirvTranslator/Vk] Cheaper guest buffer loads and f16 conversion, gated on device probes (#1035) 2026-10-07 10:51:57 +02:00
VulkanVideoPresenter.Present.Frames.cs Perf computed shaders (#1013) 2026-10-03 04:49:43 +03:00
VulkanVideoPresenter.Present.Hdr.cs Vk version update (#897) 2026-09-22 17:45:51 +03:00
VulkanVideoPresenter.Present.Images.cs Alpha Rebuild Progress (#887) 2026-09-20 04:09:27 +03:00
VulkanVideoPresenter.Present.Overlay.cs Vk version update (#897) 2026-09-22 17:45:51 +03:00
VulkanVideoPresenter.Present.Swapchain.cs [Gpu] Expose HDR output support and handle PQ buffer attribute changes 2026-10-02 03:37:17 +03:00
VulkanVideoPresenter.Present.cs Page fixes (#1023) 2026-10-04 19:07:37 +03:00
VulkanVideoPresenter.RenderLoop.cs Perf computed shaders (#1013) 2026-10-03 04:49:43 +03:00
VulkanVideoPresenter.Rendering.cs [GPU] Restore half-float arithmetic and image readback state (#1024) 2026-10-07 10:59:57 +02:00
VulkanVideoPresenter.Scheduler.cs [GPU] Restore half-float arithmetic and image readback state (#1024) 2026-10-07 10:59:57 +02:00
VulkanVideoPresenter.ShaderPrewarm.cs [SpirvTranslator/Vk] Cheaper guest buffer loads and f16 conversion, gated on device probes (#1035) 2026-10-07 10:51:57 +02:00
VulkanVideoPresenter.cs [SpirvTranslator/Vk] Cheaper guest buffer loads and f16 conversion, gated on device probes (#1035) 2026-10-07 10:51:57 +02:00
WindowPollProfile.cs Alpha Rebuild Progress (#887) 2026-09-20 04:09:27 +03:00
WindowsGpuUsage.cs Alpha Rebuild Progress (#887) 2026-09-20 04:09:27 +03:00