mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 17:09:57 -04:00
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>
This commit is contained in:
@@ -123,7 +123,7 @@ folder's `licenses/` and in each component's own folder.
|
||||
| zlib 1.4 (MSYS2 `mingw-w64-ucrt-x86_64-zlib`), static library | https://zlib.net, Copyright (C) Jean-loup Gailly and Mark Adler | zlib | linked into `NX2navi-Setup.exe` (its unzip) |
|
||||
| mingw-w64 CRT startup code and winpthreads 14.0.0, GCC 16.2.0's `libgcc` (MSYS2 packages), static | https://www.mingw-w64.org, https://gcc.gnu.org | mingw-w64: ZPL-2.1 / MIT / public domain; libgcc: GPL-3.0 with the GCC Runtime Library Exception | linked into `NX2navi.exe` and `NX2navi-Setup.exe` |
|
||||
| NVIDIA DLSS 310.9.1 (`nvngx_dlss.dll`, NVIDIA's own build, unmodified; pinned with its size and sha256 in `tools/dlss_pin.py`) | https://github.com/NVIDIA/DLSS @ `v310.9.1` (`lib/Windows_x86_64/rel/nvngx_dlss.dll`), Copyright NVIDIA Corporation | NVIDIA RTX SDKs License (https://github.com/NVIDIA/DLSS/blob/v310.9.1/LICENSE.txt); licensed for systems with NVIDIA GPUs only | `app/<version>/bin/` with `nvngx_dlss-NOTICE.txt`, also in the build kit's `bin/`; `tools/make_game.py` copies both beside the built game, where NGX loads the library (`runtime/vk_dlaa.c`) |
|
||||
| NVIDIA Streamline 2.14.16 runtime (`sl.interposer.dll`, `sl.common.dll`, `sl.dlss_g.dll`, `sl.pcl.dll`, `sl.reflex.dll`, NVIDIA's own builds, unmodified) and NVIDIA DLSS Frame Generation 310.9.16 (`nvngx_dlssg.dll`, as the Streamline SDK ships it) | https://github.com/NVIDIA-RTX/Streamline, SDK release 2.14.16 (`bin/x64/`), Copyright NVIDIA Corporation | Streamline: MIT; `nvngx_dlssg.dll`: NVIDIA RTX SDKs License, licensed for systems with NVIDIA GPUs only | `app/<version>/bin/dlssg/` with both licence texts and `dlssg-NOTICE.txt` (each file's sha256), when the release is made with `tools/make_launcher.py --dlssg --streamline`; `tools/make_game.py` copies them beside the built game, where `nx2navi_dlssg.dll` (this repository's `runtime/dlssg/`, built with the Streamline SDK's MIT headers) loads them (`runtime/vk_dlssg.c`) |
|
||||
| NVIDIA Streamline 2.14.16 runtime (`sl.interposer.dll`, `sl.common.dll`, `sl.dlss_g.dll`, `sl.pcl.dll`, `sl.reflex.dll`, NVIDIA's own builds, unmodified) and NVIDIA DLSS Frame Generation 310.9.16 (`nvngx_dlssg.dll`, as the Streamline SDK ships it) | https://github.com/NVIDIA-RTX/Streamline, SDK release 2.14.16 (`bin/x64/`), Copyright NVIDIA Corporation | Streamline: MIT; `nvngx_dlssg.dll`: NVIDIA RTX SDKs License, licensed for systems with NVIDIA GPUs only | `app/<version>/bin/dlssg/` with both licence texts and `dlssg-NOTICE.txt` (each file's sha256), when the release is made with `tools/make_launcher.py --dlssg`, and the build kit's `bin/dlssg/` with `tools/make_kit.py --dlssg` (the SDK release pinned with its size and sha256 and each file's sha256 in `tools/streamline_pin.py`); `tools/make_game.py` copies them beside the built game, where `nx2navi_dlssg.dll` (this repository's `runtime/dlssg/`, built with the Streamline SDK's MIT headers) loads them (`runtime/vk_dlssg.c`) |
|
||||
| Button prompt art: the 128x128 PNGs of the Input Prompts Pack V7 (`XGamepad`, `P5Gamepad` and `Keyboard_Mouse` styles), unmodified | the pack as licensed to the repository owner; never in this repository | the pack's licence, which allows redistributing these pictures in NX2navi's releases (confirmed by the repository owner, 2026-11-09) | `app/<version>/prompt-art/` and the build kit's `prompt-art/` when made with `--prompt-art` (`tools/prompt_art.py`); `tools/pad_prompts.py` draws the game's Xbox, PlayStation and keyboard and mouse prompts from them on the player's PC |
|
||||
|
||||
Downloaded on the player's PC by the launcher, not distributed: the MSYS2 UCRT64 packages that
|
||||
|
||||
@@ -119,6 +119,9 @@ beside the game.
|
||||
- The build copies NVIDIA's DLSS library `nvngx_dlss.dll` (with `nvngx_dlss-NOTICE.txt`, which names its licence)
|
||||
and FSR 3.1's `amd_fidelityfx_vk.dll` beside `ocarina.exe` from the kit's `bin\`. To use another DLSS version, put
|
||||
your own `nvngx_dlss.dll` there: later builds keep it.
|
||||
- A kit with `bin\dlssg\` (made with `tools/make_kit.py --dlssg`) also brings DLSS Frame Generation on GeForce RTX 40
|
||||
and 50 cards: the build copies `nx2navi_dlssg.dll`, NVIDIA Streamline's runtime, `nvngx_dlssg.dll` and their licence
|
||||
texts beside `ocarina.exe`, and Frame generation in the Screen menu then offers DLSS too.
|
||||
- Logs are in `logs\`. When reporting a problem, say where you were in the game and which graphics card you have, and
|
||||
attach `logs\nx2navi.log`. Never send game files.
|
||||
|
||||
|
||||
@@ -268,6 +268,14 @@ game folder is the default `<launcher>\game`. The dump is never touched.
|
||||
ship the library; it also asks that a commercial release be announced to NVIDIA first
|
||||
(https://developer.nvidia.com/sw-notification) and that the use of DLSS be credited.
|
||||
|
||||
`--dlssg nx2navi_dlssg.dll` (built by `tools/build_dlssg.py`, which needs Visual Studio's C++ compiler) adds DLSS
|
||||
Frame Generation in `bin/dlssg/`: beside it NVIDIA Streamline's runtime (`sl.interposer.dll`, `sl.common.dll`,
|
||||
`sl.dlss_g.dll`, `sl.pcl.dll`, `sl.reflex.dll`) and `nvngx_dlssg.dll`, taken from the Streamline SDK release that
|
||||
`tools/streamline_pin.py` pins. The script downloads that release once (cached in `toolchain/launcher-dl/`), checks
|
||||
the archive's size and sha256 and each file's sha256, and writes `dlssg-NOTICE.txt` with the two licence texts;
|
||||
`make_game.py` copies the whole set beside the game. `--streamline SDK` takes an SDK folder on disk instead (its
|
||||
files must be the pinned ones).
|
||||
|
||||
`--prompt-art FOLDER ...` puts the button art in the release (`app/<version>/prompt-art`): folders that hold
|
||||
`XGamepad`, `P5Gamepad` and `Keyboard_Mouse` (the Source folders of button prompt art packs), or those three
|
||||
folders themselves; a set named itself wins over one found inside a folder named, and the same set twice is
|
||||
|
||||
@@ -1657,13 +1657,13 @@ class MakeGameTest(Tmp):
|
||||
def test_dlssg_beside_the_game(self):
|
||||
"""DLSS Frame Generation's files go beside the game only as a whole set, with the licence texts; the release
|
||||
script (tools/make_launcher.py) and the build agree on the set."""
|
||||
import make_launcher
|
||||
import streamline_pin
|
||||
from unittest import mock
|
||||
kit, out = self.tmp / 'kit', self.tmp / 'game'
|
||||
src = kit / 'bin' / 'dlssg'
|
||||
src.mkdir(parents=True)
|
||||
out.mkdir()
|
||||
self.assertEqual(make_launcher.DLSSG_FILES, self.mg.DLSSG_FILES)
|
||||
self.assertEqual(streamline_pin.FILES, self.mg.DLSSG_FILES)
|
||||
with mock.patch.object(self.mg, 'KIT', kit):
|
||||
for n in self.mg.DLSSG_FILES[:-1]:
|
||||
(src / n).write_bytes(n.encode())
|
||||
@@ -1676,6 +1676,58 @@ class MakeGameTest(Tmp):
|
||||
self.assertEqual((out / n).read_bytes(), (src / n).read_bytes())
|
||||
self.assertEqual((out / 'streamline-LICENSE.txt').read_text(), 'MIT')
|
||||
|
||||
def test_streamline_pin(self):
|
||||
"""The Streamline files come out of the SDK archive checked one by one; the archive goes once they are out and
|
||||
a filled cache needs no download; an SDK folder on disk must hold the pinned files; bin/dlssg/ gets the set
|
||||
make_game.py places, the two licence texts and a notice with every file's sha256."""
|
||||
import streamline_pin
|
||||
from unittest import mock
|
||||
files = {n: f'{n} of the SDK'.encode() for n in streamline_pin.SDK_FILES}
|
||||
pins = {n: hashlib.sha256(d).hexdigest() for n, d in files.items()}
|
||||
cache = self.tmp / 'dl'
|
||||
cache.mkdir()
|
||||
archive = cache / f'streamline-sdk-v{streamline_pin.VERSION}.zip'
|
||||
with zipfile.ZipFile(archive, 'w') as z:
|
||||
for n, d in files.items():
|
||||
z.writestr(n, d)
|
||||
z.writestr('bin/x64/sl.nis.dll', b'a plugin the game does not load')
|
||||
fetched = []
|
||||
|
||||
def download(url, dest, sha256=None, size=None): # the archive is already where net.download writes it
|
||||
fetched.append(url)
|
||||
self.assertEqual(Path(dest), archive)
|
||||
return dest
|
||||
|
||||
with mock.patch.dict(streamline_pin.SDK_FILES, pins), mock.patch('launcher.net.download', download):
|
||||
sdk = streamline_pin.resolve(None, cache)
|
||||
self.assertEqual(fetched, [streamline_pin.URL])
|
||||
self.assertFalse(archive.exists())
|
||||
self.assertEqual(streamline_pin.wrong_files(sdk), [])
|
||||
self.assertFalse((sdk / 'bin' / 'x64' / 'sl.nis.dll').exists())
|
||||
self.assertEqual(streamline_pin.resolve(None, cache), sdk) # filled: no second download
|
||||
self.assertEqual(len(fetched), 1)
|
||||
self.assertEqual(streamline_pin.resolve(sdk, cache), sdk) # a folder on disk with the pinned files
|
||||
(sdk / 'bin' / 'x64' / 'sl.common.dll').write_bytes(b'another Streamline')
|
||||
with self.assertRaises(SystemExit):
|
||||
streamline_pin.resolve(sdk, cache)
|
||||
(sdk / 'bin' / 'x64' / 'sl.common.dll').write_bytes(files['bin/x64/sl.common.dll'])
|
||||
with zipfile.ZipFile(archive, 'w') as z: # an archive whose file differs is refused
|
||||
for n, d in files.items():
|
||||
z.writestr(n, b'changed' if n == 'license.txt' else d)
|
||||
with self.assertRaises(SystemExit):
|
||||
streamline_pin.extract(archive, self.tmp / 'x')
|
||||
dll = self.tmp / 'nx2navi_dlssg.dll'
|
||||
dll.write_bytes(b'our frame generation shim')
|
||||
dest = self.tmp / 'bin' / 'dlssg'
|
||||
streamline_pin.place(dll, sdk, dest)
|
||||
self.assertEqual(sorted(p.name for p in dest.iterdir()),
|
||||
sorted((*streamline_pin.FILES, *streamline_pin.TEXTS, streamline_pin.NOTICE)))
|
||||
self.assertEqual((dest / 'streamline-LICENSE.txt').read_bytes(), files['license.txt'])
|
||||
note = (dest / streamline_pin.NOTICE).read_text(encoding='utf-8')
|
||||
self.assertIn(f'Streamline {streamline_pin.VERSION} SDK', note)
|
||||
self.assertIn(f'nx2navi_dlssg.dll sha256 {hashlib.sha256(dll.read_bytes()).hexdigest()}', note)
|
||||
self.assertIn(f'nvngx_dlssg.dll sha256 {pins["bin/x64/nvngx_dlssg.dll"]}', note)
|
||||
|
||||
@unittest.skipIf(os.name == 'nt', 'a script stands in for windres.exe')
|
||||
def test_compile_resources(self):
|
||||
# The toolchain, the kit and the game under folders with spaces, as under C:\Users\Ali Sayed. windres must
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
|
||||
Streamline's C++ types have MSVC's ABI, so this one DLL is built with Visual Studio's compiler (the Build Tools are
|
||||
enough; vswhere finds them), against the SDK's headers, which stay where they are. The Vulkan headers are MSYS2's.
|
||||
A launcher release ships the DLL ready-made beside Streamline's own runtime DLLs (tools/make_launcher.py --dlssg
|
||||
and --streamline), and tools/make_game.py place_dlssg puts them beside the game.
|
||||
A launcher release and the build kit ship the DLL ready-made beside Streamline's own runtime DLLs
|
||||
(tools/make_launcher.py and tools/make_kit.py --dlssg, with the Streamline files tools/streamline_pin.py pins), and
|
||||
tools/make_game.py place_dlssg puts them beside the game.
|
||||
"""
|
||||
import argparse
|
||||
import os
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
"""Assemble the build kit: what a player needs to build Ocarina of Time on their own PC with tools/make_game.py.
|
||||
|
||||
python tools/make_kit.py --xlate <dir with nx2navi_xlate.exe and .id> [--ffx amd_fidelityfx_vk.dll]
|
||||
[--dlss nvngx_dlss.dll | --no-dlss] [--prompt-art FOLDER [FOLDER ...]]
|
||||
[--out build/kit] [--zip]
|
||||
[--dlss nvngx_dlss.dll | --no-dlss] [--dlssg nx2navi_dlssg.dll [--streamline SDK]]
|
||||
[--prompt-art FOLDER [FOLDER ...]] [--out build/kit] [--zip]
|
||||
|
||||
The kit holds this repository's runtime/, recomp/, the build tools, the shader translator built from tools/xlate,
|
||||
NVIDIA's DLSS library with its notice (tools/dlss_pin.py: downloaded from NVIDIA's DLSS SDK repository and checked,
|
||||
or --dlss; not with --no-dlss), AMD's FSR 3.1 library with --ffx, the button art with --prompt-art, and
|
||||
or --dlss; not with --no-dlss), DLSS Frame Generation in bin/dlssg/ with --dlssg (nx2navi_dlssg.dll from
|
||||
tools/build_dlssg.py beside NVIDIA Streamline's runtime, tools/streamline_pin.py: downloaded from NVIDIA's Streamline
|
||||
SDK release and checked, or --streamline), AMD's FSR 3.1 library with --ffx, the button art with --prompt-art, and
|
||||
README-BuildKit.md; no game code, data or anything generated from the game. check_content runs over the folder before
|
||||
it is zipped.
|
||||
|
||||
@@ -48,6 +50,10 @@ def main():
|
||||
ap.add_argument('--dlss', type=Path, help="NVIDIA's nvngx_dlss.dll from disk instead of downloading it from "
|
||||
"NVIDIA's DLSS SDK repository")
|
||||
ap.add_argument('--no-dlss', action='store_true', help='leave NVIDIA DLSS out of the kit')
|
||||
ap.add_argument('--dlssg', type=Path, metavar='DLL',
|
||||
help='nx2navi_dlssg.dll (tools/build_dlssg.py) for DLSS Frame Generation')
|
||||
ap.add_argument('--streamline', type=Path, metavar='SDK',
|
||||
help='the Streamline SDK folder instead of downloading the SDK release with --dlssg')
|
||||
ap.add_argument('--prompt-art', type=Path, nargs='+', metavar='FOLDER',
|
||||
help='the button art: folders holding XGamepad, P5Gamepad and Keyboard_Mouse, or those folders')
|
||||
ap.add_argument('--out', type=Path, default=ROOT / 'build' / 'kit')
|
||||
@@ -56,9 +62,13 @@ def main():
|
||||
sys.path.insert(0, str(ROOT / 'tools'))
|
||||
import dlss_pin
|
||||
import prompt_art
|
||||
import streamline_pin
|
||||
if a.streamline and not a.dlssg:
|
||||
sys.exit('--streamline goes with --dlssg')
|
||||
if a.prompt_art:
|
||||
prompt_art.art_files(a.prompt_art) # the art is all there before anything is downloaded
|
||||
dlss = None if a.no_dlss else dlss_pin.resolve(a.dlss, ROOT / 'build' / 'dl')
|
||||
sdk = streamline_pin.resolve(a.streamline, ROOT / 'build' / 'dl') if a.dlssg else None
|
||||
kit = a.out / NAME
|
||||
if kit.exists():
|
||||
shutil.rmtree(kit)
|
||||
@@ -79,6 +89,8 @@ def main():
|
||||
shutil.copy2(a.ffx, kit / 'bin' / 'amd_fidelityfx_vk.dll')
|
||||
if dlss: # DLSS: NGX loads it from beside the game (runtime/vk_dlaa.c); make_game.py copies it there
|
||||
dlss_pin.place(dlss, kit / 'bin')
|
||||
if sdk: # DLSS Frame Generation (runtime/vk_dlssg.c): make_game.py place_dlssg copies it beside the game
|
||||
streamline_pin.place(a.dlssg, sdk, kit / 'bin' / 'dlssg')
|
||||
if a.prompt_art: # make_game.py draws the button prompts from it (its prompts step)
|
||||
n, size = prompt_art.copy_art(a.prompt_art, kit / prompt_art.FOLDER)
|
||||
print(f'button art: {n} pictures, {size / 1e6:.1f} MB')
|
||||
|
||||
@@ -21,8 +21,10 @@ The release folder (--out) holds:
|
||||
bin/nvngx_dlss.dll and its notice (NVIDIA DLSS at the version tools/dlss_pin.py
|
||||
pins, downloaded from NVIDIA's DLSS SDK repository and checked, or --dlss; not with
|
||||
--no-dlss),
|
||||
bin/dlssg/ with --dlssg and --streamline (DLSS Frame Generation: nx2navi_dlssg.dll,
|
||||
Streamline's runtime DLLs and nvngx_dlssg.dll, their licences and a notice),
|
||||
bin/dlssg/ with --dlssg (DLSS Frame Generation: nx2navi_dlssg.dll, Streamline's
|
||||
runtime DLLs and nvngx_dlssg.dll at the version tools/streamline_pin.py pins,
|
||||
downloaded from NVIDIA's Streamline SDK release and checked, or --streamline; their
|
||||
licences and a notice),
|
||||
lib/libnx2navirt.a (the runtime, prebuilt with the release's compiler),
|
||||
prompt-art/ with --prompt-art (the button art make_game.py draws the Xbox,
|
||||
PlayStation and keyboard and mouse prompts from, tools/prompt_art.py art_files),
|
||||
@@ -58,6 +60,7 @@ sys.path.insert(0, str(ROOT / 'tools'))
|
||||
import check_content # noqa: E402
|
||||
import dlss_pin # noqa: E402
|
||||
import prompt_art # noqa: E402
|
||||
import streamline_pin # noqa: E402
|
||||
from launcher import toolchain # noqa: E402
|
||||
from launcher.paths import Layout # noqa: E402
|
||||
|
||||
@@ -172,50 +175,6 @@ def build_python(py):
|
||||
|
||||
# ---------------------------------------------------------------- app/<version>/
|
||||
|
||||
# DLSS Frame Generation: the files tools/make_game.py DLSSG_FILES names, put beside the game from bin/dlssg/.
|
||||
DLSSG_FILES = ('nx2navi_dlssg.dll', 'sl.interposer.dll', 'sl.common.dll', 'sl.dlss_g.dll', 'sl.pcl.dll', 'sl.reflex.dll',
|
||||
'nvngx_dlssg.dll')
|
||||
DLSSG_NOTICE = 'dlssg-NOTICE.txt'
|
||||
|
||||
|
||||
def place_dlssg(dll, sdk, dest):
|
||||
"""DLSS Frame Generation into dest (the release's bin/dlssg/): nx2navi_dlssg.dll (tools/build_dlssg.py), NVIDIA
|
||||
Streamline's interposer and the plugins it loads, and NGX's nvngx_dlssg.dll, unmodified from the Streamline SDK's
|
||||
bin/x64, with Streamline's licence (MIT), the NVIDIA RTX SDKs License that covers nvngx_dlssg.dll, and a notice
|
||||
naming each file's sha256."""
|
||||
sdk_bin = sdk / 'bin' / 'x64'
|
||||
srcs = {n: (dll if n == 'nx2navi_dlssg.dll' else sdk_bin / n) for n in DLSSG_FILES}
|
||||
texts = {'streamline-LICENSE.txt': sdk / 'license.txt',
|
||||
'nvidia-rtx-sdks-LICENSE.txt': sdk_bin / 'nvngx_dlss.license.txt'}
|
||||
missing = [str(p) for p in (*srcs.values(), *texts.values()) if not p.is_file()]
|
||||
if missing:
|
||||
sys.exit(f'DLSS Frame Generation: {", ".join(missing)} missing')
|
||||
dest.mkdir(parents=True, exist_ok=True)
|
||||
lines = ['DLSS Frame Generation for NX2navi. nx2navi_dlssg.dll is NX2navi\'s own code (runtime/dlssg/), built',
|
||||
'with the Streamline SDK\'s headers. The other files are NVIDIA\'s own builds, unmodified, from the',
|
||||
f'{streamline_version(sdk)} SDK (https://github.com/NVIDIA-RTX/Streamline): the sl.*.dll files under its',
|
||||
'MIT licence (streamline-LICENSE.txt), nvngx_dlssg.dll under the NVIDIA RTX SDKs License',
|
||||
'(nvidia-rtx-sdks-LICENSE.txt), which licenses it only for use on systems with NVIDIA GPUs. They are not',
|
||||
'part of NX2navi and NX2navi\'s licence does not cover them.', '']
|
||||
for n, p in srcs.items():
|
||||
shutil.copy2(p, dest / n)
|
||||
lines.append(f'{n} sha256 {sha256_file(p)}')
|
||||
for n, p in texts.items():
|
||||
shutil.copy2(p, dest / n)
|
||||
(dest / DLSSG_NOTICE).write_text('\n'.join(lines) + '\n', encoding='utf-8')
|
||||
|
||||
|
||||
def streamline_version(sdk):
|
||||
"""'Streamline 2.14.16' from the SDK's README title line, or 'Streamline' when it names none."""
|
||||
try:
|
||||
for line in (sdk / 'README.md').read_text(encoding='utf-8', errors='replace').splitlines()[:5]:
|
||||
if 'Version' in line:
|
||||
return 'Streamline ' + line.rsplit('Version', 1)[1].strip()
|
||||
except OSError:
|
||||
pass
|
||||
return 'Streamline'
|
||||
|
||||
|
||||
def build_app(app, ver, xlate, feed_repo, lock, ffx=None, dlss=None, art=None, dlssg=None):
|
||||
copy_tree(ROOT / 'launcher', app / 'launcher')
|
||||
for d in ('runtime', 'recomp'):
|
||||
@@ -237,7 +196,7 @@ def build_app(app, ver, xlate, feed_repo, lock, ffx=None, dlss=None, art=None, d
|
||||
if dlss: # DLSS: NGX loads it from beside the game (runtime/vk_dlaa.c); make_game.py copies it there
|
||||
dlss_pin.place(dlss, app / 'bin')
|
||||
if dlssg: # DLSS Frame Generation (runtime/vk_dlssg.c): make_game.py place_dlssg copies it beside the game
|
||||
place_dlssg(dlssg[0], dlssg[1], app / 'bin' / 'dlssg')
|
||||
streamline_pin.place(dlssg[0], dlssg[1], app / 'bin' / 'dlssg')
|
||||
if art: # make_game.py draws the button prompts from it (its prompts step)
|
||||
n, size = prompt_art.copy_art(art, app / prompt_art.FOLDER)
|
||||
say(f'button art: {n} pictures, {size / 1e6:.1f} MB')
|
||||
@@ -354,9 +313,10 @@ def main():
|
||||
"downloading it from NVIDIA's DLSS SDK repository")
|
||||
ap.add_argument('--no-dlss', action='store_true', help='leave NVIDIA DLSS out of the release')
|
||||
ap.add_argument('--dlssg', type=Path, metavar='DLL',
|
||||
help='nx2navi_dlssg.dll (tools/build_dlssg.py) for DLSS Frame Generation, with --streamline')
|
||||
help='nx2navi_dlssg.dll (tools/build_dlssg.py) for DLSS Frame Generation')
|
||||
ap.add_argument('--streamline', type=Path, metavar='SDK',
|
||||
help='the Streamline SDK folder whose bin/x64 gives the Streamline and nvngx_dlssg.dll files')
|
||||
help=f'the Streamline {streamline_pin.VERSION} SDK folder whose bin/x64 gives the Streamline and '
|
||||
'nvngx_dlssg.dll files, instead of downloading the SDK release with --dlssg')
|
||||
ap.add_argument('--prompt-art', type=Path, nargs='+', metavar='FOLDER',
|
||||
help='the button art: folders holding XGamepad, P5Gamepad and Keyboard_Mouse, or those folders')
|
||||
ap.add_argument('--out', type=Path, default=MAIN_ROOT / 'build' / 'launcher-release')
|
||||
@@ -386,10 +346,10 @@ def main():
|
||||
+ (f' (CLANG64 clang left out: {lock["fast_skipped"]})' if lock.get('fast_skipped') else ''))
|
||||
dlss = None if a.no_dlss else dlss_pin.resolve(a.dlss, DL)
|
||||
say(f'NVIDIA DLSS {dlss_pin.VERSION}: {dlss}' if dlss else 'NVIDIA DLSS left out (--no-dlss)')
|
||||
if bool(a.dlssg) != bool(a.streamline):
|
||||
sys.exit('--dlssg and --streamline go together')
|
||||
dlssg = (a.dlssg, a.streamline) if a.dlssg else None
|
||||
say(f'DLSS Frame Generation: {a.dlssg}, {streamline_version(a.streamline)}' if dlssg
|
||||
if a.streamline and not a.dlssg:
|
||||
sys.exit('--streamline goes with --dlssg')
|
||||
dlssg = (a.dlssg, streamline_pin.resolve(a.streamline, DL)) if a.dlssg else None
|
||||
say(f'DLSS Frame Generation: {a.dlssg}, Streamline {streamline_pin.VERSION}: {dlssg[1]}' if dlssg
|
||||
else 'DLSS Frame Generation left out (no --dlssg)')
|
||||
build_app(folder / 'app' / ver, ver, a.xlate, a.feed, lock, a.ffx, dlss, a.prompt_art, dlssg)
|
||||
(folder / 'app' / 'current.txt').write_text(ver + '\n', encoding='utf-8')
|
||||
|
||||
118
tools/streamline_pin.py
Normal file
118
tools/streamline_pin.py
Normal file
@@ -0,0 +1,118 @@
|
||||
"""NVIDIA Streamline's runtime for DLSS Frame Generation (runtime/vk_dlssg.c): tools/make_launcher.py and
|
||||
tools/make_kit.py put it in the release's or the kit's bin/dlssg/ beside nx2navi_dlssg.dll (tools/build_dlssg.py), and
|
||||
tools/make_game.py place_dlssg copies the whole set beside the game.
|
||||
|
||||
The files are NVIDIA's own builds from the Streamline SDK release at a pinned version, unmodified: the SDK archive is
|
||||
downloaded once, checked against its size and SHA-256, and only the files the game loads are kept, each checked
|
||||
against its own SHA-256. The sl.*.dll files are under Streamline's MIT licence; nvngx_dlssg.dll is under the NVIDIA RTX
|
||||
SDKs License, which licenses it only for use on systems with NVIDIA GPUs. The notice written beside them names the
|
||||
version and each file's sha256.
|
||||
"""
|
||||
import shutil
|
||||
import sys
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
VERSION = '2.14.16'
|
||||
URL = f'https://github.com/NVIDIA-RTX/Streamline/releases/download/v{VERSION}/streamline-sdk-v{VERSION}.zip'
|
||||
SIZE = 276016170
|
||||
SHA256 = '32041e51db0cab709a271b72a352281b690c2abbd669a827809401a5dd23956b'
|
||||
|
||||
DLL = 'nx2navi_dlssg.dll' # this repository's runtime/dlssg/, built by tools/build_dlssg.py
|
||||
# The set tools/make_game.py DLSSG_FILES names: without all of it the game leaves DLSS Frame Generation off.
|
||||
FILES = (DLL, 'sl.interposer.dll', 'sl.common.dll', 'sl.dlss_g.dll', 'sl.pcl.dll', 'sl.reflex.dll', 'nvngx_dlssg.dll')
|
||||
NOTICE = 'dlssg-NOTICE.txt'
|
||||
# The SDK's files the set takes, by their path in the SDK, with their sha256.
|
||||
SDK_FILES = {
|
||||
'bin/x64/sl.interposer.dll': 'b1d7395aebd7b9722841d64dcf7433680020b6a8e421f851c16d5ba0c2182edf',
|
||||
'bin/x64/sl.common.dll': '38eea3b4209afc455636ea372b5933d65fcc13becec6c84d101dcfc4d8648f75',
|
||||
'bin/x64/sl.dlss_g.dll': '3ed9538df724993bea8a050195a6a78b9c8c8a566d5b05ade477aab3c390e90f',
|
||||
'bin/x64/sl.pcl.dll': '5698c38e722318681f215c9fe68e45b9bedd51378acc699d8eee26e961e57770',
|
||||
'bin/x64/sl.reflex.dll': '443577e869352436ff7ec8f4d9c90418d3e95368436ce219261e0f4f07a38122',
|
||||
'bin/x64/nvngx_dlssg.dll': '8d59d49b36410dd6b62fef2503a5871d347415bd85d943fa0848563a95dd50c7',
|
||||
'license.txt': '7b6f23e7d6f3ad6292f9308d2b42cdc3d82ae4e9b2abb55f230279d83bedd43d',
|
||||
'bin/x64/nvngx_dlss.license.txt': '3027f23ca5a46dd9cb8183fbd522983a86f64d7daac5982912bf9f214671f294',
|
||||
}
|
||||
# The licence texts beside the DLLs, by the SDK file each is copied from.
|
||||
TEXTS = {'streamline-LICENSE.txt': 'license.txt', 'nvidia-rtx-sdks-LICENSE.txt': 'bin/x64/nvngx_dlss.license.txt'}
|
||||
|
||||
|
||||
def sha256_file(path):
|
||||
import hashlib
|
||||
h = hashlib.sha256()
|
||||
with open(path, 'rb') as f:
|
||||
while b := f.read(1 << 20):
|
||||
h.update(b)
|
||||
return h.hexdigest()
|
||||
|
||||
|
||||
def wrong_files(sdk):
|
||||
"""The pinned SDK files that are missing from sdk or differ from the pin."""
|
||||
sdk = Path(sdk)
|
||||
return [n for n, h in SDK_FILES.items() if not (sdk / n).is_file() or sha256_file(sdk / n) != h]
|
||||
|
||||
|
||||
def resolve(sdk, cache_dir):
|
||||
"""A folder laid out as the SDK is that holds the pinned files: sdk when given (its files must be the pinned
|
||||
ones), else cache_dir/streamline-<version>, filled from the SDK archive when missing (downloaded with
|
||||
launcher/net.py: resumed, checked against the size and SHA-256, and deleted once its files are out)."""
|
||||
if sdk:
|
||||
sdk = Path(sdk)
|
||||
if not sdk.is_dir():
|
||||
raise SystemExit(f'{sdk} does not exist')
|
||||
bad = wrong_files(sdk)
|
||||
if bad:
|
||||
raise SystemExit(f'{sdk} is not the Streamline {VERSION} SDK ({", ".join(bad)} missing or different); '
|
||||
'another Streamline needs VERSION, SIZE, SHA256 and SDK_FILES in tools/streamline_pin.py '
|
||||
'changed first')
|
||||
return sdk
|
||||
dest = Path(cache_dir) / f'streamline-{VERSION}'
|
||||
if not wrong_files(dest):
|
||||
return dest
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
from launcher import net
|
||||
archive = Path(cache_dir) / f'streamline-sdk-v{VERSION}.zip'
|
||||
if not (archive.is_file() and archive.stat().st_size == SIZE):
|
||||
print(f'download {URL} ({SIZE / 1e6:.0f} MB)', flush=True)
|
||||
net.download(URL, archive, sha256=SHA256, size=SIZE)
|
||||
extract(archive, dest)
|
||||
archive.unlink()
|
||||
return dest
|
||||
|
||||
|
||||
def extract(archive, dest):
|
||||
"""The pinned files out of the SDK archive into dest, each checked against its sha256."""
|
||||
import hashlib
|
||||
with zipfile.ZipFile(archive) as z:
|
||||
names = {n.replace('\\', '/'): n for n in z.namelist()}
|
||||
for n, h in SDK_FILES.items():
|
||||
if n not in names:
|
||||
raise SystemExit(f'{archive.name} has no {n}')
|
||||
data = z.read(names[n])
|
||||
if hashlib.sha256(data).hexdigest() != h:
|
||||
raise SystemExit(f'{n} in {archive.name} differs from the pinned file')
|
||||
(dest / n).parent.mkdir(parents=True, exist_ok=True)
|
||||
(dest / n).write_bytes(data)
|
||||
|
||||
|
||||
def place(dll, sdk, dest):
|
||||
"""DLSS Frame Generation into dest (a release's or the kit's bin/dlssg/): nx2navi_dlssg.dll, Streamline's
|
||||
interposer and the plugins it loads, and NGX's nvngx_dlssg.dll from the SDK folder resolve returned, the two
|
||||
licence texts, and a notice naming each file's sha256."""
|
||||
dll, sdk, dest = Path(dll), Path(sdk), Path(dest)
|
||||
if not dll.is_file():
|
||||
raise SystemExit(f'{dll} does not exist')
|
||||
srcs = {n: (dll if n == DLL else sdk / 'bin' / 'x64' / n) for n in FILES}
|
||||
dest.mkdir(parents=True, exist_ok=True)
|
||||
lines = ['DLSS Frame Generation for NX2navi. nx2navi_dlssg.dll is NX2navi\'s own code (runtime/dlssg/), built',
|
||||
'with the Streamline SDK\'s headers. The other files are NVIDIA\'s own builds, unmodified, from the',
|
||||
f'Streamline {VERSION} SDK (https://github.com/NVIDIA-RTX/Streamline): the sl.*.dll files under its',
|
||||
'MIT licence (streamline-LICENSE.txt), nvngx_dlssg.dll under the NVIDIA RTX SDKs License',
|
||||
'(nvidia-rtx-sdks-LICENSE.txt), which licenses it only for use on systems with NVIDIA GPUs. They are not',
|
||||
'part of NX2navi and NX2navi\'s licence does not cover them.', '']
|
||||
for n, p in srcs.items():
|
||||
shutil.copy2(p, dest / n)
|
||||
lines.append(f'{n} sha256 {sha256_file(p)}')
|
||||
for n, src in TEXTS.items():
|
||||
shutil.copy2(sdk / src, dest / n)
|
||||
(dest / NOTICE).write_text('\n'.join(lines) + '\n', encoding='utf-8')
|
||||
Reference in New Issue
Block a user