mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 04:08:32 +09:00
Bothd7976326bugs passed every unit test while corrupting real frames - state-level assertions cannot see them. This module renders and reads back. A headless EGL-pbuffer harness (no window, no GLFW) linking MobileGL_s directly, registered once per backend under the ctest label integration-gpu, behind the default-OFF option MOBILEGL_BUILD_INTEGRATION_TEST. The platform pre-flight runs the ENTIRE bring-up in a forked child first - MobileGL aborts rather than returning errors on an unusable platform, and the child dying on any signal turns into a clean GTEST_SKIP instead of taking the test binary down. MOBILEGL_ITEST_REQUIRE_GPU makes the label falsifiable: with it set, an unusable harness (or a context that lands on a software rasterizer) is a FAILURE - without it, a CI runner whose driver pinning silently broke reports the same green as one that rendered every frame. Configure-time detection pins the EGL vendor and Vulkan ICD jsons, preferring hardware vendors and never selecting llvmpipe/lavapipe. Scenarios assert on glReadPixels with whole-region pixel counts (a 2x2 quadrant pattern whose signature distinguishes all eight square symmetries; every region predicate reports the first offending pixel): - OrientationScenario: default -> FBO -> default, pinning the transform-flags memo key. Keying GetBaseTransformFlagsRaw on the pre-transform alone fails exactly 3 entries. - StreamedArenaScenario: an untouched streamed vertex buffer must survive transient-arena recycling. Re-enabling only the cross-frame vertex revalidation fails exactly this entry. - CrossFrameBufferScenario + ResidentIndexScenario: cross-frame mutation matrix (SubData, map/unmap, persistent+flush, coherent persistent, orphan, CopyBufferSubData; vertex and index) plus six adversarial resident-EBO constructions. Instrumentation showed the cross-frame EBO memo cannot be made to serve wrong bytes from GL level on this stack (89 entries, 81 accepts, zero divergent slices) - these cases are freshness tripwires, documented as such in-file; the EBO half ofd7976326remains unpinned by a failing test. At the buggy commit72ee7c43the suite fails 4 entries (3 orientation + 1 streamed-arena); atd7976326all 52 pass, 5 consecutive runs, zero flakes, and the default build is bit-for-bit unaffected (unit suite unchanged). Adversarially verified twice, including hostile-platform sweeps (26 configurations, all clean skips) and hand-edits of each production hole in isolation.
54 lines
2.1 KiB
C++
54 lines
2.1 KiB
C++
// MobileGL - MobileGL/MG_IntegrationTest/Main.cpp
|
|
// 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
|
|
//
|
|
// Entry point for the headless GPU integration scenarios.
|
|
//
|
|
// The banner lives in a gtest Environment rather than in main() on purpose:
|
|
// Environment::SetUp does not run for `--gtest_list_tests`, which is what CMake
|
|
// invokes at build time to discover the cases. Discovery therefore never brings
|
|
// up EGL, never needs a GPU and cannot hang.
|
|
|
|
#include <gtest/gtest.h>
|
|
#include <cstdio>
|
|
|
|
#include "Harness/HeadlessGL.h"
|
|
|
|
namespace {
|
|
|
|
class HarnessBanner : public ::testing::Environment {
|
|
public:
|
|
void SetUp() override {
|
|
const MGITest::HeadlessGL& gl = MGITest::HeadlessGL::Get();
|
|
std::fprintf(stderr, "MobileGL integration scenarios: backend=%s\n", gl.BackendName().c_str());
|
|
if (gl.Usable()) {
|
|
std::fprintf(stderr, " renderer: %s\n surface: %dx%d pbuffer (headless)\n",
|
|
gl.RendererString().c_str(), gl.Width(), gl.Height());
|
|
} else if (MGITest::RequireGpu()) {
|
|
std::fprintf(stderr,
|
|
" FAILING every scenario (MOBILEGL_ITEST_REQUIRE_GPU is set): %s\n",
|
|
gl.SkipReason().c_str());
|
|
} else {
|
|
std::fprintf(stderr,
|
|
" SKIPPING every scenario: %s\n"
|
|
" (set MOBILEGL_ITEST_REQUIRE_GPU=1 to make this a failure instead - a run that\n"
|
|
" skipped everything is otherwise indistinguishable from one that passed)\n",
|
|
gl.SkipReason().c_str());
|
|
}
|
|
}
|
|
|
|
void TearDown() override { MGITest::HeadlessGL::Get().ShutDown(); }
|
|
};
|
|
|
|
} // namespace
|
|
|
|
int main(int argc, char** argv) {
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
::testing::AddGlobalTestEnvironment(new HarnessBanner());
|
|
return RUN_ALL_TESTS();
|
|
}
|