Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 28 additions & 3 deletions gpu/vk/vk_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,9 +223,30 @@ bool create_device() {
flag = has_extension(exts, name);
if (flag) want.push_back(name);
};
// (RX_VK_FORCE_MESH_FALLBACK=1, a test: mesh shaders not used where they are, so the no-mesh fallback the GTX 10xx and RX 5000
// cards run (issue 640) can be tried on any GPU)
if (getenv("RX_VK_FORCE_MESH_FALLBACK") && atoi(getenv("RX_VK_FORCE_MESH_FALLBACK")) != 0) dev.mesh_shader = false;
// (the Graphics tab's Mesh shaders row, mesh_shaders= in hookshot_options.ini, #1001: 0 Automatic (native where there are mesh
// shaders, the compute fallback where not and for the task + mesh draws of the cards below), 1 Native (no fallback where
// there are mesh shaders), 2 Compute (the fallback on every GPU). RX_VK_FORCE_MESH_FALLBACK=1, a test, is Compute over it:
// mesh shaders not used where they are, so the no-mesh fallback the GTX 10xx and RX 5000 cards run (issue 640) can be tried
// on any GPU)
static const int mesh_mode = [] {
char exe[MAX_PATH];
const DWORD len = game_module_path(exe, MAX_PATH); // (the game folder, not bin beside the launcher: vk_paths.h)
std::string ini(exe, len);
ini = ini.substr(0, ini.find_last_of("\\/") + 1) + "hookshot_options.ini";
int v = 0;
if (FILE* fl = fopen(ini.c_str(), "r")) {
char line[80];
while (fgets(line, sizeof line, fl))
if (!strncmp(line, "mesh_shaders=", 13)) {
v = atoi(line + 13);
break;
}
fclose(fl);
}
if (const char* e = getenv("RX_VK_FORCE_MESH_FALLBACK")) v = atoi(e) != 0 ? 2 : v;
return v >= 0 && v <= 2 ? v : 0;
}();
if (mesh_mode == 2) dev.mesh_shader = false;
else optional(VK_EXT_MESH_SHADER_EXTENSION_NAME, dev.mesh_shader);
optional(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, dev.external_memory_host);
optional(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, dev.external_memory_fd); // (guest memory as udmabufs: vk_memory.cpp import_dma_buf)
Expand Down Expand Up @@ -434,9 +455,13 @@ bool create_device() {
// Navi 22 can time out on task + mesh draws in the AMD Windows driver (issue 996).
task_mesh_fallback = dev.props.vendorID == 0x1002 && dev.props.deviceID == 0x73df;
#endif
if (mesh_mode == 1) task_mesh_fallback = false; // (Native: the card's own mesh shaders for every draw)
if (const char* e = getenv("RX_VK_TASK_MESH_FALLBACK")) task_mesh_fallback = atoi(e) != 0;
dev.task_mesh_fallback = task_mesh_fallback && dev.mesh_shader && f12.bufferDeviceAddress && !getenv("RX_VK_NO_MESH_FALLBACK");
if (dev.task_mesh_fallback) logf("vk: task + mesh programs use the compute fallback (RX_VK_TASK_MESH_FALLBACK=0: native)");
logf("vk: mesh shaders row: %s (%s)", mesh_mode == 2 ? "Compute" : mesh_mode == 1 ? "Native" : "Automatic",
dev.mesh_shader ? (dev.task_mesh_fallback ? "native, task + mesh draws on the compute path" : "native")
: dev.mesh_fallback ? "the compute path" : "none");
if (robust) logf("vk: robust buffer access %s", robust_ok ? "on" : "not supported");
f.features.robustBufferAccess = robust_ok ? VK_TRUE : VK_FALSE; // (off by default: the game's accesses stay in their buffers)
dev.features = f.features;
Expand Down
11 changes: 11 additions & 0 deletions gpu/vk/vk_menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,10 @@ const char* tx_robust(int v) {
static const char* t[] = {"Auto", "Off", "On"};
return (unsigned)v < 3 ? t[v] : t[0];
}
const char* tx_mesh_mode(int v) {
static const char* t[] = {"Automatic", "Native", "Compute"};
return (unsigned)v < 3 ? t[v] : t[0];
}
const char* tx_preset(int v) {
static const char* t[] = {"Custom", "Minimum (4GB)", "Low (6GB)", "Balanced (8GB)", "High (12GB)", "Ultra (16GB+)"};
return t[std::min(std::max(v, 0), 5)];
Expand Down Expand Up @@ -603,6 +607,9 @@ MENU_HINTS(hn_wide_menus, 0, "The menus stretched over the whole screen, as befo
"The menus in the middle 16:9; beside them, what the game draws there, out of focus.",
"The menus in the middle 16:9; black beside them.")
MENU_HINTS(hn_robust, 0, "On, on every card.", "Can be faster on some NVIDIA cards.", "Always on.")
MENU_HINTS(hn_mesh_mode, 0, "The GPU's own mesh shaders where it has them, the compute path where it has not.",
"The GPU's own mesh shaders for every draw. A GPU without them still uses the compute path.",
"The compute path on every GPU: try it if your card crashes or leaves objects out. Usually a little slower.")
MENU_HINTS(hn_fps, 0, nullptr, "With frame generation on, the game's own rate too.")
MENU_HINTS(hn_menu_size, 1, "Smaller, for a desk.", "The usual size.", "Larger, for a TV across the room.")
MENU_HINTS(hn_speed, 0, "A step each frame: the game slows down whenever it runs below 60 fps.",
Expand Down Expand Up @@ -685,6 +692,9 @@ Row rows[] = {
{TAB_GRAPHICS, "Robust buffers", &opts.robust, 0, 2, 1, tx_robust,
"Bounds-checked buffer reads: a read past a buffer's end is dropped instead of stopping the GPU. Applies after a "
"restart.", hn_robust, true},
{TAB_GRAPHICS, "Mesh shaders", &opts.mesh_mode, 0, 2, 1, tx_mesh_mode,
"How the game's mesh programs (much of the scenery) run: on the GPU's own mesh shaders, or as compute shaders, which "
"every GPU has. Applies after a restart.", hn_mesh_mode, true},

// Audio
{TAB_AUDIO, "Volume", &opts.volume, 0, 100, 5, tx_percent,
Expand Down Expand Up @@ -1072,6 +1082,7 @@ const char* ini_key(const Row& r) {
if (r.value == &opts.upscale) return "upscaling";
if (r.value == &opts.dlss) return "dlss"; // (as opts.dlss and RX_VK_DLSS)
if (r.value == &opts.handheld) return "handheld_profile"; // (the Profile row; host/nn_applet.c reads it at the start)
if (r.value == &opts.mesh_mode) return "mesh_shaders"; // (gpu/vk/vk_main.cpp reads it as the device is made)
static char k[32];
size_t n = 0;
for (const char* p = r.name; *p && n + 1 < sizeof k; p++) k[n++] = *p == ' ' ? '_' : (char)tolower(*p);
Expand Down
2 changes: 2 additions & 0 deletions gpu/vk/vk_menu.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ struct Options {
int gyro_deadzone = 1; // the motion's deadzone: 0 tight, 1 standard (the console's default), 2 loose
int prompts = 0; // the button icons: 0 Auto (the controller), 1 Switch, 2 Xbox, 3 PS4, 4 PS5, 5 Steam Deck (host/prompts.c)
int robust = 0; // bounds-checked buffer access: 0 Auto (on), 1 Off, 2 On (gpu/vk/vk_main.cpp; RX_VK_ROBUST)
int mesh_mode = 0; // task and mesh programs: 0 Automatic, 1 Native, 2 Compute (gpu/vk/vk_main.cpp: mesh_shaders=;
// RX_VK_FORCE_MESH_FALLBACK and RX_VK_TASK_MESH_FALLBACK over it)
int descriptor_reuse = 1; // (on by default since options_version 4) a draw keeps its descriptors through other slots' registrations (gpu/vk/vk_draw.cpp; RX_VK_DESC_SLOTGEN)
int sampler_cache = 0; // sampler ids answer their parameters without the registrations' lock (gpu/vk/vk_draw.cpp; RX_VK_SAMPLER_CACHE)
int preset = 0; // quality preset: 0 Custom, 1 Minimum (4GB), 2 Low (6GB), 3 Balanced (8GB), 4 High (12GB), 5 Ultra (16GB+)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_audio_output_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
static int au_device_channels(void) { device_asked++; return device_channels; }
HOST
struct Row { int tab; const char* name; int* value; };
struct { int output_res, resolution, fps_cap, upscale, dlss, handheld, audio_output; } opts;
struct { int output_res, resolution, fps_cap, upscale, dlss, handheld, mesh_mode, audio_output; } opts;
MENU
int main(int argc, char **argv) {
assert(argc == 7);
Expand Down
2 changes: 1 addition & 1 deletion tests/test_stick_dead_zone.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ def main():
#include <cstring>
#define CHECK(x) do { if (!(x)) { fprintf(stderr, "FAIL:%d %s\n", __LINE__, #x); exit(1); } } while (0)
enum MenuTab { TAB_CONTROLS };
struct Options { int output_res = 0, resolution = 0, fps_cap = 0, upscale = 0, dlss = 0, handheld = 0, stick_dead_zone = 0; } opts;
struct Options { int output_res = 0, resolution = 0, fps_cap = 0, upscale = 0, dlss = 0, handheld = 0, mesh_mode = 0, stick_dead_zone = 0; } opts;
static int parse_output(const char* text) { return atoi(text); } // (the Output row's own parse: not what this checks)
''' + block(menu, "struct Row {") + ";\n" + block(menu, "const char* tx_stick_dead_zone(") + "\n" + \
"Row rows[] = {" + row.group(0) + "};\n" + block(menu, "const char* ini_key(") + r'''
Expand Down
Loading