mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-11 13:48:30 +09:00
[Feat] (MG_Impl, MG_State, MG_Util): the GL_KHR_parallel_shader_compile surface (P1 stage 5)
GL_COMPLETION_STATUS_KHR in both object getters, reading the non-joining node-direct state - the one query that must never block is asserted never to reach a join gate. glMaxShaderCompilerThreadsKHR/ARB share one implementation: a zero count suspends async FIRST and then joins every outstanding compile and link this context owns (suspend-before-join is the only order whose post-condition is 'nothing in flight'), a nonzero count restores; the suspension is a process latch the extension controls, kept distinct from the configuration flag that gates the ADVERTISEMENT - an app that turned threading off has not made the extension disappear. GL_MAX_SHADER_COMPILER_THREADS_KHR reports the thread count. DriverPost gains the MobileGL-side async row (PASS/INFO naming the env knob) and an informational host-driver row backed by a new GLES capability probe. The extension string itself lands per backend in the two follow-up commits, keeping this one green stand-alone.
This commit is contained in:
@@ -107,6 +107,25 @@ namespace MobileGL::MG_Util::Async {
|
||||
return kAsyncShaderCompileDefault;
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Written only by glMaxShaderCompilerThreadsKHR/ARB, i.e. only on the GL thread, but
|
||||
// read by every enqueue decision, so it is atomic rather than plain: a worker never
|
||||
// reads it, but a second GL thread in another context shares this process-wide pool.
|
||||
std::atomic<Bool> g_asyncSuspendedByApplication{false};
|
||||
} // namespace
|
||||
|
||||
void SetAsyncShaderCompileSuspended(const Bool suspended) {
|
||||
g_asyncSuspendedByApplication.store(suspended, std::memory_order_release);
|
||||
}
|
||||
|
||||
Bool IsAsyncShaderCompileSuspended() {
|
||||
return g_asyncSuspendedByApplication.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
Bool AsyncShaderCompileActive() {
|
||||
return AsyncShaderCompileEnabled() && !IsAsyncShaderCompileSuspended();
|
||||
}
|
||||
|
||||
Uint DetectShaderCompileThreadCount() {
|
||||
if (const Uint32 configured = MG_Config::Features.AsyncShaderCompileThreads; configured > 0) {
|
||||
// An explicit request is honoured as given - it is the escape hatch for measuring
|
||||
|
||||
@@ -27,11 +27,37 @@ namespace MobileGL::MG_Util::Async {
|
||||
inline constexpr Bool kAsyncShaderCompileDefault = false;
|
||||
|
||||
// MOBILEGL_ASYNC_SHADER_COMPILE forces the answer either way; unset keeps the built-in
|
||||
// default above. Falsy is a complete kill switch: it reverts the threading *and* (from
|
||||
// the extension stage on) withdraws GL_KHR_parallel_shader_compile, so the application
|
||||
// behaviour change goes with it.
|
||||
// default above. Falsy is a complete kill switch: it reverts the threading *and*
|
||||
// withdraws GL_KHR_parallel_shader_compile, so the application behaviour change goes
|
||||
// with it.
|
||||
//
|
||||
// This is the pure CONFIGURATION answer, and it is deliberately not affected by
|
||||
// glMaxShaderCompilerThreadsKHR: it is what decides whether the extension is advertised
|
||||
// at all, and an application that switched threading off through the extension has not
|
||||
// made the extension go away. Code deciding whether to enqueue asks
|
||||
// AsyncShaderCompileActive() instead.
|
||||
Bool AsyncShaderCompileEnabled();
|
||||
|
||||
// ---- GL_KHR_parallel_shader_compile: glMaxShaderCompilerThreadsKHR(count) ----
|
||||
// The extension defines count == 0 as "no compiler threads": compilation must happen on
|
||||
// the application's thread. That is a mode switch, not a concurrency budget of one, so it
|
||||
// is a latch of its own rather than SetMaxConcurrency(1) - a budget of one would still
|
||||
// move the work off-thread and still report GL_COMPLETION_STATUS_KHR = GL_FALSE, both of
|
||||
// which the extension forbids after a zero count.
|
||||
//
|
||||
// The latch is process-wide, matching the pool it suspends. It is released by the next
|
||||
// nonzero glMaxShaderCompilerThreadsKHR/ARB, which is the only thing that releases it:
|
||||
// no implicit re-arm on eglInitialize, on a context switch or at any join, because an
|
||||
// application that asked for serial compilation gets to keep it until it asks otherwise.
|
||||
void SetAsyncShaderCompileSuspended(Bool suspended);
|
||||
Bool IsAsyncShaderCompileSuspended();
|
||||
|
||||
// What every enqueue site branches on: the configuration flag AND the absence of a
|
||||
// glMaxShaderCompilerThreadsKHR(0). False makes glCompileShader/glLinkProgram run their
|
||||
// bodies inline, exactly as the flag-off path does, which is what makes a subsequent
|
||||
// GL_COMPLETION_STATUS_KHR read immediately GL_TRUE.
|
||||
Bool AsyncShaderCompileActive();
|
||||
|
||||
// min(4, big cores), where a big core is one whose cpufreq ceiling is within 15% of the
|
||||
// machine maximum; the whole CPU count where that sysfs tree is absent. Clamped to [1, 4]
|
||||
// because peak RSS scales as workers x largest glslang arena, and four
|
||||
|
||||
Reference in New Issue
Block a user