mirror of
https://github.com/spoopyghosty0/frameport.git
synced 2026-10-18 02:01:25 +02:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c183477808 |
No files matched your search
@@ -8,7 +8,7 @@ d6337034fb0bdcca7ef9b7063d85b7586b8508b63b435959e8fffaba0691091c ./arm64-v8a/li
|
||||
321da502e0f8f46f0880aad39fe6b84bdef88f925164568814cf704a1b31a577 ./arm64-v8a/libfp_ovrp.so
|
||||
40defdaddcda53bd2649eb48076fae1622bfc2bfc88e9e03c94fc8b45af2a4f2 ./arm64-v8a/libfp_ovrtrace.so
|
||||
0167c2fde5dfde62897f9d85afc4fc8e97784e988b5b8df6cea8c407240b3424 ./arm64-v8a/libfp_tkeys.so
|
||||
468b97ee3c36481d939a87425b15880c7a801d16732350e1e2832b385d63f20a ./arm64-v8a/libfp_vk.so
|
||||
e32f9b3222bfe2e58c193db809ac2cf54086df36fd2ec6651aa2e58308f6b39d ./arm64-v8a/libfp_vk.so
|
||||
383054f8b3b41dde76d062c71856cd3163655e50009c08454bc1793f393ead65 ./arm64-v8a/libfpg.so
|
||||
4a13a33e112c9e4e3c5ff4337ed6e988a9e5b3602f48d654df148ef5fafbf426 ./arm64-v8a/libfpglmv.so
|
||||
36400eae4ba3807bcfcd54463daa217347032b07218792faa448d8cbbd086a0e ./arm64-v8a/libframe_xrshim.so
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
package: com.Meta4.TFBeyondReality
|
||||
title: 'Transformers Beyond Reality: Redux'
|
||||
status: unknown
|
||||
notes: Starts and runs at 72 fps in headless launch tests (2026-10-17); not yet checked in the headset. Steam's shader
|
||||
cache layer is left out and a few shaders the Frame's driver refuses are skipped, so some objects may be missing.
|
||||
details: Unreal Engine game (Binned3 allocator, GitHub issue 349). Crash 1 - the allocator's 76 GiB up-front
|
||||
reservation is refused by the Frame's kernel (frame.unreal_noreserve, suggested by analysis). Crash 2 - Unreal's
|
||||
"Shader compilation failures are Fatal." With Lepton's Fossilize layer loaded every graphics pipeline failed with
|
||||
VK_ERROR_OUT_OF_HOST_MEMORY, even a constant-colour one (not the pipeline cache, not the CPU allocator, not Valve's
|
||||
FDM/RPO layers); vk_no_fossilize takes the layer out of the game's instance. A few pipelines with the game's
|
||||
multiview vertex shaders then still fail in Turnip; vk_pipeline_fallback creates them with blank shaders.
|
||||
tested_version: 1.495.34291
|
||||
engine: Unreal
|
||||
xr: OpenXR
|
||||
adapter:
|
||||
vk_no_fossilize: 1
|
||||
vk_pipeline_fallback: 1
|
||||
verified:
|
||||
date: '2026-10-17'
|
||||
issue: 349
|
||||
@@ -301,6 +301,16 @@ signatures:
|
||||
piece (for example Transformers Beyond Reality). Rebuild with the reservation marked as not committed.
|
||||
suggest: [frame.unreal_noreserve]
|
||||
supersedes: [native-crash]
|
||||
- id: vulkan-pipeline-refused
|
||||
# GitHub #349: with Lepton's Fossilize layer loaded every Transformers pipeline failed with -1; without it a few
|
||||
# multiview vertex shaders still fail in Turnip. Unreal ends at the first one.
|
||||
pattern: '(Shader compilation failures are Fatal|vk shim: vkCreateGraphicsPipelines failed: -\d+)'
|
||||
severity: fatal
|
||||
diagnosis: The Frame's graphics driver refused to build some of the game's shaders, and Unreal ends the game at the
|
||||
first one (for example Transformers Beyond Reality). Try leaving out Steam's shader cache layer, and skipping the
|
||||
shaders the driver still refuses (they then draw nothing).
|
||||
suggest: [adapter.vk_no_fossilize, adapter.vk_pipeline_fallback]
|
||||
supersedes: [native-crash, force-quit]
|
||||
- id: graphics-requirements-missing
|
||||
pattern: '(XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING|Failed to create XR session: -50\b|xrCreateSession[^\n]*-50\b)'
|
||||
severity: fatal
|
||||
|
||||
@@ -639,3 +639,21 @@ the entry's `link` record (+ `direct`); `pipeline.check_link_updates` (GUI start
|
||||
`link_bar` + game page callout → `link_dialog.update_from_link` (fetch again, one confirmation, `download_and_install`
|
||||
per game; add_from_link clears the offer and keeps a name the user gave). CLI `frameport link-updates [--install]`.
|
||||
|
||||
|
||||
## Vulkan pipelines refused: Fossilize and Turnip (Transformers, #349)
|
||||
|
||||
Transformers Beyond Reality: Redux (Unreal, Vulkan) ended its first frames with Unreal's "Shader compilation failures
|
||||
are Fatal." (2026-10-17, headless on the dev Frame). `vk_pipeline_log=1` showed every graphics pipeline failing in
|
||||
pairs: the precache attempt with `VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT` (flags 0x100) answers
|
||||
`1000297000` (= VK_PIPELINE_COMPILE_REQUIRED, normal), the real compile answers `-1` (VK_ERROR_OUT_OF_HOST_MEMORY)
|
||||
in the same millisecond, and the shim never logged a single success. The dumped SPIR-V was valid (spirv-val), one
|
||||
module a constant-colour fragment shader. Ruled out in one run each: the app's VkPipelineCache, its
|
||||
VkAllocationCallbacks (retry without either/both), Valve's VALVE_rpo/VALVE_fdm_injection (`device.foveation: off`).
|
||||
Khronos' validation layer added a crash of its own (null deref in its vkCreateRenderPass2 on the game's create info,
|
||||
the shim changed nothing there): don't use it for this game. Removing `VK_LAYER_fossilize` from GraphicsEnv's debug
|
||||
layer list (`android::GraphicsEnv::setDebugLayers`, as `native/zinkfix` adds its layer) made the pipelines compile:
|
||||
360 modules instead of 10, frames submitted. Two Fossilize instances are still created by other threads before the
|
||||
engine loads the shim; they aren't the renderer's. About six pipelines with the game's multiview vertex shader
|
||||
(module 12944, ViewIndex) still fail in Turnip; a blank fragment shader alone doesn't help, blank vertex + fragment
|
||||
does. Settings `vk_no_fossilize` + `vk_pipeline_fallback` (catalog entry): headless RUNNING after 72 s at 72 fps.
|
||||
Headset check pending (some objects may be missing).
|
||||
+38
-2
@@ -2,7 +2,7 @@
|
||||
|
||||
# Patches
|
||||
|
||||
Every patch and game setting FramePort knows: 179 entries in 5 groups. A game's recipe is its chosen patches and settings; tested games get theirs from the catalog ([GAMES.md](GAMES.md)), and other games get the patches FramePort suggests from its analysis. You change them on the game page under Customize.
|
||||
Every patch and game setting FramePort knows: 181 entries in 5 groups. A game's recipe is its chosen patches and settings; tested games get theirs from the catalog ([GAMES.md](GAMES.md)), and other games get the patches FramePort suggests from its analysis. You change them on the game page under Customize.
|
||||
|
||||
Each entry says what the patch does, whether it changes the APK or only the install, when FramePort suggests it, its options, the catalog games whose recipe names it and the launch-test signatures that suggest it. Patches that are on by default are on for every game, so the catalog rarely names them.
|
||||
|
||||
@@ -12,7 +12,7 @@ Link to an entry with its id, dots replaced by dashes: `PATCHES.md#frame-unity_t
|
||||
|
||||
- [Patches from OVRPort](#group-overport) (25)
|
||||
- [Steam Frame patches](#group-frame) (61)
|
||||
- [Game settings](#group-adapter) (72)
|
||||
- [Game settings](#group-adapter) (74)
|
||||
- [Files and settings on the Frame](#group-device) (8)
|
||||
- [PC VR (Proton and Revive)](#group-pcvr) (13)
|
||||
|
||||
@@ -170,6 +170,8 @@ Link to an entry with its id, dots replaced by dashes: `PATCHES.md#frame-unity_t
|
||||
| [Retry refused picture formats](#adapter-swapchain_fix) | `adapter.swapchain_fix` | Game settings | |
|
||||
| [Steady controller input after focus](#adapter-sync_guard) | `adapter.sync_guard` | Game settings | 3 |
|
||||
| [Hide Vulkan foveation](#adapter-vk_hide_fdm) | `adapter.vk_hide_fdm` | Game settings | 1 |
|
||||
| [Without Steam's shader cache layer](#adapter-vk_no_fossilize) | `adapter.vk_no_fossilize` | Game settings | 1 |
|
||||
| [Skip refused graphics](#adapter-vk_pipeline_fallback) | `adapter.vk_pipeline_fallback` | Game settings | 1 |
|
||||
| [Vulkan pipeline failures (log)](#adapter-vk_pipeline_log) | `adapter.vk_pipeline_log` | Game settings | |
|
||||
| [Stop objects popping in and out](#adapter-vk_query_slots) | `adapter.vk_query_slots` | Game settings | |
|
||||
| [Vulkan shader dump (diagnostics)](#adapter-vk_shader_dump) | `adapter.vk_shader_dump` | Game settings | |
|
||||
@@ -2262,6 +2264,40 @@ For Unreal Engine 5 games that crash on the Frame (for example Metro Awakening).
|
||||
|
||||
> Vulkan shim (frame.vk_sanitize): the game doesn't see VK_EXT_fragment_density_map(2). Unreal Engine 5 turns on fragment-density-map foveation when the driver offers it and expects the density map from the headset, which the Frame doesn't provide: image views and barriers for a missing image, then a crash in the Frame's Vulkan driver (for example Metro Awakening). Valve's own foveation layer isn't affected.
|
||||
|
||||
### <a id="adapter-vk_no_fossilize"></a>Without Steam's shader cache layer
|
||||
|
||||
Some games can't create any graphics with it (for example Transformers Beyond Reality).
|
||||
|
||||
- `adapter.vk_no_fossilize`
|
||||
- **Changes:** Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
|
||||
- **Suggested:** not automatically; set on the game page (Customize), by a recipe or after a launch test.
|
||||
- **Options:**
|
||||
- Value: int, default `0`.
|
||||
- Game settings → Troubleshooting → "Without Steam's shader cache layer" (advanced).
|
||||
- **Catalog games (1):** Transformers Beyond Reality: Redux.
|
||||
- **Suggested by launch-test signatures:**
|
||||
- `vulkan-pipeline-refused` (fatal): The Frame's graphics driver refused to build some of the game's shaders, and Unreal ends the game at the first one (for example Transformers Beyond Reality).
|
||||
- **Source:** [patches/settings.py](../src/frameport/patches/settings.py)
|
||||
|
||||
> Vulkan shim (frame.vk_sanitize): takes Lepton's Fossilize shader-cache layer out of the game's Vulkan layers (Android's debug layer list) when the engine loads its Vulkan library. With Fossilize loaded every graphics pipeline of Transformers Beyond Reality failed (VK_ERROR_OUT_OF_HOST_MEMORY), which Unreal treats as fatal (GitHub #349). Lepton has no switch for it; instances created before the engine loads the shim keep it.
|
||||
|
||||
### <a id="adapter-vk_pipeline_fallback"></a>Skip refused graphics
|
||||
|
||||
When the Frame's driver refuses one of the game's shaders, that object is left out instead of the game ending.
|
||||
|
||||
- `adapter.vk_pipeline_fallback`
|
||||
- **Changes:** Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
|
||||
- **Suggested:** not automatically; set on the game page (Customize), by a recipe or after a launch test.
|
||||
- **Options:**
|
||||
- Value: int, default `0`.
|
||||
- Game settings → Troubleshooting → "Skip refused graphics" (advanced).
|
||||
- **Catalog games (1):** Transformers Beyond Reality: Redux.
|
||||
- **Suggested by launch-test signatures:**
|
||||
- `vulkan-pipeline-refused` (fatal): The Frame's graphics driver refused to build some of the game's shaders, and Unreal ends the game at the first one (for example Transformers Beyond Reality).
|
||||
- **Source:** [patches/settings.py](../src/frameport/patches/settings.py)
|
||||
|
||||
> Vulkan shim (frame.vk_sanitize): a graphics pipeline the Frame's driver refuses is created again with a fragment shader that writes zero, then with a vertex shader that only sets the position as well, so the draw shows nothing instead of Unreal ending with "Shader compilation failures are Fatal." (for example a few multiview vertex shaders in Transformers Beyond Reality, GitHub #349). Logged as "retried with a blank".
|
||||
|
||||
### <a id="adapter-vk_pipeline_log"></a>Vulkan pipeline failures (log)
|
||||
|
||||
Logs graphics pipelines the Frame's driver refuses. No effect on the game.
|
||||
|
||||
+1
-1
@@ -205,7 +205,7 @@ version is `catalog/triage.yaml` (used by `frameport test` / the Job screen); ke
|
||||
| Unity game shows a picture but the player body is frozen: no head tracking, the controllers stay on the model, no buttons, although OpenXR input works (BONELAB 1.2068, Oculus XR Plugin) | OVRPlugin reports the headset as not worn (`ovrp_GetUserPresent2` → 0) a few seconds after start, and the game's rig only follows a present user (Marrow `XRHMD.IsUserPresent` = Unity's HMD `UserPresence`) | `frame.unity_user_presence` (the Oculus XR Plugin's lookup → `libfp_ovrp.so`, reports present; log `user presence: OVRPlugin 0 …`) |
|
||||
| Unreal 5 game crashes at its first render pass, backtrace `vulkan.freedreno.so` ← `libVkLayer_fossilize.so` ← `libfp_vk.so (create_render_pass2)` (Metro Awakening) | a subpass without a depth attachment names a depth/stencil resolve attachment; the Frame's Turnip reads the missing depth attachment (NULL) | the Vulkan shim drops that resolve (always, FramePort after 0.11.0; log `dropped the depth resolve of subpass N (no depth attachment)`); triage `unreal-vulkan-driver-crash` |
|
||||
| Unreal game crashes before its first frame: SIGSEGV `fault addr 0x10` on the main thread, backtrace all `libUnreal.so` above the linker's `soinfo::call_constructors` (inside `System.loadLibrary`), right after `Parsing commandline` (GitHub #349, Transformers Beyond Reality) | The game is built with Unreal's Binned3 allocator, which reserves its whole range while the library loads: one `mmap(NULL, 76 GiB, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS)`. Quest grants it; the Frame's kernel (heuristic overcommit, mode 0) refuses a writable private mapping larger than RAM + swap, and Unreal's out-of-memory handler ("Ran out of memory allocating ...") dereferences its not-yet-created log | `frame.unreal_noreserve` (suggested from analysis `unreal_binned3`): every such anonymous read/write mmap in the engine library gets `MAP_NORESERVE` (one instruction each: `mov w3, #0x22` → `#0x4022`); triage `unreal-reserve-refused`. Found by disassembling the crash pc (the OOM handler; its UTF-16 format string) and the caller's `mov x0, #0x1300000000` |
|
||||
| Unreal Vulkan game fails on its first frames and OVRPlugin reports `foveationImage = 0x0, width = 0, height = 0` (for example Transformers Beyond Reality: Redux, #349) | Quest FB foveation remains advertised by OVRPort's dispatcher despite `foveation_fix=1`. This is a hypothesis for the failure, not a confirmed cause: Redux's alternate no-ForceQuit build dereferences a null graphics-pipeline-state object during Vulkan pipeline binding, not a density image | Diagnostic `adapter.hide_fb_foveation=1` (off by default, Vulkan): filters the dispatcher and runtime extension lists/instance requests, removes foveation create/image chains and refuses profile creation/updates. Rebuild with the adapter **and xrshim** artifacts, then compare first-frame survival and Unreal's original fatal log. Does not disable Valve FDM injection. Device verification pending |
|
||||
| Unreal Vulkan game ends on its first frames with "Shader compilation failures are Fatal." (tombstone abort message; `System.exit` / ForceQuit; the no-ForceQuit build dereferences a null pipeline instead), `vk_pipeline_log=1` shows `vkCreateGraphicsPipelines failed: -1` (for example Transformers Beyond Reality: Redux, #349) | With Lepton's Fossilize layer loaded **every** graphics pipeline failed with VK_ERROR_OUT_OF_HOST_MEMORY, even a constant-colour one; retries without the pipeline cache, without the app's CPU allocator, and without Valve's FDM/RPO layers all failed too. Without Fossilize a few multiview vertex shaders still fail in Turnip (a blank fragment shader alone doesn't help, blank vertex + fragment does) | `adapter.vk_no_fossilize=1` (Vulkan shim removes `VK_LAYER_fossilize` from GraphicsEnv's debug layer list when the engine loads it) + `adapter.vk_pipeline_fallback=1` (refused pipelines are made with blank shaders; logged "retried with a blank"); triage `vulkan-pipeline-refused`. Headless: runs at 72 fps; headset check pending. The `foveationImage = 0x0` warning (`hide_fb_foveation`) was ruled out |
|
||||
| Unreal 5 game crashes in `vulkan.freedreno.so` called straight from `libUnreal.so` right after its swapchains, or a few seconds into the first frames (Metro Awakening) | Unreal turns on fragment-density-map foveation because Turnip offers VK_EXT_fragment_density_map, then records barriers (to `FRAGMENT_DENSITY_MAP_OPTIMAL`) and image views (2D array R8G8) for a density map the Frame never provides (VK_NULL_HANDLE); Turnip dereferences it | adapter `vk_hide_fdm=1` (the game doesn't see the extension) + `vk_spec_fixes=1` (leaves out null-image barriers, refuses null-image views); triage `unreal-fdm-missing`. Found by disassembling the driver at the crash pc: the struct offsets (0x58 = VkSubpassDescription2, 0x48/0x60 = image barriers, viewType/format in registers) name the call |
|
||||
| Own-engine game crashes in `je_free` from its own library on the first frames (Roblox) | the game frees memory it doesn't own; not the Vulkan shim or the format fallback | unsupported |
|
||||
|
||||
|
||||
+142
-2
@@ -106,6 +106,8 @@ static int validation; // vk_validation: add Khronos' validation layer (bu
|
||||
static int hide_fdm; // vk_hide_fdm: the game doesn't see VK_EXT_fragment_density_map(2)
|
||||
static int want_dump; // vk_shader_dump: write the game's SPIR-V modules to files/fp_vk_shaders/
|
||||
static int want_pipeline_log; // vk_pipeline_log: log failing pipeline creations (pipeline_log.h)
|
||||
static int no_fossilize; // vk_no_fossilize: take Lepton's Fossilize layer out of GraphicsEnv's list
|
||||
static int pipeline_fallback; // vk_pipeline_fallback: retry a failed graphics pipeline with blank shaders
|
||||
static char app_files[400]; // /sdcard/Android/data/<package>/files
|
||||
|
||||
static void read_settings(const char *path) {
|
||||
@@ -119,6 +121,8 @@ static void read_settings(const char *path) {
|
||||
if (!strncmp(line, "vk_spec_fixes=", 14)) spec_fixes = atoi(line + 14) != 0;
|
||||
if (!strncmp(line, "vk_shader_dump=", 15)) want_dump = atoi(line + 15) != 0;
|
||||
if (!strncmp(line, "vk_pipeline_log=", 16)) want_pipeline_log = atoi(line + 16) != 0;
|
||||
if (!strncmp(line, "vk_no_fossilize=", 16)) no_fossilize = atoi(line + 16) != 0;
|
||||
if (!strncmp(line, "vk_pipeline_fallback=", 21)) pipeline_fallback = atoi(line + 21) != 0;
|
||||
if (!strncmp(line, "vk_query_slots=", 15)) {
|
||||
int v = atoi(line + 15);
|
||||
query_slots = v == 1 ? 2 : v >= 2 && v <= 4 ? v : 1; // 1 = on (the settings dialog's switch) = 2 slots
|
||||
@@ -183,6 +187,52 @@ static uint32_t *fixed_shader(const uint32_t *code, size_t size, size_t *out_siz
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Android's loader reads GraphicsEnv's debug layer list (Lepton's gpu_debug_layers) at each vkCreateInstance; this
|
||||
// takes one layer out of it (same libgraphicsenv calls as native/zinkfix, which adds its own layer)
|
||||
struct cxx_string { size_t cap; size_t size; char *data; };
|
||||
#define GE_INSTANCE "_ZN7android11GraphicsEnv11getInstanceEv"
|
||||
#define GE_GET_LAYERS "_ZN7android11GraphicsEnv14getDebugLayersEv"
|
||||
#define GE_SET_LAYERS "_ZN7android11GraphicsEnv14setDebugLayersENSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE"
|
||||
|
||||
static const char *cxx_chars(const void *s, size_t *len) {
|
||||
const unsigned char *b = s;
|
||||
if (!b) { *len = 0; return NULL; }
|
||||
if (b[0] & 1) {
|
||||
const struct cxx_string *l = s;
|
||||
*len = l->size;
|
||||
return l->data;
|
||||
}
|
||||
*len = b[0] >> 1;
|
||||
return (const char *)b + 1;
|
||||
}
|
||||
|
||||
static void drop_debug_layer(void *vk, const char *name) {
|
||||
void *(*get_instance)(void) = (void *(*)(void))dlsym(vk, GE_INSTANCE);
|
||||
const void *(*get_layers)(void *) = (const void *(*)(void *))dlsym(vk, GE_GET_LAYERS);
|
||||
void (*set_layers)(void *, struct cxx_string *) = (void (*)(void *, struct cxx_string *))dlsym(vk, GE_SET_LAYERS);
|
||||
void *env = get_instance && get_layers && set_layers ? get_instance() : NULL;
|
||||
size_t len = 0;
|
||||
const char *cur = env ? cxx_chars(get_layers(env), &len) : NULL;
|
||||
if (!env || len > 4096 || (len && !cur)) {
|
||||
LOG("vk shim: can't change the debug layer list (GraphicsEnv not found)");
|
||||
return;
|
||||
}
|
||||
char old[4097], *out = malloc(len + 16);
|
||||
if (!out) return;
|
||||
memcpy(old, cur ? cur : "", len);
|
||||
old[len] = 0;
|
||||
size_t n = 0;
|
||||
for (char *save = NULL, *tok = strtok_r(old, ":", &save); tok; tok = strtok_r(NULL, ":", &save)) {
|
||||
if (!strcmp(tok, name)) continue;
|
||||
n += (size_t)sprintf(out + n, "%s%s", n ? ":" : "", tok);
|
||||
}
|
||||
struct cxx_string tmp = {((len + 16) & ~(size_t)15) | 1, n, out};
|
||||
set_layers(env, &tmp);
|
||||
if ((tmp.cap & 1) && tmp.data == out) free(out);
|
||||
const char *now = cxx_chars(get_layers(env), &len);
|
||||
LOG("vk shim: debug layers now \"%.*s\" (without %s)", (int)len, now ? now : "", name);
|
||||
}
|
||||
|
||||
static void init(void) {
|
||||
read_all_settings();
|
||||
if (nfixes) LOG("vk shim: %d shader fix(es) configured", nfixes);
|
||||
@@ -194,6 +244,7 @@ static void init(void) {
|
||||
pl_on = 1;
|
||||
LOG("vk shim: logging failed pipeline creations and sampler Y'CbCr conversions");
|
||||
}
|
||||
if (pipeline_fallback) LOG("vk shim: failed graphics pipelines get blank shaders");
|
||||
if (spec_fixes) LOG("vk shim: Vulkan spec fixes on (depth images can be cleared, no depth resolve in shader-resolve "
|
||||
"subpasses)");
|
||||
real_vk = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL);
|
||||
@@ -202,10 +253,18 @@ static void init(void) {
|
||||
real_gdpa = (PFN_vkGetDeviceProcAddr)dlsym(real_vk, "vkGetDeviceProcAddr");
|
||||
real_rp2_trampoline = (PFN_vkCreateRenderPass2)dlsym(real_vk, "vkCreateRenderPass2");
|
||||
real_csm_trampoline = (PFN_vkCreateShaderModule)dlsym(real_vk, "vkCreateShaderModule");
|
||||
if (no_fossilize) drop_debug_layer(real_vk, "VK_LAYER_fossilize");
|
||||
}
|
||||
LOG("vk shim: libvulkan.so %s", real_gipa && real_gdpa ? "OK" : "MISSING");
|
||||
}
|
||||
|
||||
// The engine's first vkCreateInstance can come from another thread before any wrapped call runs init(), so the layer
|
||||
// list is changed when the engine loads this library
|
||||
__attribute__((constructor)) static void early_init(void) {
|
||||
read_all_settings();
|
||||
if (no_fossilize) pthread_once(&once, init);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- pointer checks
|
||||
|
||||
static pthread_mutex_t probe_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
@@ -868,13 +927,94 @@ static VKAPI_ATTR void VKAPI_CALL cmd_pipeline_barrier2_khr(VkCommandBuffer cb,
|
||||
|
||||
// ---------------------------------------------------------------- pipeline log (vk_pipeline_log, diagnostics)
|
||||
|
||||
// GitHub #349: Turnip fails some of Transformers' pipelines (-1 = its "ir3 variant failed"), and Unreal treats a
|
||||
// failed pipeline as fatal. A failed pipeline is retried with a fragment shader that writes zero to location 0, then
|
||||
// with a vertex shader that only writes gl_Position as well: the draw then shows nothing instead of ending the game.
|
||||
static const uint32_t FALLBACK_FS[] = {
|
||||
0x07230203, 0x00010000, 0x00070000, 0x0000000b, 0x00000000, 0x00020011, 0x00000001, 0x0003000e,
|
||||
0x00000000, 0x00000001, 0x0006000f, 0x00000004, 0x00000001, 0x6e69616d, 0x00000000, 0x00000002,
|
||||
0x00030010, 0x00000001, 0x00000007, 0x00040047, 0x00000002, 0x0000001e, 0x00000000, 0x00030016,
|
||||
0x00000003, 0x00000020, 0x00040017, 0x00000004, 0x00000003, 0x00000004, 0x0004002b, 0x00000003,
|
||||
0x00000005, 0x00000000, 0x0007002c, 0x00000004, 0x00000006, 0x00000005, 0x00000005, 0x00000005,
|
||||
0x00000005, 0x00040020, 0x00000007, 0x00000003, 0x00000004, 0x00020013, 0x00000008, 0x00030021,
|
||||
0x00000009, 0x00000008, 0x0004003b, 0x00000007, 0x00000002, 0x00000003, 0x00050036, 0x00000008,
|
||||
0x00000001, 0x00000000, 0x00000009, 0x000200f8, 0x0000000a, 0x0003003e, 0x00000002, 0x00000006,
|
||||
0x000100fd, 0x00010038,
|
||||
};
|
||||
static const uint32_t FALLBACK_VS[] = {
|
||||
0x07230203, 0x00010000, 0x00070000, 0x0000000c, 0x00000000, 0x00020011, 0x00000001, 0x0003000e,
|
||||
0x00000000, 0x00000001, 0x0006000f, 0x00000000, 0x00000001, 0x6e69616d, 0x00000000, 0x00000002,
|
||||
0x00040047, 0x00000002, 0x0000000b, 0x00000000, 0x00030016, 0x00000003, 0x00000020, 0x00040017,
|
||||
0x00000004, 0x00000003, 0x00000004, 0x0004002b, 0x00000003, 0x00000005, 0x00000000, 0x0004002b,
|
||||
0x00000003, 0x00000006, 0x3f800000, 0x0007002c, 0x00000004, 0x00000007, 0x00000005, 0x00000005,
|
||||
0x00000005, 0x00000006, 0x00040020, 0x00000008, 0x00000003, 0x00000004, 0x00020013, 0x00000009,
|
||||
0x00030021, 0x0000000a, 0x00000009, 0x0004003b, 0x00000008, 0x00000002, 0x00000003, 0x00050036,
|
||||
0x00000009, 0x00000001, 0x00000000, 0x0000000a, 0x000200f8, 0x0000000b, 0x0003003e, 0x00000002,
|
||||
0x00000007, 0x000100fd, 0x00010038,
|
||||
};
|
||||
|
||||
static pthread_mutex_t fallback_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static VkDevice fallback_device;
|
||||
static VkShaderModule fallback_module[2]; // [0] fragment, [1] vertex; kept for the device's lifetime
|
||||
|
||||
static VkShaderModule fallback_shader(VkDevice device, int vertex) {
|
||||
pthread_mutex_lock(&fallback_lock);
|
||||
if (fallback_device != device) {
|
||||
fallback_device = device; // one device per game in practice; a new one gets new modules
|
||||
fallback_module[0] = fallback_module[1] = VK_NULL_HANDLE;
|
||||
}
|
||||
if (!fallback_module[vertex]) {
|
||||
PFN_vkCreateShaderModule csm = (PFN_vkCreateShaderModule)any_fn(device, FN_CSM);
|
||||
VkShaderModuleCreateInfo mi = {VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, NULL, 0,
|
||||
vertex ? sizeof FALLBACK_VS : sizeof FALLBACK_FS,
|
||||
vertex ? FALLBACK_VS : FALLBACK_FS};
|
||||
if (csm && csm(device, &mi, NULL, &fallback_module[vertex]) != VK_SUCCESS) fallback_module[vertex] = VK_NULL_HANDLE;
|
||||
}
|
||||
VkShaderModule m = fallback_module[vertex];
|
||||
pthread_mutex_unlock(&fallback_lock);
|
||||
return m;
|
||||
}
|
||||
|
||||
static VkResult fallback_pipeline(VkDevice device, VkPipelineCache cache, const VkGraphicsPipelineCreateInfo *ci,
|
||||
const VkAllocationCallbacks *alloc, VkPipeline *out,
|
||||
PFN_vkCreateGraphicsPipelines real, VkResult failed) {
|
||||
static int logged;
|
||||
VkPipelineShaderStageCreateInfo st[6];
|
||||
memcpy(st, ci->pStages, sizeof *st * ci->stageCount);
|
||||
VkGraphicsPipelineCreateInfo p = *ci;
|
||||
p.pStages = st;
|
||||
VkResult r = failed;
|
||||
for (int pass = 0; pass < 2 && r < 0; pass++) { // 0: fragment shader only, 1: vertex shader too
|
||||
int replaced = 0;
|
||||
for (uint32_t s = 0; s < p.stageCount; s++) {
|
||||
int vertex = st[s].stage == VK_SHADER_STAGE_VERTEX_BIT;
|
||||
if (st[s].stage != VK_SHADER_STAGE_FRAGMENT_BIT && !(pass && vertex)) continue;
|
||||
VkShaderModule m = fallback_shader(device, vertex);
|
||||
if (!m) continue;
|
||||
st[s].pNext = NULL;
|
||||
st[s].flags = 0;
|
||||
st[s].module = m;
|
||||
st[s].pName = "main";
|
||||
st[s].pSpecializationInfo = NULL;
|
||||
replaced++;
|
||||
}
|
||||
if (!replaced) continue;
|
||||
r = real(device, cache, 1, &p, alloc, out);
|
||||
if (logged++ < 20)
|
||||
LOG("vk shim: failed pipeline (%d) retried with a blank %s shader: %d", failed,
|
||||
pass ? "vertex + fragment" : "fragment", r);
|
||||
}
|
||||
return r < 0 ? failed : r;
|
||||
}
|
||||
|
||||
static VKAPI_ATTR VkResult VKAPI_CALL create_graphics_pipelines(VkDevice device, VkPipelineCache cache, uint32_t count,
|
||||
const VkGraphicsPipelineCreateInfo *ci,
|
||||
const VkAllocationCallbacks *alloc, VkPipeline *out) {
|
||||
PFN_vkCreateGraphicsPipelines real = (PFN_vkCreateGraphicsPipelines)any_fn(device, FN_CGP);
|
||||
if (!real) return VK_ERROR_INITIALIZATION_FAILED;
|
||||
VkResult r = real(device, cache, count, ci, alloc, out);
|
||||
pl_graphics(count, ci, out, r);
|
||||
if (pl_on) pl_graphics(count, ci, out, r);
|
||||
if (pipeline_fallback && r < 0 && count == 1 && ci && ci->pStages && ci->stageCount <= 6) r = fallback_pipeline(device, cache, ci, alloc, out, real, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -950,7 +1090,7 @@ static PFN_vkVoidFunction wrap(const char *name) {
|
||||
case FN_EDEP: return hide_fdm ? (PFN_vkVoidFunction)vkEnumerateDeviceExtensionProperties : NULL;
|
||||
case FN_CDEV: return hide_fdm || spec_fixes ? (PFN_vkVoidFunction)vkCreateDevice : NULL;
|
||||
case FN_CIV: return spec_fixes ? (PFN_vkVoidFunction)create_image_view : NULL;
|
||||
case FN_CGP: return pl_on ? (PFN_vkVoidFunction)create_graphics_pipelines : NULL;
|
||||
case FN_CGP: return pl_on || pipeline_fallback ? (PFN_vkVoidFunction)create_graphics_pipelines : NULL;
|
||||
case FN_CCP: return pl_on ? (PFN_vkVoidFunction)create_compute_pipelines : NULL;
|
||||
case FN_CSAMP: return pl_on ? (PFN_vkVoidFunction)create_sampler : NULL;
|
||||
case FN_CDSL: return pl_on ? (PFN_vkVoidFunction)create_set_layout : NULL;
|
||||
|
||||
@@ -319,6 +319,16 @@
|
||||
"title": "Hide Vulkan foveation",
|
||||
"group": "Game settings"
|
||||
},
|
||||
"adapter.vk_no_fossilize": {
|
||||
"anchor": "adapter-vk_no_fossilize",
|
||||
"title": "Without Steam's shader cache layer",
|
||||
"group": "Game settings"
|
||||
},
|
||||
"adapter.vk_pipeline_fallback": {
|
||||
"anchor": "adapter-vk_pipeline_fallback",
|
||||
"title": "Skip refused graphics",
|
||||
"group": "Game settings"
|
||||
},
|
||||
"adapter.vk_pipeline_log": {
|
||||
"anchor": "adapter-vk_pipeline_log",
|
||||
"title": "Vulkan pipeline failures (log)",
|
||||
|
||||
@@ -1476,6 +1476,7 @@
|
||||
"Size of text and layout. Under WSL, Automatic follows half of Windows' display scaling (150% → 125%).": "",
|
||||
"Skip for now": "",
|
||||
"Skip Meta avatars": "",
|
||||
"Skip refused graphics": "",
|
||||
"Skip this version": "",
|
||||
"Skips a Quest-only reporting step in Meta's audio library that crashes some games.": "",
|
||||
"Skips a separate data-file check when an Unreal game still hangs at startup with the content check off. Experimental; the game still needs its data.": "",
|
||||
@@ -1488,6 +1489,7 @@
|
||||
"Some engines contain assembly (for example OpenSSL's) that checks a return-address signature it never made. The Quest's CPU ignores those checks, the Steam Frame's enforces them: the game crashes with SIGILL as soon as it uses that code, for example on its first network connection (Star Wars Pinball VR). In a library with unpaired checks, the signing and checking instructions become no-ops.": "",
|
||||
"Some engines leave the pNext of unused Vulkan attachment references uninitialized. The Frame's driver never reads it, but Lepton always loads Steam's Fossilize shader-cache layer, which follows it and crashes on the first frame (SIGSEGV in libVkLayer_fossilize.so from FVulkanRenderPass, for example Deadpool VR). Loads Vulkan through a small shim that keeps valid pointers and drops only unreadable ones or ones pointing at the wrong structure type. It also drops a depth resolve named in a subpass without a depth attachment, which crashes the Frame's driver at the first render pass (for example Metro Awakening).": "",
|
||||
"Some game folders are already set up for SteamVR: a Revive copy (LibRevive64.dll) next to the game, started by a small loader DLL (for example xinput1_3.dll) that Windows loads from the game's folder. Then FramePort starts the game program directly — like double-clicking it — instead of through its own Revive (two Revives conflict; for example the Oculus Platform check then fails). On the Frame, Wine is told to use those loader DLLs from the game folder instead of its own.": "",
|
||||
"Some games can't create any graphics with it (for example Transformers Beyond Reality).": "",
|
||||
"Some games keep content in separate files next to their OBB (for example Star Wars: Tales from the Galaxy's Edge: its seasons and sound banks) and ask Meta's platform for them as asset files. OVRPort's platform loader doesn't know them, so the game waits for content that never arrives (black screen after loading). Lists the content files shipped with the game's data (*.pak) as installed and answers their download request at once with the file's path; nothing is copied or downloaded. Shares the language-pack library.": "",
|
||||
"Some games save their render resolution in a settings file and load it after creating the headset's eye buffers; after a resolution scale change the saved size no longer matches and the picture is displaced or stretched, with black borders (for example BlazeRush's user_config.xml). FramePort writes the values its recipe names into the game's file while the game isn't running (after an install and after a Game settings change), from the Frame's own eye-buffer size times the resolution scale: w and h = the eye buffer's width and height, for example h*16/9. Only existing entries change; the previous file is kept as <file>.frameport-backup. The size is learned from the game's last start, so a file the game wrote before is corrected from the next install or settings change on.": "",
|
||||
"Some OpenGL ES engines compile every shader for multiview (both eyes in one draw, `num_views=2`) and use the same shaders to draw into ordinary single-layer framebuffers, for example a HUD or PDA screen rendered to a texture. Quest's driver draws them anyway; the Frame's driver (Mesa) follows the OVR_multiview rule and silently drops every such draw, so those panels stay black (for example Doom3Quest's HUD and PDA). Loads OpenGL ES through a small interposer (libfpglmv.so) that draws those cases with a single-view copy of the shader program (left-eye view; uniforms copied before each such draw). Eye-buffer draws are unchanged. Logs under the tag GLMV; the setting gl_mv_debug adds error checks and counters.": "",
|
||||
@@ -1893,10 +1895,12 @@
|
||||
"Vulkan pipeline failures (log)": "",
|
||||
"Vulkan shader dump (diagnostics)": "",
|
||||
"Vulkan shader fixes": "",
|
||||
"Vulkan shim (frame.vk_sanitize): a graphics pipeline the Frame's driver refuses is created again with a fragment shader that writes zero, then with a vertex shader that only sets the position as well, so the draw shows nothing instead of Unreal ending with \"Shader compilation failures are Fatal.\" (for example a few multiview vertex shaders in Transformers Beyond Reality, GitHub #349). Logged as \"retried with a blank\".": "",
|
||||
"Vulkan shim (frame.vk_sanitize): logs every failing graphics/compute pipeline creation with its shader stages (named like the vk_shader_dump files), structure types and any sampler Y'CbCr conversion involved, to find the pipeline behind Unreal's \"Shader compilation failures are Fatal.\" No effect on the game.": "",
|
||||
"Vulkan shim (frame.vk_sanitize): makes two Unreal habits valid Vulkan - depth images get VK_IMAGE_USAGE_TRANSFER_DST_BIT (they are cleared with vkCmdClearDepthStencilImage) and Qualcomm shader-resolve subpasses lose an invalid depth resolve. Found with the validation layer in Into The Radius 2 (flickering models, windows behind models). Also leaves out image barriers without an image and refuses image views without one, which crash the Frame's driver (for example Metro Awakening).": "",
|
||||
"Vulkan shim (frame.vk_sanitize): on gives every occlusion query room for both eyes. In multiview passes the Frame's driver writes a zero result for the second eye into the next query, so engines that count on one slot cull visible objects (models popping in and out, for example Into The Radius 2). 0 = off, 1 = on (2 slots).": "",
|
||||
"Vulkan shim (frame.vk_sanitize): SPIR-V modules matching size + SHA-256 get words inserted at a byte offset, for example stores that initialize locals a shader reads before writing (an undefined loop counter hung the GPU in VR4's campaign). Format: <size>:<sha256>:<byte offset>:<word>,<word>,...; several separated by ';'. Comes from a game's recipe.": "",
|
||||
"Vulkan shim (frame.vk_sanitize): takes Lepton's Fossilize shader-cache layer out of the game's Vulkan layers (Android's debug layer list) when the engine loads its Vulkan library. With Fossilize loaded every graphics pipeline of Transformers Beyond Reality failed (VK_ERROR_OUT_OF_HOST_MEMORY), which Unreal treats as fatal (GitHub #349). Lepton has no switch for it; instances created before the engine loads the shim keep it.": "",
|
||||
"Vulkan shim (frame.vk_sanitize): the game doesn't see VK_EXT_fragment_density_map(2). Unreal Engine 5 turns on fragment-density-map foveation when the driver offers it and expects the density map from the headset, which the Frame doesn't provide: image views and barriers for a missing image, then a crash in the Frame's Vulkan driver (for example Metro Awakening). Valve's own foveation layer isn't affected.": "",
|
||||
"Vulkan shim (frame.vk_sanitize): writes every distinct SPIR-V module the game creates to Android/data/<package>/files/fp_vk_shaders/<size>_<sha256>.spv, with index.txt listing every creation in order with its time, to find the shader behind a GPU hang and capture it for a new vk_shader_fix. Diagnostics include the newest modules. No effect on the game.": "",
|
||||
"Vulkan: drop invalid render-pass pointers": "",
|
||||
@@ -1922,6 +1926,7 @@
|
||||
"What your Frame is ready for and what's installed": "",
|
||||
"What's new in FramePort {version}": "",
|
||||
"What's new…": "",
|
||||
"When the Frame's driver refuses one of the game's shaders, that object is left out instead of the game ending.": "",
|
||||
"Where it's installed": "",
|
||||
"Where new games go on the Frame, such as a microSD card. Installed games stay put; right-click → Move to… moves one. Cards formatted as FAT, exFAT or NTFS can't hold games.": "",
|
||||
"Where the power goes": "",
|
||||
@@ -1942,6 +1947,7 @@
|
||||
"Windows' firewall for WSL blocks the Frame. Show the setup command again and allow the change when Windows asks.": "",
|
||||
"With emulated passthrough, honours the eye layer's XR_FB_composition_layer_alpha_blend, which the Frame's runtime ignores: Unreal games keep inverted alpha and ask for inverse blending, so the room showed where the game drew and black where it should show the room (for example Star Wars: Beyond Victory). The alpha is inverted in the game's image before it is composited (Vulkan).": "",
|
||||
"Without a Meta account, OVRPort's platform library makes up a new user id at every start (ovr_GetLoggedInUserID). Games that file saves under the user id (for example Walkabout Mini Golf) then start with an empty profile each time and seem to lose all progress. Gives the game a fixed id instead, different for each game and each FramePort user.": "",
|
||||
"Without Steam's shader cache layer": "",
|
||||
"Working": "",
|
||||
"Working…": "",
|
||||
"Works": "",
|
||||
|
||||
@@ -234,6 +234,16 @@ SETTINGS = [
|
||||
"Vulkan shim (frame.vk_sanitize): logs every failing graphics/compute pipeline creation with its shader stages "
|
||||
"(named like the vk_shader_dump files), structure types and any sampler Y'CbCr conversion involved, to find the "
|
||||
"pipeline behind Unreal's \"Shader compilation failures are Fatal.\" No effect on the game."),
|
||||
("vk_no_fossilize", "int", 0, "Vulkan shim: without Lepton's Fossilize layer",
|
||||
"Vulkan shim (frame.vk_sanitize): takes Lepton's Fossilize shader-cache layer out of the game's Vulkan layers "
|
||||
"(Android's debug layer list) when the engine loads its Vulkan library. With Fossilize loaded every graphics "
|
||||
"pipeline of Transformers Beyond Reality failed (VK_ERROR_OUT_OF_HOST_MEMORY), which Unreal treats as fatal "
|
||||
"(GitHub #349). Lepton has no switch for it; instances created before the engine loads the shim keep it."),
|
||||
("vk_pipeline_fallback", "int", 0, "Vulkan shim: blank shaders for refused pipelines",
|
||||
"Vulkan shim (frame.vk_sanitize): a graphics pipeline the Frame's driver refuses is created again with a fragment "
|
||||
"shader that writes zero, then with a vertex shader that only sets the position as well, so the draw shows "
|
||||
"nothing instead of Unreal ending with \"Shader compilation failures are Fatal.\" (for example a few multiview "
|
||||
"vertex shaders in Transformers Beyond Reality, GitHub #349). Logged as \"retried with a blank\"."),
|
||||
("vk_validation", "int", 0, "Vulkan shim: validation layer",
|
||||
"Diagnostics: the Vulkan shim (frame.vk_sanitize) adds Khronos' validation layer to the game's instance; its "
|
||||
"findings go to launch.log. The layer library (libVkLayer_khronos_validation.so) must be in the APK."),
|
||||
@@ -425,6 +435,12 @@ UI: dict[str, dict] = {
|
||||
help="Shows each eye's picture to the other eye. For testing.", control=("switch",)),
|
||||
"vk_pipeline_log": dict(group="troubleshooting", level="advanced", label="Vulkan pipeline failures (log)",
|
||||
help="Logs graphics pipelines the Frame's driver refuses. No effect on the game.", control=("switch",)),
|
||||
"vk_no_fossilize": dict(group="troubleshooting", level="advanced", label="Without Steam's shader cache layer",
|
||||
help="Some games can't create any graphics with it (for example Transformers Beyond Reality).",
|
||||
control=("switch",)),
|
||||
"vk_pipeline_fallback": dict(group="troubleshooting", level="advanced", label="Skip refused graphics",
|
||||
help="When the Frame's driver refuses one of the game's shaders, that object is left out instead of "
|
||||
"the game ending.", control=("switch",)),
|
||||
"vk_validation": dict(group="troubleshooting", level="advanced", label="Vulkan error checks (log)",
|
||||
help="Logs Vulkan mistakes the game makes. Needs a special test build.", control=("switch",)),
|
||||
"rect_clamp": dict(group="troubleshooting", level="advanced", label="Keep pictures in bounds",
|
||||
@@ -589,6 +605,8 @@ class AdapterSetting(Patch):
|
||||
"vk_query_slots": lambda a: a.engine == "Unreal" and ap.is_vulkan(a),
|
||||
"vk_validation": lambda a: a.engine == "Unreal",
|
||||
"vk_pipeline_log": lambda a: a.engine in ("Unreal", "Other") and "arm64-v8a" in a.abis,
|
||||
"vk_no_fossilize": lambda a: a.engine in ("Unreal", "Other") and "arm64-v8a" in a.abis,
|
||||
"vk_pipeline_fallback": lambda a: a.engine in ("Unreal", "Other") and "arm64-v8a" in a.abis,
|
||||
# wherever the Vulkan shim can be (vk_sanitize); Unreal's Vulkan builds are rarely detected as such
|
||||
"vk_shader_dump": lambda a: a.engine in ("Unreal", "Other") and "arm64-v8a" in a.abis,
|
||||
"zink_shader_fix": ap.is_gles,
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
"""vk_no_fossilize / vk_pipeline_fallback (GitHub #349): the Vulkan shim leaves Lepton's Fossilize layer out and
|
||||
creates pipelines the driver refuses with blank shaders."""
|
||||
import re
|
||||
import shutil
|
||||
import struct
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
import yaml
|
||||
|
||||
from frameport.patches import base
|
||||
from frameport.patches.settings import UI
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("key", ["vk_no_fossilize", "vk_pipeline_fallback"])
|
||||
def test_settings_registered_off_by_default(key):
|
||||
base.load_all()
|
||||
p = base.REGISTRY[f"adapter.{key}"]
|
||||
assert p.category == "adapter" and p.default == 0 and not p.default_on
|
||||
assert UI[key]["group"] == "troubleshooting"
|
||||
|
||||
|
||||
def test_artifact_reads_the_settings():
|
||||
so = (ROOT / "artifacts/arm64-v8a/libfp_vk.so").read_bytes()
|
||||
for s in (b"vk_no_fossilize=", b"vk_pipeline_fallback=", b"VK_LAYER_fossilize", b"retried with a blank",
|
||||
b"_ZN7android11GraphicsEnv14setDebugLayers"):
|
||||
assert s in so
|
||||
|
||||
|
||||
def _blank_shaders():
|
||||
src = (ROOT / "native/vkshim/vkshim.c").read_text()
|
||||
out = {}
|
||||
for name in ("FS", "VS"):
|
||||
body = re.search(rf"FALLBACK_{name}\[\] = \{{(.*?)\}};", src, re.S).group(1)
|
||||
words = [int(w, 16) for w in re.findall(r"0x[0-9a-f]{8}", body)]
|
||||
out[name] = struct.pack(f"<{len(words)}I", *words)
|
||||
return out
|
||||
|
||||
|
||||
def test_blank_shaders_are_valid_spirv(tmp_path):
|
||||
shaders = _blank_shaders()
|
||||
assert all(b[:4] == b"\x03\x02\x23\x07" for b in shaders.values())
|
||||
if not shutil.which("spirv-val"):
|
||||
pytest.skip("needs spirv-val")
|
||||
for name, data in shaders.items():
|
||||
f = tmp_path / f"{name}.spv"
|
||||
f.write_bytes(data)
|
||||
subprocess.run(["spirv-val", "--target-env", "vulkan1.0", str(f)], check=True)
|
||||
|
||||
|
||||
def test_triage_suggests_both_settings():
|
||||
rules = yaml.safe_load((ROOT / "catalog/triage.yaml").read_text())
|
||||
rules = rules.get("signatures", rules) if isinstance(rules, dict) else rules
|
||||
rule = next(r for r in rules if r["id"] == "vulkan-pipeline-refused")
|
||||
pat = re.compile(rule["pattern"])
|
||||
assert pat.search("E UE4: Shader compilation failures are Fatal.")
|
||||
assert pat.search("I FrameBridge: vk shim: vkCreateGraphicsPipelines failed: -1 (1 pipeline(s); failure 2)")
|
||||
assert not pat.search("I FrameBridge: vk shim: vkCreateGraphicsPipelines failed: 1000297000 (1 pipeline(s))")
|
||||
assert set(rule["suggest"]) == {"adapter.vk_no_fossilize", "adapter.vk_pipeline_fallback"}
|
||||
Reference in new issue
Block a user