Repository navigation
Changes since v0.2.1
Picture
- The game now renders at 1280x800, the Steam Deck panel's own 16:10 shape, not letterboxed 1280x720. The HUD sits at the top and bottom of the taller frame, and the dials keep their shape.
- The classic renderer (Xenos plugin, F9) draws the game's own 16:9 frame, so it no longer shows garbage below the scene at 16:10.
- No more magenta and black patches in the sky during lightning: colors are clamped to the render target's range, as the Xbox 360's EDRAM does.
- The light flares fade over 100 ms instead of a few frames, so they stop blinking when a light goes behind a car.
- The motion blur follows the sustained frame rate, so a paused frame no longer pumps (#1).
- Fixed the stretched triangles that appeared after hours of play (a race in the SDK's write tracking).
Settings
- The port's own settings are in the game's Options menu and in the pause menu, on three pages:
- Display: renderer, aspect ratio, HDR, antialiasing (MSAA 2x to 8x or FSR), FSR resolution, dynamic resolution, frame generation, texture filtering, frame rate, frame latency.
- Driving: the automatic gearbox and the cars' lights.
- Developer: debug keys and diagnostics.
- New frame rate setting: the display's refresh rate, or a half or a third of it (
pgr4_native_present_interval). - A flag on the command line no longer gets saved into the settings file.
Driving
- F5 switches every car's lights on or off. The Driving page sets this for every race (
pgr4_headlights). - The automatic gearbox shifts down sooner and keeps the engine near the top of its range. The Driving page restores the original behaviour (
pgr4_automatic_keep_revs).
Upscaling and frame generation
- New: FidelityFX Frame Generation (
pgr4_native_frame_generation). The game runs at 45 fps and the display shows 90. The HUD is drawn into every frame, never interpolated. - New: dynamic resolution (
pgr4_native_upscaler_target_fps). The upscaler lowers its render size when the GPU falls behind, and learns how much each size change saves. - FSR's image is better:
- It gets the scene's real camera.
- It gets motion for the sky.
- Its motion vectors stay bounded and finite.
- Its color is read in the EDRAM's range.
- Alpha-to-coverage dither (fences) no longer leaves a screen door.
- The motion blur's mask is kept, so the player's car stays sharp.
- The upscaler sizes now come from the 1280x800 frame. The default is 1280x800, antialiasing only.
- One debug switch (F8) for FSR and frame generation, with AMD's watermark for FSR 4.
- F7 and F8 work in every session.
Performance and stability
- The renderer's Direct3D 12 calls now run on a thread of their own. In the Tokyo race in the rain, the render thread's time on draws went from 6.6 to 4.1 ms a frame. Its slowest frames went from 10 to 5.6 ms, which leaves the GPU as the limit.
- Motion vectors are cheaper to compute: each draw finds its previous-frame match in order.
- The upscaled scene's alpha comes in the resolve copy, which saves a full-screen pass (about 0.15 to 0.2 ms of GPU time).
- The pipeline cache keeps what you actually play, so prewarmed pipelines no longer age out.
- Fixed a crash at about one start in four with OptiScaler:
d3d12.dllnow loads at its first call.
PGR4 native renderer
Project Gotham Racing 4 (Title Update #2), recompiled for 64-bit Windows from the Xbox 360
executable, with a native Direct3D 12 renderer. It is tuned for the Steam Deck OLED, at 1280x800
and 90 fps with MSAA and motion blur on. It runs on Windows and, through Proton, on SteamOS and
Linux. It is built with the ReXGlue SDK and fixes from Xenia Canary, on the work of
safzanpirani/pgr4-native (github.com/safzanpirani/pgr4-native).
This package holds no game data. You need your own copy of the game.
What goes where
Put these beside pgr4_recompiled.exe:
game/ the disc's files: default.xex, Game/, UI/ and the rest
game/Content/ Title Update #2's package, and downloadable content if you have it
-
game/: the files extracted from your PGR4 disc (an ISO extractor such as XBOX360 ISO
Extract does this).game/default.xexmust exist. -
game/Content/: the packages as they come from Xbox Live or off a console, unchanged:
- Title Update #2 (version 0.0.2.1),
TU_16L61VP_0000004000000.00000000000G1. The game runs
only with this update, since the code was recompiled from it. Its SHA-256 is
9980cf82c3bbbb32b35c841532c832b5598e99ce50daba8c658645213ab3d9b8. - DLC, the files named by a 42-digit hex ID (Vehicle Pack 1 is
638152C719C45657B6640991BA6375D88A9D437D4D), if you have it.
The first start installs each new package into
userdata/. - Title Update #2 (version 0.0.2.1),
If you have the update's two files extracted instead of its package, put them in a folder named
title-update/ beside the executable. That folder takes precedence over the package. Their
SHA-256:
default.xexp 7e7c672b542dc20d20bed72e27603335701a6eb9f243d2a8a2468bb966ee9401
Pgr4TitleUpdate.bin f4bc47545df5fe8d0301bd4593d3b7b6e3871520f98e5f7249921973781a4b74
The first start creates userdata/ (your save and the shader caches) and logs/ beside the
executable. Keep userdata/ when you update to a new release.
Steam Deck
- In Desktop Mode, copy this folder (with game/ filled in) anywhere, for example
~/Games/PGR4. - Steam > Games > Add a Non-Steam Game to My Library > Browse, select
pgr4_recompiled.exe. - In the shortcut's Properties > Compatibility, force a Proton version (tested: GE-Proton 11-5).
- In Properties > General > Launch Options, enter
PROTON_USE_XALIA=0 DXVK_HDR=1 %command%.
Xalia, Proton's gamepad helper for desktop programs, otherwise takes about a tenth of a CPU
core during races.DXVK_HDR=1lets the game output HDR where the display takes it (the
OLED model, or an HDR TV, with HDR on in Steam's display settings). - Play it from Game Mode. The frame rate follows the display: 90 fps on the OLED, 60 on the
LCD model. Steam's frame limiter works too.
Windows
Run pgr4_recompiled.exe. It needs a GPU with Direct3D 12. Set window_width and
window_height in pgr4_recompiled.toml to your display's resolution. With HDR on in
Windows' display settings the game outputs HDR.
Settings
pgr4_recompiled.toml beside the executable holds the settings, one per line. A flag on the
command line overrides it: in Steam's launch options, %command% --fullscreen=false for one.
The game's Options menu has three pages of the port's own. Display holds the renderer (native or
classic), the aspect ratio, HDR and its brightness, antialiasing (off, MSAA 2x to 8x, or FSR),
FSR's resolution, dynamic resolution and frame generation, texture filtering, the frame rate
(the display's refresh rate, a half or a third of it) and the frame latency. The classic renderer
(the Xenos plugin) draws only the game's own 16:9 frame: a game started on it is 16:9, and at
16:10 the choice of renderer takes effect at the next start. Driving holds the
automatic gearbox's downshifts (the game's, or earlier) and the lights of every car and bike
(the race's, on or off). Developer holds the debug keys, the FSR debug view and the renderer's
diagnostics. A choice marked * takes effect at the next start; the others apply at once. The
pages save to userdata/pgr4_settings.toml, which is read after pgr4_recompiled.toml; delete
it to go back to the release settings.
F5 switches the lights of every car on or off, from what the race gives them, until you change
the Driving page's setting (pgr4_headlights: race, on or off), which holds for every
race. On a Steam Deck, a back grip in the shortcut's controller layout can send F5. The
automatic gearbox shifts down sooner than the original, keeping the engine near the top of its
range; the Driving page (or pgr4_automatic_keep_revs = false) gives back the original's.
Upscaling
The release settings give the 3D scene 4x MSAA (pgr4_native_msaa: 1, 2 for the game's own, 4
or 8). More samples cost GPU time: on a Steam Deck OLED at 90 Hz in the St Petersburg race, with
16x anisotropic filtering, 4x averages 89.7 fps with 1% lows of 62.6 fps (GPU 86 % busy), and 8x
about 88 fps with 1% lows near 47 fps. With
pgr4_native_upscaler = true in pgr4_recompiled.toml, AMD's FidelityFX Super Resolution
antialiases the scene instead and upscales it to the frame's 1280x800. The scene renders at
pgr4_native_upscaler_width x pgr4_native_upscaler_height (the Display settings' FSR
resolution):
| Size | FSR's name for it |
|---|---|
| 1280x800 (default) | Native AA: antialiasing only |
| 853x533 | Quality |
| 753x471 | Balanced |
| 640x400 | Performance |
With pgr4_native_upscaler_target_fps set (90 for the Steam Deck OLED, which the Display
settings' Dynamic resolution sets), the upscaler starts at that size and lowers it, down to a
height of pgr4_native_upscaler_min_height, whenever the GPU falls behind, then raises it again
once the GPU catches up. A frame has the time of one at that frame rate, or at the lower one the
frames are shown at: the Frame rate setting's half or third of the refresh rate, or frame
generation's half. Much of the GPU's time does not shrink with the render size (the
post-processing, the interface and the upscaler itself), and the upscaler measures how much does
from its own changes of size. In a Tokyo race in the rain at 90 Hz, FSR 3.1 up to 1280x800 with a
target of 90 and a minimum of 400 rows averaged 89.1 fps with 1% lows of 41.2 fps, mostly at 400
to 500 rows. FSR 4 through OptiScaler takes longer than a 90 fps frame on a Steam Deck even at
400 rows (about 14 ms), so there the size stays at the minimum and the log says so; at 45 fps (the
Frame rate setting) or with frame generation it fits at full size.
F7 switches between MSAA and the upscaler while you play, and F8 shows the upscaler's debug view
(pgr4_native_fsr_debug), with FSR 4 AMD's watermark of the model it runs.
Both start off. The interface always stays at full resolution, and no sharpening is added.
On a Steam Deck OLED, MSAA is still the fastest at 90 fps. In a St Petersburg race, MSAA averaged
89.6 fps, FSR at 1280x720 84.0 and FSR at 853x480 86.9. The upscaler is there for its image, and
for FSR 4.
Out of the box this is FSR 3.1, from AMD's signed amd_fidelityfx_loader_dx12.dll and
amd_fidelityfx_upscaler_dx12.dll beside the executable. The game calls only AMD's FidelityFX
API, so the tools below can put a newer upscaler behind it. They are not part of this package,
and only OptiScaler and HelixSR are tested with PGR4, on a Steam Deck. To see which upscaler runs, start the game once with
%command% --log_level=info and look for PGR4 native upscaler: in logs/: it names the
upscaler's version (3.1.5 for the packaged FSR 3.1) and the render size.
Frame generation
With pgr4_native_frame_generation = true as well as pgr4_native_upscaler = true, AMD's
FidelityFX Frame Generation (amd_fidelityfx_framegeneration_dx12.dll beside the executable)
makes a frame between each two the game draws, from the upscaler's depth and motion. The game
then runs at half the display's refresh rate and the display shows twice as many frames: on a
Steam Deck OLED at 90 Hz, 45 game frames and 90 shown a second. The interface is drawn whole
into every frame, never interpolated. In the St Petersburg race, FSR at 1280x720 with frame
generation held 45.0 fps with 1% lows of 44.5 fps and no frame shown late (GPU 83 % busy), and
FSR 4 Lite at 960x540 through OptiScaler held 45.0 fps. Frame generation adds input latency: a
frame takes about 66 ms from its start to the display, against about 33 ms without it.
pgr4_native_fsr_debug (F8, or FSR debug view in the Developer settings) shows FidelityFX's debug
view of it, as of the upscaler.
FSR 4 on a Steam Deck (Proton)
AMD's FSR 4.1.2 has a Lite model for handheld GPUs. Under Proton it falls back to FSR 3 because
it asks the Windows driver for the GPU family, and Wine has no answer.
FSR4Injector's amdxc64.dll supplies the answer.
Its Decky plugin sets up only Steam games, so for this one do it by hand:
- Put two files beside
pgr4_recompiled.exe:amdxc64.dllfrom FSR4Injector's release (itsbin/, LGPL).- AMD's
amdxcffx64.dll, FidelityFX 2.4.0.4370 (FSR 4.1.2), from AMD's Adrenalin 26.10.1
driver package. FSR4Injector's plugin downloads it from AMD into the games it sets up.
- Set the launch options to
WINEDLLOVERRIDES=amdxc64=n,b FSR4I_FAMILY=150 FSR4I_REV=1 PROTON_USE_XALIA=0 DXVK_HDR=1 %command%.
The shim knows only the Legion Go 2's GPU by itself. Family 150 with revision 1 is the answer
for which AMD's library picks the Lite model (FSR4Injector'sshim/src/fsr4i.c), and the one
OptiScaler gives for Lite. AddFSR_WATERMARK=1to have AMD's library show the model it runs. - Set
pgr4_native_upscaler = true.
FSR4Injector lists the Steam Deck as untested.
OptiScaler
OptiScaler hooks the same FidelityFX calls and can
put FSR 4, XeSS or DLSS behind them.
- Steam Deck, with fgmod (Decky Framegen): set the launch options to
PROTON_USE_XALIA=0 DXVK_HDR=1 ~/fgmod/fgmod %command%. fgmod copies OptiScaler in as
dxgi.dlland replaces the package'samd_fidelityfx_upscaler_dx12.dllwith its own, keeping
the original asamd_fidelityfx_upscaler_dx12.dll.b. fgmod 0.7.9 brings OptiScaler 0.7.9 and
AMD's FSR 4.0.2 upscaler, neither of which has the Lite model. - Windows: put
OptiScaler.dll, renamed todxgi.dll, andOptiScaler.inibeside the
executable.
In OptiScaler.ini, Dx12Upscaler picks the upscaler (ffx for FSR 3.1 and 4, xess,
dlss). For FSR 4's Lite model, put AMD's amdxcffx64.dll 4.1.2 beside the executable and use
an OptiScaler that knows the Lite model (its current source does) with Fsr4GpuSupport=4.
OptiScaler then answers AMD's GPU query itself, without FSR4Injector's shim. Keep the render
size in pgr4_native_upscaler_width and _height: the game renders at that size whatever
OptiScaler's own ratio settings say. Insert opens OptiScaler's menu (ShortcutKey in
OptiScaler.ini changes the key). OptiScaler upscales in a context of its own, so through it F8
shows only AMD's watermark: the debug view is the Upscaler Debug View in OptiScaler's menu.
OptiScaler turns the game's FidelityFX calls into its own DLSS (NGX) calls before it picks the
upscaler (inputs/FfxApi_Dx12.cpp), so what hooks those reaches this game as well:
- HelixSR Scaler, an OptiScaler build, runs NVIDIA's
DLSS Model E network (DLSS 3.7's) as compute shaders on GPUs without DLSS, the Steam Deck's
included. Its setup builds the network on the PC it runs on; then put the Scaler into the game
by hand, as its README describes for a game the setup does not list (dxgi.dll,
OptiScaler.ini,OptiScaler/andHelixSR/beside the executable), and pick HLX DLSS in
its menu (Dx12Upscaler=dlss). HelixSR 3.2.0 on a Steam Deck OLED, in the Tokyo race in the
rain with a target of 90 and a minimum of 400 rows, averaged 89.4 fps with 1% lows of 64.7 fps,
mostly at the minimum (about 10 ms of GPU time a frame). Its FSR drop-in puts its own FSR 4 in
place of the package'samd_fidelityfx_upscaler_dx12.dll. - OptiScaler DLSS 5 runs DLSS 5 Neural Rendering
around the upscaler (its pass inNVSDK_NGX_D3D12_EvaluateFeature), on NVIDIA RTX GPUs with
nvngx_dlssnr.dll. The game hands over the scene before its interface is drawn, and no exposure
texture (FSR's auto exposure), so the model's white point is the pass's own measurement.
Geometry Wars
The arcade cabinet in the garage starts gw_recompiled.exe, which must stay beside
pgr4_recompiled.exe. Its settings are in gw_recompiled.toml.
Licenses
LICENSE.txt is this project's license. LICENSES/ holds those of the ReXGlue SDK, Xenia,
PGR4-Recomp, MTR-PGR4 and the libraries built into the program, and the sources it was built
from (SOURCE.txt). Project Gotham Racing 4 and its content belong to their owners; these
licenses grant no rights to the game.