mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-09 20:58:31 +09:00
Still fully synchronous - EnsureLinkJoined()/EnsureCompileJoined() are empty
inline no-ops (verified to fold away at every one of the ~1200 call sites;
this project builds without LTO) - but every read of link- or compile-produced
state now goes through a private accessor the compiler enforces, so when
stage 4 moves the bodies onto pool workers, 'which reads must join' is a
type-system fact instead of a 400-line audit.
- ProgramObject: the 31 fields ResetLinkArtifacts clears plus the 5 link
outputs it forgot (infoLog, linkedFragData{Location,Index}, the geometry
strip-capture pair) move into a nested LinkArtifacts behind Artifacts().
ResetLinkArtifacts is now a worker-safe pure clear; the link-observable
version bumps (backendState/link/uboContent) move to a GL-thread-only
BumpLinkObservableVersions() called once from Link()'s prologue and from
glProgramBinary's mandated failure - the link body never writes them, so
a stage-4 worker cannot lose an invalidation against the draw path.
- ShaderObject: compile artifacts (TShader, preprocessed source, side-channel
maps, status/log, consume-once flag) behind Compiled(); the P0b layer-1
memo trio deliberately stays outside as the future non-joining
COMPLETION_STATUS_KHR fast path.
- CompileEnv (new): a GL-thread snapshot of everything the compile pipeline
used to read live from the backend mid-parse - compute limits (the
GetIntegeri_v reach-back is gone from the worker path), advertised
extensions, device quirks, TBuiltInResource inputs. Captured lazily per
backend activation; the consume-once re-parse now runs against the same
env as the original parse.
- The GL-thread prologue / worker-body boundary is marked in Link() where
the stage sort ends; everything below is a pure function of the snapshot.
Public getter signatures unchanged - MG_Impl and both backends compile
untouched. Unit 476/476, Program suites 117/117, DirectGLES retrace 38/39 on
llvmpipe (the one failure is the known pre-existing non-CI iterationrp case;
the NVIDIA userspace driver was updated out from under the running kernel
module mid-session, so GLX there is down until a reboot).
82 lines
5.1 KiB
C++
82 lines
5.1 KiB
C++
// MobileGL - MobileGL/MG_Util/ShaderTranspiler/ShaderSourceProcessor.h
|
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
|
// Licensed under the GNU Lesser General Public License v3.0:
|
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
// End of Source File Header
|
|
|
|
#pragma once
|
|
#include <Includes.h>
|
|
#include <MG_State/GLState/ProgramState/ShaderObject.h>
|
|
#include <MG_Util/ShaderTranspiler/CompileEnv.h>
|
|
|
|
namespace MobileGL {
|
|
enum class ShaderProfile {
|
|
Core,
|
|
Compatibility,
|
|
ES,
|
|
};
|
|
|
|
namespace MG_Util {
|
|
namespace ShaderTranspiler {
|
|
// The whole source-rewriting pipeline. `env` is the compile-time snapshot of
|
|
// everything outside (stage, source) this reads - advertised extensions and the
|
|
// device-quirk inputs - so the transformation is a pure function of its three
|
|
// arguments and can run on a worker thread.
|
|
void PreprocessShaderSource(ShaderStage stage, String& source, const CompileEnv& env);
|
|
// Convenience overload that resolves the current context's env itself. GL thread
|
|
// only, and deliberately not used by the compile pipeline: it exists for the unit
|
|
// tests and diagnostics that drive the preprocessor standalone.
|
|
void PreprocessShaderSource(ShaderStage stage, String& source);
|
|
|
|
// Some desktop-captured compute shaders build a workgroup-wide linear prefix scan
|
|
// from subgroupInclusiveAdd plus a shared array of subgroup totals. Qualcomm's
|
|
// Vulkan driver miscompiles that exact float InclusiveScan path for native subgroups
|
|
// wider than the capture's 32 lanes. For the narrowly recognized, uniform-control-
|
|
// flow template, replace the subgroup-local scan with a shared-memory, strict
|
|
// left-fold over virtual 32-lane segments. Returns true only when the complete safe
|
|
// template was recognized and rewritten. PreprocessShaderSource reaches this through
|
|
// its device-quirk registry: by default only on detected Qualcomm Vulkan devices,
|
|
// overridable either way with MOBILEGL_QUIRK_SUBGROUP_PREFIX_SCAN=1/0. The explicit
|
|
// entry point exists for deterministic tests.
|
|
Bool RewriteLinearSubgroupPrefixScanForVulkan(ShaderStage stage, Uint32 nativeSubgroupSize, String& source);
|
|
|
|
// Rewrites a "#version 330 core" directive that PreprocessShaderSource normalized down
|
|
// from a legacy desktop version back up to "#version 460 core". Returns false (leaving
|
|
// the source untouched) for anything else: ES, compatibility, or an already-modern
|
|
// declaration. Exists so a shader that only parses under the laxer 460 rules - e.g. it
|
|
// uses 420-era syntax without the matching #extension line, which real drivers tend to
|
|
// accept - can be retried instead of failing to compile.
|
|
Bool RetargetLegacyVersionDirectiveTo460(String& source);
|
|
|
|
// GLSL reserves a few names glslang happily accepts as identifiers ("packed",
|
|
// "row_major" outside a layout(...) list, the image*Shadow family). Returns the
|
|
// compile-error text for the first violation, or nullopt for a clean source.
|
|
std::optional<String> FindReservedIdentifierViolation(const String& source);
|
|
|
|
// Explicit layout(location = N) qualifiers on default-block uniform declarations,
|
|
// keyed by declared name (no "[0]" suffix). Multi-declarator statements assign
|
|
// consecutive locations, advancing by the array element count.
|
|
//
|
|
// Exists because the single link-compatible parse runs under relaxed Vulkan rules,
|
|
// where glslang's vkRelaxedRemapUniformVariable moves plain uniforms into
|
|
// MGL_GLOBAL_UBO and DISCARDS their location qualifiers ("ignoring layout qualifier
|
|
// for uniform location"); opaque uniforms keep theirs. This lexical side-channel
|
|
// restores the discarded locations to the GL location assigner
|
|
// (ProgramObject::DoReflection). It scans preprocessor-visible text, so a
|
|
// declaration inside an inactive #if branch is still recorded - harmless unless a
|
|
// pack declares the same uniform with different explicit locations in alternative
|
|
// branches (none observed; explicit uniform locations have zero incidence in the
|
|
// shader-pack corpus, this is an ARB_explicit_uniform_location conformance surface).
|
|
UnorderedMap<String, Int> ExtractExplicitUniformLocations(const String& source);
|
|
|
|
// Explicit layout(binding = N) on sampler/image uniforms, i.e. their initial
|
|
// texture/image units. The Vulkan-client relaxed parse strips these before
|
|
// mapIO can capture them, so they are recovered lexically (same narrow
|
|
// grammar discipline as ExtractExplicitUniformLocations).
|
|
UnorderedMap<String, Uint> ExtractExplicitOpaqueBindings(const String& source);
|
|
} // namespace ShaderTranspiler
|
|
} // namespace MG_Util
|
|
} // namespace MobileGL
|