[Feat] (MG_Util, MG_IntegrationTest): POST rows for the Espryt multi-draw tier, and the scenario that pins it

Three DriverPost rows per the POST rule, since the ladder took on two
new driver dependencies: glDrawElementsBaseVertex (WARN when absent -
every base-vertex draw then costs a CPU index rewrite and an upload) and
compute shaders (INFO - the default tiers never use them). The third
names the tier that will actually run, with the full set the driver
supports, resolved by the same function the backend calls so the two can
not drift. The existing "Multi-draw base vertex" row stopped saying the
fallback is a per-draw loop, which is no longer the whole truth.

Scenario D asserts the one contract every tier shares: a multi-draw
paints exactly what the unrolled single draws paint. The reference side
is a loop of glDrawElementsBaseVertex and never enters the emulation, so
a tier cannot make itself look right by breaking both sides alike, and a
blank-frame pair is rejected outright - drawing nothing is the failure
mode this path actually has.

Nine cases, chosen for the shapes the Minecraft retraces contain none
of: narrow index types, a base vertex past the index type's range,
primitive restart inside a strip on two index types, client-memory index
arrays, and a batch with zero-count sub-draws (whose prefix sums the
flattening tier's binary search has to skip). Each of the six tiers
passes all nine on NVIDIA, and ext/auto/compute also pass on Mesa where
the ext tier is reachable.

The suite is falsifiable, not merely green: rewriting the rebase the way
MobileGlues does it - truncate to the source width, no restart
passthrough - fails exactly three cases on the drawelements tier (both
restart cases and the out-of-range base vertex) and leaves basevertex,
which rewrites nothing, passing. That control is also what turned up the
restart hole in the flattening tier fixed in the previous commit.
This commit is contained in:
BZLZHH
2026-08-07 08:16:08 -04:00
parent 0ec487c993
commit 867fe3e0ef
3 changed files with 564 additions and 3 deletions
+41 -3
View File
@@ -11,6 +11,7 @@
#include <Config.h>
#include <MGGitHash.h>
#include <MG_Backend/DirectGLES/BackendObject_DirectGLES.h>
#include <MG_Backend/DirectGLES/MultiDraw.h>
#include <MG_Backend/DirectVulkan/BackendObject_DirectVulkan.h>
// Only for the compile-time MAX_VERTEX_ATTRIBS constant asserted below. The POST still executes no
// MG_State code: it runs standalone, before MG_State::Init().
@@ -319,9 +320,46 @@ namespace MobileGL::MG_Util::SelfTest {
} else {
builder.Info("Multi-draw base vertex",
"glMultiDrawElementsBaseVertexEXT not supported (needs EXT/OES_"
"draw_elements_base_vertex plus GL_EXT_multi_draw_arrays); "
"glMultiDrawElementsBaseVertex falls back to a per-draw loop with "
"identical output");
"draw_elements_base_vertex plus GL_EXT_multi_draw_arrays); the batch "
"takes the next emulation tier instead, with identical output - see "
"\"Multi-draw elements tier\" below for the one that will run");
}
// glMultiDrawElements(BaseVertex) has no ES counterpart at all, so DirectGLES
// emulates it; these rows say which emulation the driver leaves available and
// which one will run. The two capabilities each tier leans on come first.
if (caps.SupportsDrawElementsBaseVertex) {
builder.Pass("Draw elements base vertex",
"glDrawElementsBaseVertex available (ES 3.2 core or EXT/OES_draw_elements_base_"
"vertex); a multi-draw batch can replay its sub-draws with their own base "
"vertices");
} else {
builder.Warn("Draw elements base vertex",
"glDrawElementsBaseVertex not supported (pre-ES 3.2 without EXT/OES_draw_"
"elements_base_vertex); every base-vertex draw has to be emulated by rewriting "
"the index stream on the CPU, which costs an upload per batch");
}
if (caps.SupportsComputeShader) {
builder.Pass("Compute shaders",
"available (ES 3.1 core); the opt-in \"compute\" multi-draw tier can flatten a "
"whole batch into one draw");
} else {
builder.Info("Compute shaders",
"not available (pre-ES 3.1); no impact on the default multi-draw tiers, which "
"never use compute");
}
{
// The same resolution the backend runs, over the capabilities probed here.
// Like the Magma tier row, the preference comes from MG_Config::Features,
// which is only populated once MobileGL::Initialize() has parsed the
// environment - a POST executed standalone before that reports the
// unclamped choice, so the row names the variable rather than implying it
// was consulted.
using MG_Backend::DirectGLES::MultiDrawImpl::ResolveTier;
String resolution;
ResolveTier(caps, glesFuncs, MG_Config::Features.EsprytMultiDrawMode, &resolution);
builder.Info("Multi-draw elements tier",
"glMultiDrawElements(BaseVertex) emulation: " + resolution +
"; override with MOBILEGL_ESPRYT_MULTIDRAW_MODE");
}
if (caps.SupportsTextureBorderClamp) {
builder.Pass("Texture border clamp",