mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 20:28:32 +09:00
[Fix, Test] (MG_Backend/DirectGLES, MG_Util, CI): keep an explicit LOD constant under a new avoid flag - folding the bias uniform into it kills the ANGLE llvmpipe JIT
This commit is contained in:
@@ -411,6 +411,9 @@ jobs:
|
||||
if [ "${{ matrix.backend.name }}" = "DirectGLES" ] && [ "${{ matrix.case.name }}" = "minecraft-1.21.4-fabric-iris-bliss-in-world" ]; then
|
||||
extra_retrace_args+=(--avoid-angle-llvmpipe-sampler-mipmap-min-filter)
|
||||
fi
|
||||
if [ "${{ matrix.backend.name }}" = "DirectGLES" ] && [ "${{ matrix.case.avoid_angle_llvmpipe_explicit_lod_bias || false }}" = "true" ]; then
|
||||
extra_retrace_args+=(--avoid-angle-llvmpipe-explicit-lod-bias)
|
||||
fi
|
||||
if [ "${{ matrix.case.coherent_as_flush || false }}" = "true" ]; then
|
||||
extra_retrace_args+=(--coherent-as-flush)
|
||||
fi
|
||||
|
||||
@@ -89,6 +89,13 @@ namespace MobileGL::MG_Config {
|
||||
// MOBILEGL_AVOID_SAMPLER_MIPMAP_MIN_FILTER: avoid mipmap min filters in samplers,
|
||||
// resolves certain rendering bugs on ANGLE + llvmpipe.
|
||||
Bool AvoidSamplerMipmapMinFilter = false;
|
||||
// MOBILEGL_AVOID_EXPLICIT_LOD_BIAS: leave an already-explicit LOD argument alone when
|
||||
// emulating GL_TEXTURE_LOD_BIAS, instead of adding the bias uniform to it. Injecting
|
||||
// the uniform turns a compile-time-constant LOD into a runtime expression, which
|
||||
// sends ANGLE + llvmpipe down a mip-selection path that dereferences a NULL
|
||||
// descriptor and kills the process. Deviates from spec (Vulkan adds the bias to
|
||||
// OpImageSampleExplicitLod), so it is an avoidance for that stack only.
|
||||
Bool AvoidExplicitLodBias = false;
|
||||
// MOBILEGL_COHERENT_AS_FLUSH: app-compat for engines (e.g. Flywheel) that write
|
||||
// GPU-read data through persistent GL_MAP_FLUSH_EXPLICIT_BIT maps they never
|
||||
// flush. Persistent FLUSH_EXPLICIT map requests are rewritten to coherent
|
||||
|
||||
@@ -171,6 +171,7 @@ namespace MobileGL::MG_ConfigLoader {
|
||||
features.MagmaFramesInFlight = QueryEnvUint32("MOBILEGL_MAGMA_FRAMESINFLIGHT", 3, 1, 64);
|
||||
features.AvoidSamplerMipmapMinFilter =
|
||||
QueryEnvFlag("MOBILEGL_AVOID_SAMPLER_MIPMAP_MIN_FILTER");
|
||||
features.AvoidExplicitLodBias = QueryEnvFlag("MOBILEGL_AVOID_EXPLICIT_LOD_BIAS");
|
||||
features.CoherentAsFlush = QueryEnvFlag("MOBILEGL_COHERENT_AS_FLUSH");
|
||||
features.TraceSkipAutodestroy = QueryEnvFlag("MOBILEGL_TRACE_SKIP_AUTODESTROY");
|
||||
features.DisableUboRing = QueryEnvFlag("MOBILEGL_DISABLE_UBO_RING");
|
||||
|
||||
@@ -55,6 +55,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
return g_GLESCapabilities.AvoidSamplerMipmapMinFilter;
|
||||
}
|
||||
|
||||
static Bool ShouldAvoidExplicitLodBiasOnAngleLlvmpipe() {
|
||||
// IsAngleLlvmpipeRenderer combined with the MOBILEGL_AVOID_EXPLICIT_LOD_BIAS
|
||||
// feature toggle, both resolved in FillInGLESCapabilities.
|
||||
return g_GLESCapabilities.AvoidExplicitLodBias;
|
||||
}
|
||||
|
||||
static GLenum ResolveBackendMinFilter(const SamplerParameters& samplerParams,
|
||||
Bool avoidMipmapMinFilter) {
|
||||
GLenum filter = MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.minFilter,
|
||||
@@ -4466,7 +4472,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
source = ProcessOutColorLocations(source);
|
||||
source = ForceFlatIntegerVaryings(source, glShaderType);
|
||||
source = BroadcastLegacyFragColor(std::move(source), glShaderType, m_fragColorBroadcastCount);
|
||||
source = EmulateTextureLodBias(source);
|
||||
source = EmulateTextureLodBias(source, ShouldAvoidExplicitLodBiasOnAngleLlvmpipe());
|
||||
source = EmulateBaseInstanceInVertexShader(std::move(source), glShaderType);
|
||||
source = PromoteDrawParameterGlobalsToUniforms(std::move(source), glShaderType);
|
||||
source = ForceSupporterOutput(source);
|
||||
|
||||
@@ -957,7 +957,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
String EmulateTextureLodBias(const String& glslCode) {
|
||||
String EmulateTextureLodBias(const String& glslCode, Bool avoidExplicitLodBias) {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
@@ -1018,6 +1018,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
if (samplerIt == samplerNames.end()) continue;
|
||||
|
||||
const String& biasName = samplerIt->second;
|
||||
if (form->explicitLodArg >= 0 && avoidExplicitLodBias) {
|
||||
// The lookup already names its level; leaving it alone keeps a constant
|
||||
// LOD constant. Costs the bias on explicit-LOD lookups only.
|
||||
continue;
|
||||
}
|
||||
if (form->explicitLodArg >= 0) {
|
||||
// Explicit LOD: the bias adds to it, as Vulkan does for
|
||||
// OpImageSampleExplicitLod and as the CTS reference expects.
|
||||
|
||||
@@ -183,7 +183,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// the bound texture's (or sampler object's) value into it; a shader whose samplers
|
||||
// all have a zero bias is therefore unaffected. Returns the source unchanged when
|
||||
// there is nothing to rewrite.
|
||||
String EmulateTextureLodBias(const String& glslCode);
|
||||
//
|
||||
// avoidExplicitLodBias leaves lookups that already carry an explicit LOD untouched,
|
||||
// so their constant level stays constant; only the implicit-LOD forms take the bias.
|
||||
// Off by default and only ever set on ANGLE + llvmpipe, where injecting the uniform
|
||||
// into a constant LOD crashes the driver (MOBILEGL_AVOID_EXPLICIT_LOD_BIAS).
|
||||
String EmulateTextureLodBias(const String& glslCode, Bool avoidExplicitLodBias = false);
|
||||
} // namespace PrgramImpl
|
||||
|
||||
namespace Utils {
|
||||
|
||||
@@ -1343,6 +1343,8 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
caps.IsAngleRenderer && caps.GLESRendererString.find("llvmpipe") != String::npos;
|
||||
caps.AvoidSamplerMipmapMinFilter =
|
||||
caps.IsAngleLlvmpipeRenderer && MG_Config::Features.AvoidSamplerMipmapMinFilter;
|
||||
caps.AvoidExplicitLodBias =
|
||||
caps.IsAngleLlvmpipeRenderer && MG_Config::Features.AvoidExplicitLodBias;
|
||||
MGLOG_I(" GL_EXT_disjoint_timer_query supported: %s",
|
||||
caps.SupportsDisjointTimerQuery ? "true" : "false");
|
||||
MGLOG_I(" GL_KHR_parallel_shader_compile supported: %s",
|
||||
@@ -1351,6 +1353,7 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
MGLOG_I(" ANGLE llvmpipe renderer: %s", caps.IsAngleLlvmpipeRenderer ? "true" : "false");
|
||||
MGLOG_I(" Avoid sampler mipmap min filter: %s",
|
||||
caps.AvoidSamplerMipmapMinFilter ? "true" : "false");
|
||||
MGLOG_I(" Avoid explicit LOD bias: %s", caps.AvoidExplicitLodBias ? "true" : "false");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1156,6 +1156,9 @@ namespace MobileGL {
|
||||
// MOBILEGL_AVOID_SAMPLER_MIPMAP_MIN_FILTER feature toggle:
|
||||
// sampler min filters should drop their mipmap component.
|
||||
Bool AvoidSamplerMipmapMinFilter = false;
|
||||
// IsAngleLlvmpipeRenderer combined with the MOBILEGL_AVOID_EXPLICIT_LOD_BIAS
|
||||
// feature toggle: LOD-bias emulation should not touch explicit-LOD lookups.
|
||||
Bool AvoidExplicitLodBias = false;
|
||||
// True when indirect draws leak the command's baseInstance word ("reserved,
|
||||
// must be zero" in unextended ES) into gl_InstanceID. Conforming ES drivers
|
||||
// keep gl_InstanceID zero-based; ANGLE's Vulkan backend hands the command
|
||||
|
||||
@@ -154,6 +154,11 @@ bool LoadMobileGL(const Request& request, std::string& error) {
|
||||
} else {
|
||||
unsetenv("MOBILEGL_AVOID_SAMPLER_MIPMAP_MIN_FILTER");
|
||||
}
|
||||
if (request.avoidAngleLlvmpipeExplicitLodBias) {
|
||||
setenv("MOBILEGL_AVOID_EXPLICIT_LOD_BIAS", "1", 1);
|
||||
} else {
|
||||
unsetenv("MOBILEGL_AVOID_EXPLICIT_LOD_BIAS");
|
||||
}
|
||||
if (request.coherentAsFlush) {
|
||||
setenv("MOBILEGL_COHERENT_AS_FLUSH", "1", 1);
|
||||
} else {
|
||||
@@ -792,6 +797,8 @@ bool WriteResultJson(const Request& request, const Result& result) {
|
||||
file << " \"usePbuffer\": " << (request.usePbuffer ? "true" : "false") << ",\n";
|
||||
file << " \"avoidAngleLlvmpipeSamplerMipmapMinFilter\": "
|
||||
<< (request.avoidAngleLlvmpipeSamplerMipmapMinFilter ? "true" : "false") << ",\n";
|
||||
file << " \"avoidAngleLlvmpipeExplicitLodBias\": "
|
||||
<< (request.avoidAngleLlvmpipeExplicitLodBias ? "true" : "false") << ",\n";
|
||||
file << " \"holdMs\": " << request.holdMs << ",\n";
|
||||
file << " \"mismatchPixels\": " << result.mismatchPixels << "\n";
|
||||
file << "}\n";
|
||||
|
||||
@@ -39,6 +39,7 @@ struct Request {
|
||||
bool useAngle = false;
|
||||
bool usePbuffer = true;
|
||||
bool avoidAngleLlvmpipeSamplerMipmapMinFilter = false;
|
||||
bool avoidAngleLlvmpipeExplicitLodBias = false;
|
||||
bool coherentAsFlush = false;
|
||||
int holdMs = 0;
|
||||
};
|
||||
|
||||
@@ -102,6 +102,7 @@ Java_top_mobilegl_plugin_trace_TraceReplayActivity_nativeRunTraceReplay(JNIEnv*
|
||||
jboolean useAngle,
|
||||
jboolean usePbuffer,
|
||||
jboolean avoidAngleLlvmpipeSamplerMipmapMinFilter,
|
||||
jboolean avoidAngleLlvmpipeExplicitLodBias,
|
||||
jboolean coherentAsFlush) {
|
||||
mobilegl_trace::Request request;
|
||||
request.tracePath = ToString(env, tracePath);
|
||||
@@ -127,6 +128,7 @@ Java_top_mobilegl_plugin_trace_TraceReplayActivity_nativeRunTraceReplay(JNIEnv*
|
||||
request.usePbuffer = usePbuffer == JNI_TRUE;
|
||||
request.avoidAngleLlvmpipeSamplerMipmapMinFilter =
|
||||
avoidAngleLlvmpipeSamplerMipmapMinFilter == JNI_TRUE;
|
||||
request.avoidAngleLlvmpipeExplicitLodBias = avoidAngleLlvmpipeExplicitLodBias == JNI_TRUE;
|
||||
request.coherentAsFlush = coherentAsFlush == JNI_TRUE;
|
||||
|
||||
ScopedTraceReplayState replayState;
|
||||
|
||||
@@ -114,6 +114,7 @@ public final class TraceReplayActivity extends Activity {
|
||||
request.useAngle,
|
||||
request.usePbuffer,
|
||||
request.avoidAngleLlvmpipeSamplerMipmapMinFilter,
|
||||
request.avoidAngleLlvmpipeExplicitLodBias,
|
||||
request.coherentAsFlush
|
||||
);
|
||||
Log.i(TAG, result.toString());
|
||||
@@ -145,6 +146,7 @@ public final class TraceReplayActivity extends Activity {
|
||||
boolean useAngle,
|
||||
boolean usePbuffer,
|
||||
boolean avoidAngleLlvmpipeSamplerMipmapMinFilter,
|
||||
boolean avoidAngleLlvmpipeExplicitLodBias,
|
||||
boolean coherentAsFlush
|
||||
);
|
||||
|
||||
@@ -168,6 +170,7 @@ public final class TraceReplayActivity extends Activity {
|
||||
final boolean useAngle;
|
||||
final boolean usePbuffer;
|
||||
final boolean avoidAngleLlvmpipeSamplerMipmapMinFilter;
|
||||
final boolean avoidAngleLlvmpipeExplicitLodBias;
|
||||
final boolean coherentAsFlush;
|
||||
|
||||
private TraceReplayRequest(
|
||||
@@ -190,6 +193,7 @@ public final class TraceReplayActivity extends Activity {
|
||||
boolean useAngle,
|
||||
boolean usePbuffer,
|
||||
boolean avoidAngleLlvmpipeSamplerMipmapMinFilter,
|
||||
boolean avoidAngleLlvmpipeExplicitLodBias,
|
||||
boolean coherentAsFlush
|
||||
) {
|
||||
this.tracePath = tracePath;
|
||||
@@ -211,6 +215,7 @@ public final class TraceReplayActivity extends Activity {
|
||||
this.useAngle = useAngle;
|
||||
this.usePbuffer = usePbuffer;
|
||||
this.avoidAngleLlvmpipeSamplerMipmapMinFilter = avoidAngleLlvmpipeSamplerMipmapMinFilter;
|
||||
this.avoidAngleLlvmpipeExplicitLodBias = avoidAngleLlvmpipeExplicitLodBias;
|
||||
this.coherentAsFlush = coherentAsFlush;
|
||||
}
|
||||
|
||||
@@ -237,6 +242,7 @@ public final class TraceReplayActivity extends Activity {
|
||||
intent.getBooleanExtra("use_angle", false),
|
||||
intent.getBooleanExtra("use_pbuffer", false),
|
||||
intent.getBooleanExtra("avoid_angle_llvmpipe_sampler_mipmap_min_filter", false),
|
||||
intent.getBooleanExtra("avoid_angle_llvmpipe_explicit_lod_bias", false),
|
||||
intent.getBooleanExtra("coherent_as_flush", false)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ Usage:
|
||||
--crop-height N \
|
||||
[--use-pbuffer] \
|
||||
[--avoid-angle-llvmpipe-sampler-mipmap-min-filter] \
|
||||
[--avoid-angle-llvmpipe-explicit-lod-bias] \
|
||||
[--coherent-as-flush] \
|
||||
--timeout-seconds N
|
||||
|
||||
@@ -40,6 +41,9 @@ Set MOBILEGL_RETRACE_USE_PBUFFER=1 or pass --use-pbuffer to run DirectGLES
|
||||
against an offscreen EGL pbuffer instead of the Activity surface.
|
||||
Pass --avoid-angle-llvmpipe-sampler-mipmap-min-filter for DirectGLES traces that
|
||||
need ANGLE llvmpipe sampler mipmap filters downgraded to avoid driver stalls.
|
||||
Pass --avoid-angle-llvmpipe-explicit-lod-bias for DirectGLES traces whose shaders
|
||||
sample with an explicit LOD that ANGLE llvmpipe cannot take a LOD bias on
|
||||
(MOBILEGL_AVOID_EXPLICIT_LOD_BIAS=1).
|
||||
Pass --coherent-as-flush for traces whose engine writes persistent
|
||||
GL_MAP_FLUSH_EXPLICIT_BIT maps it never flushes (MOBILEGL_COHERENT_AS_FLUSH=1).
|
||||
EOF
|
||||
@@ -98,6 +102,7 @@ crop_width=""
|
||||
crop_height=""
|
||||
use_pbuffer=0
|
||||
avoid_angle_llvmpipe_sampler_mipmap_min_filter=0
|
||||
avoid_angle_llvmpipe_explicit_lod_bias=0
|
||||
coherent_as_flush=0
|
||||
timeout_seconds=""
|
||||
|
||||
@@ -134,6 +139,10 @@ while [ "$#" -gt 0 ]; do
|
||||
avoid_angle_llvmpipe_sampler_mipmap_min_filter=1
|
||||
shift 1
|
||||
;;
|
||||
--avoid-angle-llvmpipe-explicit-lod-bias)
|
||||
avoid_angle_llvmpipe_explicit_lod_bias=1
|
||||
shift 1
|
||||
;;
|
||||
--coherent-as-flush) coherent_as_flush=1; shift 1 ;;
|
||||
--timeout-seconds) timeout_seconds="$(next_arg "$@")"; shift 2 ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
@@ -320,6 +329,9 @@ run_retrace() {
|
||||
if [ "${avoid_angle_llvmpipe_sampler_mipmap_min_filter}" -eq 1 ] && [ "${backend}" = "DirectGLES" ]; then
|
||||
set -- "$@" --ez avoid_angle_llvmpipe_sampler_mipmap_min_filter true
|
||||
fi
|
||||
if [ "${avoid_angle_llvmpipe_explicit_lod_bias}" -eq 1 ] && [ "${backend}" = "DirectGLES" ]; then
|
||||
set -- "$@" --ez avoid_angle_llvmpipe_explicit_lod_bias true
|
||||
fi
|
||||
if [ "${coherent_as_flush}" -eq 1 ]; then
|
||||
set -- "$@" --ez coherent_as_flush true
|
||||
fi
|
||||
|
||||
@@ -275,7 +275,10 @@ default; pass `--ez use_pbuffer true` to use the offscreen pbuffer path. Always
|
||||
process-local. For cases registered with `coherent_as_flush` (Flywheel-style
|
||||
unflushed persistent maps, e.g. the Create fixtures), pass
|
||||
`--ez coherent_as_flush true` so the replay runs with
|
||||
`MOBILEGL_COHERENT_AS_FLUSH=1`.
|
||||
`MOBILEGL_COHERENT_AS_FLUSH=1`. For cases registered with
|
||||
`avoid_angle_llvmpipe_explicit_lod_bias` (DirectGLES on ANGLE llvmpipe, e.g. the
|
||||
sundial-lite fixture), pass `--ez avoid_angle_llvmpipe_explicit_lod_bias true` so
|
||||
the replay runs with `MOBILEGL_AVOID_EXPLICIT_LOD_BIAS=1`.
|
||||
|
||||
## Reproducing the Android DirectGLES lane on Linux (ANGLE on lavapipe)
|
||||
|
||||
|
||||
@@ -184,6 +184,8 @@ def run_case(case, backend):
|
||||
command.append("--use-pbuffer")
|
||||
if backend_info["use_angle"] and case["name"] == BLISS_CASE:
|
||||
command.append("--avoid-angle-llvmpipe-sampler-mipmap-min-filter")
|
||||
if backend_info["use_angle"] and case.get("avoid_angle_llvmpipe_explicit_lod_bias"):
|
||||
command.append("--avoid-angle-llvmpipe-explicit-lod-bias")
|
||||
if case.get("coherent_as_flush"):
|
||||
command.append("--coherent-as-flush")
|
||||
env = dict(**__import__("os").environ)
|
||||
|
||||
@@ -181,7 +181,8 @@
|
||||
"name": "minecraft-1.21.4-fabric-iris-sundial-lite-in-world",
|
||||
"trace_archive": "minecraft-1.21.4-fabric-iris-sundial-lite-in-world.tgz",
|
||||
"golden": "minecraft-1.21.4-fabric-iris-sundial-lite-in-world.0000150023.png",
|
||||
"target_call": 150023
|
||||
"target_call": 150023,
|
||||
"avoid_angle_llvmpipe_explicit_lod_bias": true
|
||||
},
|
||||
{
|
||||
"name": "minecraft-1.21.4-fabric-iris-complementary-reimagined-in-world",
|
||||
|
||||
Reference in New Issue
Block a user