29 Commits

Author SHA1 Message Date
chrg6
1e8045b36b Bring the tone mapped HDR picture's settings back to the menu, with defaults that give the look it had while it was fixed.
The sixteen settings the fixed look took away are settings again: the tone mapper choice, gamma correction, mid grey, match tone slope, tone slope, hue clip emulation, exposure, highlights, shadows, contrast, saturation, highlight saturation, blowout, flare, hue correction and colour grading. They have their rows in the settings table with the defaults and ranges they had, their rows in the Screen tab under HDR output's three brightness rows (none of them with the game's own HDR), their texts in the four languages, and their lines in the example ini. The tonemap library has the luminance mapper and the grading of the observer-response mapper again, and the support buffer carries five vec4 for it.

A player who changes nothing sees the picture as before. The observer-response mapper leaves each grading step out when its value is 1, and the slider values are divided, not multiplied by a rounded reciprocal, so 50 and 100 % arrive as exactly 1. Evaluated on the CPU in single precision, the shader with every default gave the same bits as the fixed one for 400,000 random scene colours, gains and whites, in HDR and for the SDR picture; the luminance mapper and the game's curve gave the same bits as before they were removed, and the observer-response mapper with its sliders moved stayed within 0.004 % of the pixel of its old result.

Gamma correction now counts with every tone mapper, 2.2 by default, which is what gave the fixed look its true blacks; before the fixed look it ran with the luminance mapper only and the other two showed the dark tones far above black. Its off value brings that lighter picture back for a player who asks for it. The game's own HDR does not take the setting and stays at 2.2.

