mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 06:08:30 +09:00
[Fix] (SelfTest): stop optional-capability failures from declaring the whole backend unsupported, and log the POST report in chunks
This commit is contained in:
@@ -702,8 +702,11 @@ namespace MobileGL::MG_Util::SelfTest {
|
|||||||
// Every emit carries the extension-presence fact the old standalone
|
// Every emit carries the extension-presence fact the old standalone
|
||||||
// GL_EXT_disjoint_timer_query row showed, plus the probe outcome.
|
// GL_EXT_disjoint_timer_query row showed, plus the probe outcome.
|
||||||
const String extensionPresent = "GL_EXT_disjoint_timer_query extension present";
|
const String extensionPresent = "GL_EXT_disjoint_timer_query extension present";
|
||||||
|
// FailOptional: a driver that advertises the extension and then cannot serve a
|
||||||
|
// query is broken in a way nothing substitutes for, but timing GPU work is not
|
||||||
|
// something the backend needs in order to run.
|
||||||
const auto fail = [&](const String& detail) {
|
const auto fail = [&](const String& detail) {
|
||||||
builder.Fail("Timer queries", extensionPresent + "; but " + detail + disabledNote);
|
builder.FailOptional("Timer queries", extensionPresent + "; but " + detail + disabledNote);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!glesFuncs.glGenQueries || !glesFuncs.glDeleteQueries || !glesFuncs.glBeginQuery ||
|
if (!glesFuncs.glGenQueries || !glesFuncs.glDeleteQueries || !glesFuncs.glBeginQuery ||
|
||||||
@@ -837,8 +840,11 @@ namespace MobileGL::MG_Util::SelfTest {
|
|||||||
const String pathNote = native ? "GL_NV_shader_noperspective_interpolation present (native path)"
|
const String pathNote = native ? "GL_NV_shader_noperspective_interpolation present (native path)"
|
||||||
: "GL_NV_shader_noperspective_interpolation absent (gl_Position.w / "
|
: "GL_NV_shader_noperspective_interpolation absent (gl_Position.w / "
|
||||||
"gl_FragCoord.w emulation path)";
|
"gl_FragCoord.w emulation path)";
|
||||||
|
// FailOptional: a shaderpack that declares a noperspective varying renders it wrong
|
||||||
|
// and nothing stands in for the interpolation, but everything that does not use one
|
||||||
|
// is unaffected, so the backend still runs.
|
||||||
const auto fail = [&](const String& detail) {
|
const auto fail = [&](const String& detail) {
|
||||||
builder.Fail("noperspective interpolation", pathNote + "; " + detail);
|
builder.FailOptional("noperspective interpolation", pathNote + "; " + detail);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!g.glCreateShader || !g.glShaderSource || !g.glCompileShader || !g.glGetShaderiv ||
|
if (!g.glCreateShader || !g.glShaderSource || !g.glCompileShader || !g.glGetShaderiv ||
|
||||||
@@ -1336,8 +1342,10 @@ namespace MobileGL::MG_Util::SelfTest {
|
|||||||
const String timestampFacts =
|
const String timestampFacts =
|
||||||
format("timestampValidBits = {} on the graphics queue family; timestampPeriod = {} ns per tick",
|
format("timestampValidBits = {} on the graphics queue family; timestampPeriod = {} ns per tick",
|
||||||
timestampValidBits, timestampPeriod);
|
timestampValidBits, timestampPeriod);
|
||||||
|
// FailOptional, for the same reason as the GLES row: the backend does not need to
|
||||||
|
// time GPU work in order to run.
|
||||||
const auto fail = [&](const String& detail) {
|
const auto fail = [&](const String& detail) {
|
||||||
builder.Fail("Timer queries", timestampFacts + "; but " + detail + disabledNote);
|
builder.FailOptional("Timer queries", timestampFacts + "; but " + detail + disabledNote);
|
||||||
};
|
};
|
||||||
const auto vkCreateDeviceFn =
|
const auto vkCreateDeviceFn =
|
||||||
reinterpret_cast<PFN_vkCreateDevice>(getInstanceProcAddr(instance, "vkCreateDevice"));
|
reinterpret_cast<PFN_vkCreateDevice>(getInstanceProcAddr(instance, "vkCreateDevice"));
|
||||||
@@ -1557,7 +1565,13 @@ namespace MobileGL::MG_Util::SelfTest {
|
|||||||
Bool subgroupPropertiesAvailable,
|
Bool subgroupPropertiesAvailable,
|
||||||
const VkPhysicalDeviceSubgroupProperties& subgroupProperties) {
|
const VkPhysicalDeviceSubgroupProperties& subgroupProperties) {
|
||||||
constexpr const char* RowName = "Subgroup first-reduction witness";
|
constexpr const char* RowName = "Subgroup first-reduction witness";
|
||||||
const auto fail = [&](String detail) { builder.Fail(RowName, Move(detail)); };
|
// FailOptional, not Fail. The witness reports whether the NATIVE subgroup
|
||||||
|
// first-reduction works; when it does not, the renderer takes its non-subgroup
|
||||||
|
// iteration path and draws the same image. Both an Adreno 830 and Mesa lavapipe
|
||||||
|
// fail this row's topology check today while running the DirectVulkan backend
|
||||||
|
// perfectly well, so a fatal verdict here would have the screen announce that a
|
||||||
|
// backend the user is looking at through that very backend cannot run.
|
||||||
|
const auto fail = [&](String detail) { builder.FailOptional(RowName, Move(detail)); };
|
||||||
|
|
||||||
if (!subgroupPropertiesAvailable) {
|
if (!subgroupPropertiesAvailable) {
|
||||||
fail("vkGetPhysicalDeviceProperties2 could not provide raw Vulkan subgroup properties");
|
fail("vkGetPhysicalDeviceProperties2 could not provide raw Vulkan subgroup properties");
|
||||||
|
|||||||
@@ -239,13 +239,34 @@ public final class PostActivity extends Activity {
|
|||||||
nativeLoaded = true;
|
nativeLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the whole report to logcat. The report is the only machine-readable form of the
|
||||||
|
* POST, and logcat drops everything past roughly 4000 bytes of a single entry - which is
|
||||||
|
* less than one backend section, so a one-call log silently truncated the report to about
|
||||||
|
* the first dozen rows. Each chunk is prefixed with its index so a reader can reassemble
|
||||||
|
* them in order (concatenate the payloads after the "] " separator).
|
||||||
|
*/
|
||||||
|
private static void logReport(String json) {
|
||||||
|
if (json == null) {
|
||||||
|
Log.i(TAG, "<null report>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final int chunkSize = 3000;
|
||||||
|
final int chunks = (json.length() + chunkSize - 1) / chunkSize;
|
||||||
|
for (int index = 0; index < chunks; ++index) {
|
||||||
|
final int start = index * chunkSize;
|
||||||
|
final int end = Math.min(start + chunkSize, json.length());
|
||||||
|
Log.i(TAG, "[" + (index + 1) + "/" + chunks + "] " + json.substring(start, end));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void runDriverPost() {
|
private static void runDriverPost() {
|
||||||
String json = null;
|
String json = null;
|
||||||
Throwable failure = null;
|
Throwable failure = null;
|
||||||
try {
|
try {
|
||||||
ensureNativeLoaded();
|
ensureNativeLoaded();
|
||||||
json = nativeRunDriverPost();
|
json = nativeRunDriverPost();
|
||||||
Log.i(TAG, json == null ? "<null report>" : json);
|
logReport(json);
|
||||||
} catch (Throwable error) {
|
} catch (Throwable error) {
|
||||||
Log.e(TAG, "Driver POST failed", error);
|
Log.e(TAG, "Driver POST failed", error);
|
||||||
failure = error;
|
failure = error;
|
||||||
|
|||||||
Reference in New Issue
Block a user