Quest: address flavor safety review

This commit is contained in:
darthcircuit committed 2026-09-23 11:22:39 -06:00
1 parent 6e6406c200
commit 02dd9bf8cc
15 files changed
+162 -67

No files matched your search

+1 -8
View File
@@ -154,13 +154,6 @@ elseif (_aurora_dawn_provider STREQUAL "package")
endif ()
set(AURORA_DAWN_PACKAGE_URL
"https://github.com/theofficialgman/dawn-build/releases/download/${AURORA_DAWN_VERSION}/dawn-${_dawn_system}-${_dawn_arch}.tar.gz")
# Meta's Quest 1 firmware advertises VK_EXT_debug_utils but rejects it at
# vkCreateInstance. This pinned Android package disables that extension on
# Android; it is also the package validated on modern Quest headsets.
if (_dawn_system STREQUAL "android" AND _dawn_arch STREQUAL "aarch64")
set(AURORA_DAWN_PACKAGE_URL
"https://github.com/encounter/dawn-build/releases/download/${AURORA_DAWN_VERSION}/dawn-android-aarch64.tar.gz")
endif ()
# A release asset is mutable: the same tag has already served two different windows-amd64 archives,
# and a cached extraction is never re-verified. Pin the digest for the combinations we ship.
@@ -188,7 +181,7 @@ elseif (_aurora_dawn_provider STREQUAL "package")
"SHA256=f97701d26fd1f25bbcc260b4c31736ede134c730c12556029e2470fde967f424")
elseif (_dawn_system STREQUAL "android" AND _dawn_arch STREQUAL "aarch64")
set(AURORA_DAWN_PACKAGE_URL_HASH
"SHA256=27d910dee1201fd1e5b6ac567f0ba2306ebf2135e9f40b6929976c365d38b09b")
"SHA256=0e63e8cbf53551f703f582d1306f4257c0380353f66b53369d96952ce6d9f934")
endif ()
endif ()
endif ()
+31 -24
View File
@@ -10,6 +10,7 @@
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <cstring>
#include <deque>
#include <filesystem>
#include <limits>
@@ -26,6 +27,7 @@
#if defined(__ANDROID__)
#include <pthread.h>
#include <sys/resource.h>
#include <sys/system_properties.h>
#endif
namespace aurora::gfx {
@@ -70,26 +72,27 @@ constexpr size_t MaxQueuedPipelineBuilds = 256;
// First-use compilation works best as a short parallel burst. Leave two logical processors for the
// render and game threads, and cap large hosts to limit driver submissions and memory use.
constexpr size_t ReservedLogicalProcessors = 2;
#if defined(__ANDROID__)
// Quest reports all eight Kryo cores, but the Adreno Vulkan driver serializes
// much of vkCreateGraphicsPipelines. Six equal-priority compiler threads crowd
// out the translated game and XR submission threads without materially
// shortening first-use compilation. Two background-priority workers keep
// pipeline discovery asynchronous while preserving frame cadence.
constexpr size_t MaxPipelineWorkers = 2;
#else
constexpr size_t MaxPipelineWorkers = 22;
#endif
// Cached clear and GX pipelines are normally prewarmed using the full worker
// pool. Mobile Adreno drivers serialize much of pipeline creation internally;
// prewarming hundreds of recipes there starves first-use pipelines for over a
// minute. Keep cached recipes dormant on Android. A recipe is promoted to the
// priority queue as soon as the game actually requests it.
constexpr size_t Quest1MaxPipelineWorkers = 2;
static bool g_quest1PipelineScheduling = false;
static bool quest1_pipeline_scheduling() noexcept {
#if defined(__ANDROID__)
constexpr size_t MaxBackgroundPipelineWorkers = 0;
static const bool enabled = [] {
char device[PROP_VALUE_MAX]{};
return __system_property_get("ro.product.device", device) > 0 && std::strcmp(device, "monterey") == 0;
}();
return enabled;
#else
constexpr size_t MaxBackgroundPipelineWorkers = MaxPipelineWorkers;
return false;
#endif
}
static size_t max_background_pipeline_workers() noexcept {
// Quest 1's Adreno driver serializes pipeline creation. Leave cached recipes
// dormant until first use there; all newer headsets retain normal prewarm.
return g_quest1PipelineScheduling ? 0 : MaxPipelineWorkers;
}
// For synchronous pipeline fallback (OpenGL)
#ifdef NDEBUG
constexpr size_t BuildPipelinesPerFrame = 5;
@@ -484,8 +487,8 @@ static PipelineRef find_pipeline_impl(ShaderType type, const PipelineConfig& con
}
} else if (g_pendingPipelines.contains(hash)) {
auto* pending = touch_pending_pipeline(hash, g_pipelineFrameActive);
// A cached Android recipe can sit dormant because background prewarm is
// disabled. Promoting it to first-use priority must wake a worker before
// A cached recipe can sit dormant when background prewarm is disabled.
// Promoting it to first-use priority must wake a worker before
// bind_pipeline waits for completion, or both threads sleep forever.
if (g_pipelineFrameActive && deferGxPipeline) {
notifyWorker = true;
@@ -1063,9 +1066,11 @@ static void pipeline_worker() {
#endif
#if defined(__ANDROID__)
pthread_setname_np(pthread_self(), "GXPipeline");
// setpriority(PRIO_PROCESS, 0, ...) targets the calling Linux thread.
// Pipeline creation may finish later, but must not preempt gameplay or XR.
setpriority(PRIO_PROCESS, 0, 5);
if (g_quest1PipelineScheduling) {
// setpriority(PRIO_PROCESS, 0, ...) targets the calling Linux thread.
// Quest 1 pipeline creation must not preempt gameplay or XR.
setpriority(PRIO_PROCESS, 0, 5);
}
#endif
while (true) {
@@ -1076,7 +1081,7 @@ static void pipeline_worker() {
g_pipelineCv.wait(lock, [] {
return !g_priorityPipelines.empty() ||
(!g_backgroundPipelines.empty() &&
g_activeBackgroundPipelineWorkers < MaxBackgroundPipelineWorkers) ||
g_activeBackgroundPipelineWorkers < max_background_pipeline_workers()) ||
g_pipelineThreadEnd;
});
if (g_pipelineThreadEnd) {
@@ -1125,7 +1130,8 @@ static size_t pipeline_worker_count() {
}
const size_t availableWorkers =
logicalProcessors > ReservedLogicalProcessors ? logicalProcessors - ReservedLogicalProcessors : 1;
return std::clamp(availableWorkers, size_t{1}, MaxPipelineWorkers);
const size_t maximum = g_quest1PipelineScheduling ? Quest1MaxPipelineWorkers : MaxPipelineWorkers;
return std::clamp(availableWorkers, size_t{1}, maximum);
}
template <typename PipelineConfig, typename CreateFn>
@@ -1286,6 +1292,7 @@ void initialize_pipeline_cache() {
g_pipelineFrameActive = false;
g_pipelineThreadEnd = false;
g_activeBackgroundPipelineWorkers = 0;
g_quest1PipelineScheduling = quest1_pipeline_scheduling();
if (webgpu::g_backendType == wgpu::BackendType::OpenGL || webgpu::g_backendType == wgpu::BackendType::OpenGLES ||
webgpu::g_backendType == wgpu::BackendType::WebGPU) {
@@ -1298,7 +1305,7 @@ void initialize_pipeline_cache() {
g_pipelineThreads.emplace_back(pipeline_worker);
}
Log.info("Enabled {} priority pipeline compilation workers ({} background prewarm)",
workerCount, MaxBackgroundPipelineWorkers);
workerCount, max_background_pipeline_workers());
}
load_pipeline_cache();