Lines for these settings that an nx2navi.ini still holds from before the fixed look count again; the example ini and the release notes say so. Nothing of this was seen in the game.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-14 08:35:47 -05:00
chrg6
58fad9128d Give a synchronous submission of a recording copy that another thread's submission still replays a clone of its own for its deferred binds, instead of rewriting the copy under that replay.
nvnQueueSubmitCommands resolves a copy's deferred binds at the submit call: the handles the game's arrays hold now are
written into the recording copy (nvn_api_cmd.c resolve_deferred). With the replay on the submitting thread, a second
guest thread that submitted the same copy while the first one replayed it, or while the first copied it for a held
continuation (vk_exec.c cont_new), rewrote those handles under that replay: the rest of it bound the next frame's
textures and samplers, and a held continuation could be copied torn (F-2-03's part left after the private copies).

Now each copy counts the synchronous submissions between their prepare and the end of their replay (copy_prefix.busy,
which shares the 8 bytes pins had, so the prefix keeps its 56 bytes). nvn_submit_prepare takes copy_lock shared once
for all handles: the first submission in flight resolves the copy in place, as before; one that finds another in
flight, unless the copy is known to hold no deferred binds, resolves a clone made under that lock, with its texture
pins counted, and nvn_submit_done frees it after the replay, as the asynchronous path does for a copy a queued
submission still reads. A copy the game releases while a submission of it is in flight becomes a zombie and is freed at
the next sweep after it ends (release_copies, zombie_sweep). The bind loop moved unchanged into
runtime/nvn_submit_guard.h (nvn_resolve_binds) so a check can build it; it reports a corrupt record or a call past 16
deep to resolve_deferred, which ends the run with the messages it had, and keeps the first six changes' trace line.
Being code the front end carries under its MIT header, the new header keeps that line and THIRD_PARTY_NOTICES.md's row
names it. A clone is logged the first four times and at each power of two ("submits the recording ... while another
thread's submission of it is replayed"). No timing change and no wait: the clone path runs only when two threads have
one copy in flight at once.

Not reproduced before the change; nobody knows yet whether the game ever submits one copy from two threads at once (the
new line will say). Checks that passed: the new tests/submit_clone_check (four threads submitting two copies 200,000
times each while their arrays change: no replay saw its handles change, both paths ran, the counts ended at 0; the
unguarded 0.10.1 shape through the same harness: about 450,000 of 800,000 replays saw them change; nvn_resolve_binds
step by step), copy_sweep_check (its stand-in prefix follows the new layout), pass_cc_check on every runtime file, no new
-Wall -Wextra warnings in nvn_api_cmd.c and nvn_api_core.c.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-13 20:13:02 -05:00
chrg6
da65aa6099 Bring public main's Steam co-op, the removal of the old co-op and the launcher's Steam library file into the 0.10.0 line.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-13 04:37:01 -05:00
epicmeme546
c84c035939 Remove the co-op of 0.8.0: its runtime layer, relay, menu tab, settings, tests and docs.
The hidden beta shared story progress through a relay a player had to run and never showed the other players. A new co-op replaces it. Gone are runtime/coop*.c and their headers, the menu's Co-op tab and its texts in four languages, tools/coop_relay.py, the co-op tests, docs/coop.md, the [coop] section of nx2navi.ini.example, the --probe-coop mode, the coop trace item, and Monocypher, which only this layer used.

The old settings stay known as retired keys, so an nx2navi.ini that still sets them logs no unknown key, and they stay on the list of private settings, so a bug report keeps a room's secret, a relay's address and a name out. The platform layer's UDP sockets and fs_save_snapshot stay for the new co-op; cfg_ini_now and fs_profile_path, which nothing else called, are removed.

Checked: the game builds and starts, the menu shows its four tabs, --probe-cfg and --probe-fs pass, and the launcher's private-settings test passes. tests/save_share_check.py builds without its co-op stub; it cannot run from this worktree because the folder's path is longer than Windows allows, on main too.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-13 03:37:26 -05:00
chrg6
18aa16f2df Skip the menu's draw for a frame when its vertex or index buffer cannot be allocated, instead of copying through a null pointer.
The menu's Vulkan back end went on after a failed buffer allocation: it bound and mapped memory it did not have and copied the frame's vertices to the address the failed mapping left, null. Two reports of 0.8.0 end that way right after the settings menu opens with video memory used up, one on an integrated AMD GPU and one on an RTX 2050: two "got VkResult -2" lines, then an access violation in the C runtime's copy, writing address 0x20, not on a guest thread. The allocation now leaves no buffer and size 0 when it fails, the draw returns before anything is recorded, and the next frame asks for the buffer again. The change is marked in the vendored file and named in THIRD_PARTY_NOTICES.md. Compiled; the failing allocation was not reproduced here.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-12 15:19:59 -05:00
epicmeme546
385734dcc0 Sharpen FSR 3.1 more below a render scale of three quarters: its own sharpening towards the maximum, and a second, lighter RCAS pass over its picture.
FSR 3.1 was soft at Performance and Ultra Performance, most of all in motion. On a village save, while the camera turned at a steady rate (present screenshots every 0.4 s, the mean absolute Laplacian of the scene's luminance): FSR 3.1 Native AA 6.7, FSR 4 Performance 5.9 and Ultra Performance 5.4, FSR 3.1 Performance 4.0 and Ultra Performance 3.3. The library's own input checks found nothing wrong, and its tuning constants (velocity factor, accumulation per frame, shading change scale, behind the test switch NX2NAVI_FFX_KEYS) gave nothing or took detail away. Its own sharpening at 100 instead of the default 80 gave 5.0 and 4.1.

Now the share of extra sharpening grows from none at three quarters of the output's width to all of it at half (vk_dlaa_fsr3_boost). FSR 3.1's own sharpness goes that share of the way to its maximum, and its picture gets a second RCAS pass (shaders/dlaa_sharpen.comp, AMD's FSR 1 header with the linear light taken through c / (1 + max c) and back), before the HUD is drawn. Both follow the sharpness slider; 0 turns them off, and NX2NAVI_FSR3_SHARPEN=0 leaves the second pass out. At RCAS's full strength the pass took Performance to 8.2, past Native AA, with grain on every surface, so it runs 1.5 stops weaker: Performance 5.7, Ultra Performance 4.7, Quality 5.2. 63.4 fps against 65.1 without the pass. The HDR picture is clean. FSR 4 is untouched.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-12 12:50:43 -05:00
chrg6
bfe88e503a Add one anti-aliasing setting: the game's SMAA, off, FXAA, SMAA at its Ultra preset, or TAA.
Ocarina anti-aliases every frame with its own SMAA in three compute passes after the bloom composite. The new aa
setting (nx2navi.ini aa, the Screen tab's Anti-aliasing row) keeps that by default. off, fxaa and smaa leave out the
game's edge and weight passes and replace its composition with a pass of our own that writes the same square-rooted
RGB9E5 words into the scene target: a plain copy, an edge smoothing written here, or the SMAA reference implementation
with its area and search textures (MIT). taa is DLSS or FSR 3.1 at the scene's size, which the row sets through the
upscaler; while either runs, the game's SMAA stays whatever aa says. The game's passes are known by a hash of their
guest code. The shader build now also rebuilds a header when a file its source includes changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 15:09:16 -05:00
chrg6
309e412f1f Make HDR one fixed look with true blacks, and keep only its on switch and the three whites as settings.
HDR on is the game's scene through the observer-response mapper, anchored to the game's own mid grey and tone slope, with half of the hue bend of the game's clamp: the defaults the menu had. The tone mapper choice, the mid grey, the tone slope and its match, the hue clip, exposure, highlights, shadows, contrast, saturation, highlight saturation, blowout, flare, hue, grade and gamma are gone from the menu, the settings table and the example ini; a file that still sets them works as before, the keys read by nothing and logging nothing. The menu's HDR row is Off and On, with the peak, game and HUD whites under it. The game's own HDR is still there for a file that sets hdr = native, and the row lists it only then. The luminance mapper and its grading code, which no setting reaches any more, are removed from the tonemap library, and the support buffer carries one vec4 for it.

The dark tones of a dark scene sat far above black: the present showed the game's sRGB-encoded picture as that encode decodes, linear near black, while the game is graded for a display of gamma about 2.2, and since the observer-response mapper became the default the 2.2 correction ran with the luminance mapper only. A scene value of 0.003 came out at 0.29 nits at a white of 350 nits, where a 2.2 display shows the game at 0.015. The present now always shows the picture as a 2.2 display would, and the tonemap aims its peak lower by that correction's inverse, so the brightest light still reaches the display's peak; the same value comes out at 0.017 nits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 15:06:30 -05:00
chrg6
3d394dd84e Merge the fixes line: the stutter, memory, flicker and crash fixes, co-op, the mesh shader fallback and the launcher fixes.
Brought onto the line with FSR 4, its frame generation and the debug menu. Where both sides had added to the same
place, both stay: the patch table keeps the pickup count and the free camera, the settings list keeps both sides'
names, the menu includes the co-op page and the debug menu, and the launcher builder takes the pipeline list and the
FSR 4 folder. Both sides had added the menu's typed-character event; one definition stays, with the window code that
passes characters outside the basic plane.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-11 08:18:01 -05:00
epicmeme546
5bdf583331 Add frame generation through AMD's FSR SDK 2.4 as a setting to try with FSR 4, and never generate a frame without the HUD-less picture.
runtime/vk_fg4.cpp makes the frame generation swapchain and context with the libraries FSR 4 comes with
(amd_fidelityfx_loader_vk.dll and amd_fidelityfx_framegeneration_vk.dll beside the executable). vk_fg.cpp takes
that path only with fsr4_fg = 1 while FSR 4 is the upscaler; the default stays the FSR 3.1 library. The loader
picks the version for the card: the machine-learned FSR Frame Generation 4 on Radeon RX 9000 cards with Windows 11,
which is untested, and 3.1.6 elsewhere. On an RX 7900 XT (driver 26.10.1) it lists frame generation 3.1.6 and the
swapchains 4.0.0, which the driver brings and the loader chooses, and 3.1.7. The swapchain in place is wanted only
while its library is the one to use, so a change of the setting or of the upscaler, or a failure of this path,
takes it down as switching frame generation off does and the next present makes it with the other library.

The preparation gives this library the camera's position and axes, which FSR Frame Generation 4 requires, and a
scene scale of one metre a unit: with the 0.01 the FSR 3.1 path uses, version 3.1.6 drew grey translucent shapes
into the sky of its frames while the camera turned (160 captures of the screen during a camera sweep; clean with 1).

Both paths now generate a frame only when the picture without the HUD is there for it: generated from the
presented picture alone, the HUD would be warped with the scene behind it. In four configurations (21:9 with either
library, a 16:9 picture in a 21:9 window, a 1080 picture without HDR) every generated frame had it, and the log
counts the frames without. On screen, of the 6,404 pixels of the HUD's item button that stayed fixed through a
camera sweep with the FSR 3.1 library, 6,162 stayed fixed with this one.

Standing in Hyrule Field at 3440x1440 with FSR 4 Quality the game draws 43.0 frames a second with this path and
42.2 with the FSR 3.1 library, each shown twice over. One run changed the present mode, HDR, fullscreen, frame
generation, FSR 4, this setting and the upscaler in turn: 216 screenshots without a bad frame, and no failure.

The SDK's frame generation headers join runtime/third_party/ffx_sdk, unmodified. tools/make_kit.py and
tools/make_launcher.py take the third library from the --ffx4 folder when it is there, and tools/make_game.py
copies it beside the game.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-11 04:49:01 -05:00
epicmeme546
4d5454d380 Add AMD FSR 4 upscaling through the libraries of AMD's FSR SDK 2.4, as an Upscaling choice beside FSR 3.1.
runtime/vk_ffx4.cpp loads amd_fidelityfx_loader_vk.dll from beside the executable and asks it which upscaler
versions the device can run. Where a 4.x version is listed (Radeon RX 6000, RX 7000 and RX 9000 cards with AMD's
driver 26.10.1 or newer) the menu's Upscaling row gains AMD FSR 4 Native AA, Quality, Balanced, Performance and
Ultra Performance, and fsr4 = 1 runs it in FSR 3.1's place with the same inputs. Its contexts are made with that
version asked for by its id and the provider is asked afterwards which version it runs, so no other upscaler can
be shown under the name. When a context or a dispatch fails, FSR 3.1 makes the frame, and after three failures
FSR 4 is off for the run. Each upscaler starts its history anew on the frame after a change from one to the other.
The setting is off by default and the Linux build compiles stubs.

On an RX 7900 XT (driver 26.10.1, 3440x1440, HDR) the library runs FSR 4.1.2: a context takes 54 ms to make and
217 MiB of video memory. Standing in Hyrule Field: Quality 47.8 fps where FSR 3.1 gives 51.5, Native AA 41.4.
Screenshots of 601 consecutive frames standing, 801 during a camera sweep, 701 each in Kakariko and the
graveyard, and 1,301 across changes between FSR 3.1 and FSR 4, their modes and off show no flicker that FSR 3.1
does not have, and it runs together with FSR 3.1 frame generation.

The SDK's API headers are in runtime/third_party/ffx_sdk, unmodified, with the licence. tools/make_kit.py and
tools/make_launcher.py take AMD's two signed libraries with --ffx4, and tools/make_game.py copies them beside the
game when the kit has both.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-11 03:22:08 -05:00
chrg6
7e07e13bac Add co-op, off by default: rooms through a relay, progress sync between the players' own saves, and a Co-op tab.
Each player keeps their own game and save. One player makes a room, the others join it with its secret, and story flags and, by the room's rules, items, songs, quest items, small keys (a shared pool), rupees and ammunition reach every save. The layer is a host thread with one UDP socket to a relay the players run themselves (tools/coop_relay.py, Python's standard library only); the messages between the players are sealed with a key from the room's secret (XChaCha20-Poly1305, Monocypher 4.0.2 vendored with its licence and a row in THIRD_PARTY_NOTICES.md), every change is signed by the player who made it, a player accepts a room by its members' keys and the key of its rules, the save is copied to coop-backup before anything is applied, and values are set through the game's own routines between frames. The Co-op tab makes, joins, accepts, removes and leaves, and the menu takes typed text for the name, the relay and the secret. This is the contributor's pull request #518 on this line.

Nothing reaches the network while co-op is off: the socket is opened, and the relay's name looked up, only after co-op is on, a relay is set and a room is made or joined. There is no default relay.

Left out of the pull request: the other players drawn in the world (the "puppets") with the copied engine they need. They were unfinished, added two patch sites to the game's per-frame update that could not be put through the differential tests here, and their file helpers clashed with the ones this line already has. So no position is sent: the POS message's codec stays, nothing sends it.

Changed against the pull request:
- The menu's test hook drives the Co-op tab only when it comes from the environment. From nx2navi.ini it could turn co-op on, join a room and accept its offer.
- The log's label for a room is hashed from the secret instead of being its first three characters.
- A game that has not saved yet has no save to copy, and takes nothing from the room until it has saved once; that used to count as a copy made.
- A PING's token no longer carries the PC's uptime.
- On Windows the maker's key file and its folder get an access list with the player's account alone.
- The tests that link the platform layer get the socket library, and the save test a stand-in for the title screen's hook.

Checked on Windows, where the pull request had never been compiled: the runtime builds and links; --probe-coop passes (sockets on 127.0.0.1, the codec against its byte vectors, a fuzz of every parser, two sessions through a hostile mock relay, a relay restart, the sync engine); tests/coop_relay_test.py passes its 61 tests, with the probe through the real relay on 127.0.0.1 at 0 and 30 % loss; tests/coop_page_check.py passes and its deliberate fault fails 48 checks. Not checked: two games in one room (one game runs at a time here), any real network, the tab in the game.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-11 00:11:41 -05:00
chrg6
f29e34e7a0 Make the observer-response scene mapper the default HDR tone mapper, anchored to the game's mid grey and tone slope.
The HDR tonemap gains a mapper built on a finite cone response in LMS: scene grey 0.18 lands where the game's curve puts it and rises through it with the slope of the game's curve, and the hue bend of the game's clamp is given back to bright colours. It takes the scene before the game's exposure gain and the gain itself, which the splice now finds in the game's shader. The luminance mapper stays selectable and the game's own curve stays the third choice. The mapper fits the Rec. 709 gamut here, as the game's scene target holds no negative component. New settings: the tone mapper's mid grey, tone slope match, tone slope and hue clip emulation. The gamma correction on the present applies with the luminance mapper only.

Not part of this: eye adaptation, the anti-aliasing and reconstruction shaders, bloom and local exposure sliders, the output colour space choice and a 16-bit float scene target. Checked by build and numerically against the source of the port; the picture on an HDR display has not been judged. THIRD_PARTY_NOTICES.md names the source.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-10 23:20:31 -05:00
chrg6
61cd4784f8 Build the Linux kit against pinned Vulkan headers and without #embed, and try the compiler before the long steps.
A player's AppImage build of 0.7.1 stopped in its compile step after eight minutes of RomFS work: four
files did not compile, because the kit builds with the system's compiler and headers and theirs were
older than the runtime needs. vk_pipeline.c and vk_device.c name VK_KHR_pipeline_binary,
VK_KHR_dynamic_rendering_local_read and VK_KHR_shader_maximal_reconvergence, which their Vulkan headers
did not declare, and ui/menu.cpp takes its font in with #embed, which clang has from version 19.

- Vulkan headers: tools/vulkan_pin.py holds the release the other builds use (1.4.363, the archive and
  hash tools/make_release_linux.py already pinned, which now reads them from there). The AppImage carries
  its C headers in toolchain/vulkan-headers and builds against them whatever the system has; a kit or a
  source checkout uses the system's when they are at least that release and fetches the pinned ones
  otherwise (build_game.py vulkan_include). Their folder goes first on the include path of the runtime's
  sources only, so the lifted code's objects keep their keys, and a runtime object compiled before
  against the system's headers is taken over instead of compiled again. AppRun no longer asks for the
  system's Vulkan headers.
- #embed: tools/build_shaders.py also writes the font's bytes as runtime/ui/roboto_ttf.h (ignored by git,
  carried by a kit), and menu.cpp includes that where the compiler has no __has_embed. With #embed
  nothing changes.
- Before its long steps a Linux build that will compile now checks every runtime source that needs no
  header of the install with the compile step's own command (clang -fsyntax-only) and links an empty
  program against the game's libraries (make_game.py preflight): an old compiler, an old header or a
  missing development package stops it in the first seconds with the compiler's own errors. A failed
  compile names every file that failed, not only the three whose errors it prints.

Checked on Windows: tests/launcher_test.py passes with four new tests (117); the header of bytes and
#embed give the same 162,588 bytes, and both branches of menu.cpp compile; the early check passes on the
Windows file set with clang 23 and stops on files made to fail; the 34 local headers of release 363 are
the upstream tag's files by git blob id. Not run: anything on Linux, the pinned archive's download, a
compiler older than 23.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-10 12:42:17 -05:00
chrg6
75b0dca907 Add Steam Deck button prompts beside the Xbox and PlayStation ones (prompts = steamdeck).
The Controls tab's Button prompts row and nx2navi.ini take steamdeck: the Deck's own labels in the game's
text, action prompt and ocarina notes, which are A B X Y where an Xbox pad has them, L1 R1 L2 R2 and L3 R3,
Menu and View. The style is drawn by tools/pad_prompts.py like the others, into romfs-patches-steamdeck
and romfs-patches-steamdeck-label, and every build with button art writes them.

Pull request #107 by loteran asked for PlayStation and Steam Deck prompts; it was closed, and the tree
took the PlayStation half in another form, drawn from button art instead of redrawn font glyphs. This is
the Steam Deck half in that form, written here: the art has no Deck style, so its entry in
tools/prompt_art.py names the Xbox pictures for the face buttons, Menu, View, the d-pad and the sticks
and the PlayStation pictures for the shoulders and stick clicks. It needs four pictures of the Xbox set
that no other style used (the white letters on a light button, for the ocarina's notes); a release made
with --prompt-art copies them with the rest.

The Windows files compile and tests/launcher_test.py passes, with the prompts step's test following the
number of folders (seven now); every picture the style names is in the art used for releases. The style
was not drawn here (that needs the game's font), and --probe-cfg, which has a new check, was not run.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-10 06:53:30 -05:00
chrg6
32ee021905 Include NVIDIA's pinned DLSS library for Linux in the AppImage, and place it beside the built game.
On Linux the game looks for libnvidia-ngx-dlss.so.<version> beside the executable, and the driver brings
only NGX's core, so the DLSS modes did nothing in every Linux build. tools/dlss_pin.py pins the Linux
library of the DLSS version it pins for Windows, with its own size and SHA-256; tools/make_appimage.py
puts it in the kit's bin/ with its notice (downloaded from NVIDIA's DLSS SDK repository and checked, or
--dlss; --no-dlss leaves it out), and tools/make_game.py copies it beside the game on Linux as it copies
the DLL on Windows, keeping a library the player put there.

Pull request #297 by mooki000, taken as it is; the builder's description is merged with the button art
option that came with the release workflow. On Windows place_dlss does what it did. No NVIDIA file is in
the repository.

tests/launcher_test.py passes with its two new tests (112 tests, Python 3.12 on Windows); the AppImage
was not built here.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-10 06:38:02 -05:00
itaskaev2
7341eec727 Download the pinned Streamline runtime for DLSS Frame Generation, and let the build kit carry it too.
make_launcher.py --dlssg needed --streamline, a Streamline SDK folder unpacked by hand, and make_kit.py could not
carry DLSS Frame Generation at all, so a game built from the kit always left it off. tools/streamline_pin.py now pins
the Streamline 2.14.16 SDK release (its archive's size and SHA-256, and the SHA-256 of each file the game loads):
without --streamline the scripts download the archive once, check it, keep only sl.interposer.dll, sl.common.dll,
sl.dlss_g.dll, sl.pcl.dll, sl.reflex.dll, nvngx_dlssg.dll and the two licence texts, each checked, and delete the
archive. A folder given with --streamline must hold the pinned files.

The bin/dlssg/ assembly moves from make_launcher.py into streamline_pin.place, so the release and the kit write the
same set and the same dlssg-NOTICE.txt: a kit made with --dlssg and the 0.6.0 release's nx2navi_dlssg.dll has a
bin/dlssg/ identical to the 0.6.0 release's, byte for byte. make_kit.py takes --dlssg [--streamline] like the
launcher. nx2navi_dlssg.dll itself still comes from tools/build_dlssg.py.

tests/launcher_test.py test_streamline_pin covers the extraction, the cache, refused archives and folders, and the
notice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 12:18:17 -05:00
chrg6
d6711ca59b Credit the button prompt art the releases carry in THIRD_PARTY_NOTICES.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 09:12:31 -05:00
chrg6
dfc5b90b59 Fix what the 0.6.0 review found, and ship DLSS Frame Generation in the launcher release.
The commit census of the perf trace walked the address space on the presenting thread outside mem_census, which
brought back the hitch mem_census was added to remove; it now runs only with mem_census = 1. DLSS's output pass at
the mode's share fell back to no pass at all when the scene was not at that share (the first presents, a dynamic
resolution step): after such a frame the first pass wider than the scene is taken again for 120 frames. The launcher's
nx2navi.ini editor no longer rewrites a file it cannot read, keeps the byte order mark and bytes that are not UTF-8,
reads an empty line as the game does, and leaves no temporary file behind. The build kit carries the two modules
build_game.py imports on Linux, the Linux steps list the right packages and Python, and stale comments and notes are
corrected (Discord on by default, two prebuild threads, Enhanced HDR gone).

DLSS Frame Generation needs nx2navi_dlssg.dll, NVIDIA Streamline's runtime and nvngx_dlssg.dll beside the game, which
no release carried, so the menu offered it and the game turned it off. tools/make_launcher.py --dlssg and --streamline
put them with their licences and a notice in the release's bin/dlssg/, and tools/make_game.py place_dlssg copies the
whole set beside the game. THIRD_PARTY_NOTICES.md has the row; the notes and README say RTX 40 and 50.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 09:10:36 -05:00
chrg6
ef08fed45f Ship NVIDIA's DLSS library in the setup and the build kit, and put it beside the game.
The release carried AMD's FSR 3.1 library but not nvngx_dlss.dll, so DLSS ran only where the NVIDIA driver supplied the model itself; elsewhere players had to fetch the DLL by hand. tools/make_launcher.py and tools/make_kit.py now download NVIDIA's own build from the DLSS SDK repository at a pinned tag (tools/dlss_pin.py: 310.9.1, checked against its size and SHA-256, cached), and put it in the release's bin/ with a notice naming the NVIDIA RTX SDKs License that covers it. --dlss FILE takes a copy on disk instead, --no-dlss leaves it out.

tools/make_game.py copies the DLL and its notice beside the game. A different nvngx_dlss.dll the player put there is kept; the one an earlier build placed (named by the notice's sha256 line) is replaced, so a newer release can bring a newer DLSS. The compile step's key covers make_game.py and the kit version, so existing installs get the DLL with their next update.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 08:09:26 -05:00
tangerineturtle1
9e574f84ec Replace the enhanced HDR with a port of RenoDX's tone mapper.
The game's ACES tonemap shader gets a GLSL function linked into its SPIR-V where it clamps each channel: the game's SDR result upgraded to the HDR range by luminance and mapped to the display with the RenoDRT curve, exposure, highlights, shadows, contrast, saturation, highlight saturation, blowout, flare and hue correction. The settings reach it as four vec4 the support buffer gains at 1440. The present encode is a port of the swap chain pass: gamma correction, gamut compression, the peak clamp and PQ. Without an HDR10 swapchain the shader gives the game's own SDR picture; native HDR is unchanged.

The menu offers Off, RenoDX and Native, with gamma correction, the tone mapper and its grading rows. The shader build compiles sources marked "keep functions" without optimisation so their functions survive for the splice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 06:06:33 -05:00
chrg6
8daedbd806 Redraw the in-game menu with the game's own interface textures, and bring in the launcher's save import and faster builds.
In-game menu: the settings window, its tabs, rows, buttons and cursor, the performance overlay and the Preparing
shaders box are drawn with the game's interface textures where the RomFS holds them (runtime/ui/menu_skin.cpp,
perf_panel.cpp; plain shapes until they are decoded). Restart joins Continue and Quit, each behind a confirmation;
VSync is an on/off switch; DLSS is listed only on NVIDIA GPUs; the menu sounds are quieter; Picture shape is gone and
the setting descriptions are shorter; edge cases of input, layout and fonts are fixed. tools/menu_preview.py draws the
menu without the game.

Launcher: Import Saves takes a save from the game folder's saves/ folder or one the player picks; downloads fall back
to Windows' own certificate check when Python's refuses a server; updates are faster; the title bar is drawn in the
window and Navi is every icon. tools/make_game.py builds with CLANG64's clang where the launcher installed it, packs
the RomFS beside the lift and the compile, takes a prebuilt runtime, and compiles the game's resources without cmd.exe,
so a user folder with a space in its name builds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 03:57:01 -05:00
chrg6
7f50cc5e29 Third-party notices list only the code the repository copies.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 20:36:29 -05:00
chrg6
e7f6a00407 Translate every shader, keep atomic loops from spinning on stale values, harden pool teardown, and update the README.
Shaders: a switch whose index is clamped against a register that a MOV of an immediate set before it now finds its
jump table (AmpereLowering.cs BrxTargets), so all 36,031 of the game's shader variants translate and no draw is skipped
for a failed one. The compare-and-swap loop behind storage-buffer atomics (patch 0033) takes the value a failed swap
returns as its next expected value instead of loading the word again, which on some drivers kept returning a stale
copy.

Memory: an unused physical pool outlives the submission being recorded, as virtual pages may still reach it through
device addresses; an image whose creation failed is not tried again for 2 s.

The installer and Linux texts name this game.
The README has the project icon, the current status, features, requirements and known issues.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 18:03:20 -05:00
Claude
c403547c8b Add the NX2navi launcher: a one-click setup that builds the game from the player's dump, starts it and keeps it up to date.
NX2navi-Setup.exe installs the launcher into %LOCALAPPDATA%\Programs\NX2navi without administrator rights, with
shortcuts and an Apps entry. The launcher finds the player's .nup, downloads the build tools itself (the MSYS2 UCRT64
packages toolchain.lock.json pins, checked by sha256 and unpacked without pacman, and zbic from PyPI) and runs
tools/make_game.py, whose steps it shows with their progress. Its window follows the game's options menu: colours
sampled from it, the menu's filigree, the white glowing cursor, the Triforce in the title band and as the programs'
icon, and all text in the game's Cetra Display, decoded from the player's own dump. Mouse, keyboard and an XInput
pad drive it.

Updates come from GitHub releases (NX2navi-update.json): the new version is downloaded, checked and staged beside
the running one, the stub restarts into it and falls back to the previous version when it fails to start, and the
game is rebuilt without the dump. make_game.py now keys its exefs and romfs steps on the game files alone, has
--rebuild and --events, compiles only the files whose source, headers, flags or compiler changed, and replaces
ocarina.exe only once the new one links. tools/make_launcher.py builds the release on Windows or Linux.

Tested: tests/launcher_test.py (19 tests), the real toolchain download and install, and under Wine 11 the setup,
the stub, the window on the bundled Windows Python, an update from a local feed by clicking Updates, the rollback
of a version that fails to start, and the downloaded clang compiling and linking a program against the game's
libraries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Merged onto the current port: make_game.py keeps the launcher's step keys, cached link and in-place swap, and its
own runtime manifest (windres), AMD's FidelityFX library and the shader preparation, which becomes a step of its own
("shaders") that the launcher shows in its install, rebuild and update jobs. make_launcher.py ships the shader tools
and, with --ffx, AMD's library.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 14:50:52 -05:00
chrg6
ca5e5eb5a4 Add AMD FSR 3.1 upscaling, and run DLSS's smaller modes on a 16:9 picture too.
The Upscaling choice gains FSR 3.1 Native AA, Quality, Balanced, Performance and Ultra Performance. FSR 3.1 runs
through AMD's signed amd_fidelityfx_vk.dll (loaded at run time; the build kit ships it) in DLSS's place, on the same
scene light, depth and camera motion vectors and at the same render scales. Its Vulkan back end needs
VK_KHR_get_memory_requirements2, which the device now enables when FSR 3.1 is chosen.

A half-size effect pass with three targets and a half-size depth was taken for a G-buffer, which switched every later
frame to the deferred frame shape: there the output pass of a smaller scene was never found, so DLSS Quality,
Balanced, Performance and Ultra Performance did nothing on a 16:9 picture. Such a pass smaller than the scene is now
left alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 13:31:06 -05:00
chrg6
91c147a0aa Draw Ocarina in the window's shape: a wider picture and camera, with the HUD, menus and movies kept 16:9 in the middle.
The patch sets of recomp/patches-v111.txt read the game's 2560x1440 picture and 1920x1080 scene sizes from the patch page, give every 16:9 camera the picture's ratio, squeeze the UI's full-screen projection into the middle 16:9 (fades and the menu backgrounds that redraw a capture stay full width) and pillarbox movies. runtime/widescreen.c sets them up from the new Screen tab row Widescreen (NX2NAVI_GAME_ASPECT: 16:9, window, 21:9 or 32:9, at the next start).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 05:04:39 -05:00
chrg6
c8738a948c Name the settings, files and tools NX2navi
The names are NX2NAVI, NX2navi or nx2navi: the settings prefix (NX2NAVI_*), the ini file
(nx2navi.ini), the shader translator (nx2navi_xlate), the Windows resources, the installer and the docs. The 8-byte
file magics keep their size (NX2NSANS, NX2NSPRG, NX2NSPRP, NX2NPKEY, NX2NRFS1), so caches and the RomFS index from
older builds are not read. cfg.c and the settings pages took the prefix length as 5; it now follows the prefix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 05:04:39 -05:00
Valiantsin Dzerakh
0478c13e45 Import the base tree (MIT, see LICENSE) 2026-11-07 05:04:38 -05:00