mirror of
https://github.com/valentderah/totk-pc-recomp.git
synced 2026-11-11 01:41:02 +00:00
Keep #594's DLSS work off for players without DLSS
The scene patch, the heap sized for the largest DLSS scene and the function-entry hook that catches the game's render size setup were on for every 1.4.3 player; they are on now only when DLSS can run (dlaa = 1, nvngx_dlss.dll there), and the hook gives up after 1800 presents if the setup is never seen. Everyone else keeps the game's own scene size and dynamic resolution, as before #594. The uniform snapshot's second copy in host memory and the per-object motion's last-frame blocks are made only while DLSS is available: without it nothing reads them, and the snapshot goes into the device copy in one pass as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
80349df1a6
commit
13b602f28f
3 files changed
+37
-13
No files matched your search
+19
-6
@@ -56,6 +56,7 @@ static struct {
|
||||
double dlss_k; // TOTK_DLSS quality/balanced/performance/ultra_performance: the scene's share of the output, else 0
|
||||
double base_k; // the scene's share without a DLSS mode (render_scale, or the game's 5/6)
|
||||
unsigned hw, hh; // the largest scene a DLSS mode change can ask for: the heap is sized for it
|
||||
int live; // 1.4.3 with DLSS able to run: the DLSS mode can change while the game runs
|
||||
} R;
|
||||
|
||||
// The scene size is decided before the device exists, so NGX cannot be asked yet. NGX loads DLSS from nvngx_dlss.dll
|
||||
@@ -130,15 +131,20 @@ static void decide(void) {
|
||||
rt_log("resolution: TOTK_RENDER_SCALE=%s is not game or a percentage 25..400; game", s);
|
||||
}
|
||||
}
|
||||
// A DLSS mode other than dlaa sets the scene size instead, and can change while the game runs (res_dlss_mode): the
|
||||
// scene patch is always on, and the heap is sized for the largest scene the modes ask for.
|
||||
// A DLSS mode other than dlaa sets the scene size instead. On 1.4.3 with DLSS able to run (DLAA on, the DLL there)
|
||||
// the mode can change while the game runs (res_dlss_mode): the scene patch is then always on and the heap is sized
|
||||
// for the largest scene the modes ask for. Everyone else keeps the game's own scene size and its dynamic resolution
|
||||
// unless render_scale or a DLSS mode asks for another, and a heap sized for that scene alone.
|
||||
R.base_k = k;
|
||||
R.scene_set = 1;
|
||||
R.live = RT_V143 && cfg_bool("TOTK_DLAA") && dlss_dll();
|
||||
const char *m = cfg_value("TOTK_DLSS");
|
||||
R.dlss_k = dlss_share(m);
|
||||
if (R.dlss_k) rt_log("resolution: DLSS %s: the scene at %.0f %% of the output (render_scale ignored)", m, R.dlss_k * 100);
|
||||
scene_for(R.dlss_k ? R.dlss_k : k, &R.sw, &R.sh);
|
||||
scene_for(fmax(k, 2.0 / 3.0), &R.hw, &R.hh);
|
||||
double sk = R.dlss_k ? R.dlss_k : k;
|
||||
if (R.live || R.dlss_k || R.ow * sk > SCENE_MAX || R.oh * sk > SCENE_MAX) R.scene_set = 1;
|
||||
scene_for(sk, &R.sw, &R.sh);
|
||||
if (R.live) scene_for(fmax(k, 2.0 / 3.0), &R.hw, &R.hh);
|
||||
else R.hw = R.sw, R.hh = R.sh;
|
||||
const char *sr = cfg_value("TOTK_SHADOW_RES");
|
||||
if (strcmp(sr, "game")) {
|
||||
unsigned n = (unsigned)atoi(sr);
|
||||
@@ -326,7 +332,7 @@ void res_init(void) {
|
||||
rt_patch_switch(output, R.ow != BASE_W || R.oh != BASE_H);
|
||||
rt_patch_switch(scene, scene_on);
|
||||
R.on = 1;
|
||||
if (RT_V143) g_fnprof = 1; // until the game sets its render size: res_fn_hit
|
||||
if (R.live) g_fnprof = 1; // until the game sets its render size: res_fn_hit, or res_present gives up
|
||||
// Another shape than 16:9 (more than 1% off): the camera takes the output's ratio (recomp/patches-v121.txt and
|
||||
// patches-v143.txt, set aspect), so a 21:9 output shows more of the world at the sides instead of a stretched 16:9 view. The HUD's layouts
|
||||
// for that shape come from romfs-patches-<w>x<h> (romfs.c overlay_init, tools/make_romfs_patches.py --aspect).
|
||||
@@ -415,6 +421,13 @@ void res_fn_hit(uint64_t addr, uint64_t x0) {
|
||||
}
|
||||
|
||||
void res_present(Cpu *c) {
|
||||
// The hook runs on every guest function entry while it waits: should the game set its render size before
|
||||
// res_init or never, it stops after 1800 presents (half a minute at 60 fps) and modes change at the next start.
|
||||
static unsigned waited;
|
||||
if (g_fnprof && !renderer && ++waited == 1800) {
|
||||
g_fnprof = 0;
|
||||
rt_log("resolution: the game's render size setup was not seen; DLSS modes change at the next start");
|
||||
}
|
||||
if (!size_pending || !renderer) return;
|
||||
size_pending = 0;
|
||||
Cpu keep = *c; // the guest's registers as at the present call: the setup runs as if it never happened
|
||||
|
||||
@@ -172,6 +172,8 @@ static void mvprev_draw_(VkExec *ex) {
|
||||
}
|
||||
|
||||
void vk_mvprev_frame(void) {
|
||||
// without DLSS (no NGX, no RTX GPU, dlaa = 0) nothing reads last frame's blocks: P.on stays 0, no tables
|
||||
if (!vk_dlaa_available()) return;
|
||||
if (P.knob < 0) {
|
||||
P.knob = rt_knob("DLAA_OBJMV", "1");
|
||||
if (P.knob) {
|
||||
|
||||
+16
-7
@@ -22,6 +22,7 @@
|
||||
#include "host.h"
|
||||
#include "nvn_api.h"
|
||||
#include "vk.h"
|
||||
#include "vk_dlaa.h"
|
||||
#include "platform/platform.h"
|
||||
|
||||
#define ALIGN 256u
|
||||
@@ -34,8 +35,9 @@ typedef struct Arena {
|
||||
VkBuffer buf;
|
||||
VmaAllocation alloc;
|
||||
uint8_t *map;
|
||||
uint8_t *cpu; // the same bytes in host memory, for the CPU's reads (vk_usnap_bytes): map is often device memory
|
||||
// through the BAR, written fast but read back at about a microsecond a cache line
|
||||
uint8_t *cpu; // with DLSS (vk_dlaa_available), the same bytes in host memory for the CPU's reads (vk_usnap_bytes):
|
||||
// map is often device memory through the BAR, written fast but read back at about a microsecond a
|
||||
// cache line. Without DLSS nothing reads them back, and the bytes go into map in one copy.
|
||||
uint64_t size;
|
||||
} Arena;
|
||||
|
||||
@@ -98,7 +100,6 @@ static Arena *arena_get(uint64_t need) {
|
||||
return NULL;
|
||||
}
|
||||
a->map = info.pMappedData;
|
||||
if (!(a->cpu = malloc(a->size))) rt_fatal("vk_usnap: out of memory");
|
||||
rt_log("vk_usnap: new arena of %.1f MiB", a->size / 1048576.0);
|
||||
return a;
|
||||
}
|
||||
@@ -283,9 +284,14 @@ void vk_usnap_begin(const uint64_t *handles, int n, uint64_t fence) {
|
||||
}
|
||||
if (!U.nreg) return;
|
||||
if (!(U.arena = arena_get(total))) return;
|
||||
uint8_t *dst = U.arena->map;
|
||||
if (vk_dlaa_available()) {
|
||||
if (!U.arena->cpu && !(U.arena->cpu = malloc(U.arena->size))) rt_fatal("vk_usnap: out of memory");
|
||||
dst = U.arena->cpu;
|
||||
}
|
||||
for (int i = 0; i < U.nreg; i++)
|
||||
memcpy(U.arena->cpu + U.reg[i].off, (const void *)(uintptr_t)U.reg[i].lo, U.reg[i].hi - U.reg[i].lo);
|
||||
memcpy(U.arena->map, U.arena->cpu, total); // one sequential write into the device copy
|
||||
memcpy(dst + U.reg[i].off, (const void *)(uintptr_t)U.reg[i].lo, U.reg[i].hi - U.reg[i].lo);
|
||||
if (dst != U.arena->map) memcpy(U.arena->map, dst, total); // one sequential write into the device copy
|
||||
vmaFlushAllocation(vk_ctx()->vma, U.arena->alloc, 0, total); // a no-op on coherent memory
|
||||
U.on = 1;
|
||||
U.subs++, U.regions += (uint64_t)U.nreg, U.bytes += total, U.copy_ns += kern_now_ns() - t0;
|
||||
@@ -331,11 +337,14 @@ void vk_usnap_drop(uint64_t addr, uint64_t n) {
|
||||
|
||||
uint64_t vk_usnap_gen(void) { return U.gen; }
|
||||
|
||||
const uint8_t *vk_usnap_map(void) { return U.arena ? U.arena->cpu : NULL; }
|
||||
// the host copy where there is one (DLSS), else the device copy
|
||||
static uint8_t *host_copy(void) { return U.arena->cpu ? U.arena->cpu : U.arena->map; }
|
||||
|
||||
const uint8_t *vk_usnap_map(void) { return U.arena ? host_copy() : NULL; }
|
||||
|
||||
const uint8_t *vk_usnap_bytes(uint64_t addr, uint64_t n) {
|
||||
VkDescriptorBufferInfo bi;
|
||||
return vk_usnap_find(addr, n, 1, &bi) ? U.arena->cpu + bi.offset : NULL;
|
||||
return vk_usnap_find(addr, n, 1, &bi) ? host_copy() + bi.offset : NULL;
|
||||
}
|
||||
|
||||
// The arenas back on the free list (vk_exec_draw_shutdown: the device is idle, every completion ran).
|
||||
|
||||
Reference in new issue
Block a user