mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-07 19:58:32 +09:00
Android links this module against the SHIPPING libMobileGL.so on purpose, so the on-device run validates the real artifact - and that library is -fvisibility=hidden. Six symbols the scenarios reached for were therefore undefined and the executable could not be linked at all: MG_Config::Features, SetAsyncShaderCompileSuspended, ShaderCompilePool::Get/GetThreadCount/SetMaxConcurrency and AsyncShaderCompileEnabled. All six are gone rather than exported. CompilerThreadScope now restores the pool with glMaxShaderCompilerThreadsKHR (0xFFFFFFFF), which MaxShaderCompilerThreadsKHR_State defines as exactly the two steps it used to perform by hand, and AsyncAndSyncProgramsRenderIdenticalFrames picks its two modes with the same entry point - a zero count compiles inline, a nonzero one lifts that - so the switching is now itself under test. ExtensionStringMatchesTheConfiguration stops deriving its expectation from AsyncShaderCompileEnabled(), the very function the backends gate the extension string on: it was asserting the implementation against itself and would have passed however wrong both halves were. The expectation is now MOBILEGL_ASYNC_SHADER_COMPILE as the process inherited it, and the case skips where that is unset because the built-in default is a value only the implementation knows. Both-mode coverage in one ctest run is preserved by registration rather than by in-process forcing, and is wider than before. New entries, each APPENDING to the common/Vulkan environment so the EGL-vendor and ICD pinning is not lost - a ctest ENVIRONMENT property replaces the job environment rather than adding to it: DirectGLES./DirectVulkan.AsyncOn. run all of AsyncCompileScenario with MOBILEGL_ASYNC_SHADER_COMPILE=1; .AsyncOff. run the extension case with =0, which asserts the withdrawn side that nothing covered before; .OptimisticShaderStatus. run the Iris-shaped case with MOBILEGL_ASYNC_OPTIMISTIC_SHADER_STATUS=1 (its own entries because the quirk is not neutral for the rest of the scenario); DirectGLES.NoViewportArrayEmulation. runs the emulation control with MOBILEGL_FORCE_VIEWPORT_ARRAY_EMULATION=0. Run from a device shell with nothing set, the ambient configuration runs and the rest skip cleanly. 1836 -> 1853 ctest entries, all green.
504 lines
24 KiB
CMake
504 lines
24 KiB
CMake
cmake_minimum_required(VERSION 3.24)
|
|
|
|
# MobileGL headless GPU integration tests.
|
|
#
|
|
# These are not unit tests: each scenario brings up a real EGL context on a
|
|
# pbuffer, renders real frames through a real backend and asserts on
|
|
# glReadPixels output. They need a GPU, so the module is OFF by default
|
|
# (MOBILEGL_BUILD_INTEGRATION_TEST) and every scenario skips cleanly - never
|
|
# fails, never hangs - on a machine without one. "Cleanly" is not a hope: the
|
|
# harness runs the whole bring-up in a forked child first, because MobileGL
|
|
# ABORTS rather than returning an error on an unusable platform (HeadlessGL.cpp).
|
|
#
|
|
# A clean skip is also indistinguishable from a pass, so set
|
|
# MOBILEGL_ITEST_REQUIRE_GPU wherever the machine is supposed to have a GPU.
|
|
#
|
|
# Backend selection is latched at initialization from MOBILEGL_BACKEND_TYPE, so
|
|
# one process is one backend: the same binary is registered twice, once per
|
|
# backend, under the `integration-gpu` label.
|
|
|
|
message(STATUS "Generating build files for MobileGL Integration Test...")
|
|
|
|
set(CMAKE_CXX_STANDARD 23)
|
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
|
|
set(MGL_ITEST_ROOT ${CMAKE_CURRENT_LIST_DIR}/../..)
|
|
|
|
# Desktop links the static implementation directly. Android runs the same
|
|
# executable from adb shell and links the shipping shared library instead.
|
|
if (ANDROID)
|
|
set(MGL_ITEST_MOBILEGL_TARGET MobileGL)
|
|
elseif (TARGET MobileGL_s)
|
|
set(MGL_ITEST_MOBILEGL_TARGET MobileGL_s)
|
|
else()
|
|
message(STATUS "No MobileGL library target is available; skipping the integration test module")
|
|
return()
|
|
endif()
|
|
|
|
# MG_Test already pulls googletest in when MOBILEGL_BUILD_TEST is ON. Stand on
|
|
# our own feet when it is not, so this module can be built by itself.
|
|
if (NOT TARGET GTest::gtest)
|
|
include(FetchContent)
|
|
FetchContent_Declare(
|
|
googletest
|
|
GIT_REPOSITORY https://github.com/google/googletest.git
|
|
GIT_TAG v1.17.0
|
|
)
|
|
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
|
FetchContent_MakeAvailable(googletest)
|
|
endif()
|
|
|
|
add_executable(MobileGLIntegrationTest
|
|
Main.cpp
|
|
Harness/HeadlessGL.cpp
|
|
Scenarios/OrientationScenario.cpp
|
|
Scenarios/CrossFrameBufferScenario.cpp
|
|
Scenarios/ResidentIndexScenario.cpp
|
|
Scenarios/MultiDrawScenario.cpp
|
|
Scenarios/DrawParametersScenario.cpp
|
|
Scenarios/AsyncCompileScenario.cpp
|
|
Scenarios/XfbAfterClipDistanceScenario.cpp
|
|
Scenarios/ThreeChannelAttachmentScenario.cpp
|
|
Scenarios/SnormAttachmentScenario.cpp
|
|
Scenarios/PipelineFailureScenario.cpp
|
|
Scenarios/AdvertisedLimitsScenario.cpp
|
|
Scenarios/PixelStoreSweepScenario.cpp
|
|
Scenarios/FragCoordOriginScenario.cpp
|
|
Scenarios/ClearThenReadPixelsScenario.cpp
|
|
Scenarios/DepthStencilReadbackScenario.cpp
|
|
Scenarios/DepthStencilReadbackMatrixScenario.cpp
|
|
Scenarios/DepthStencilReadbackAttachmentShapeScenario.cpp
|
|
Scenarios/ClipDistanceScenario.cpp
|
|
Scenarios/ViewportArrayScenario.cpp
|
|
Scenarios/SsboArrayLengthScenario.cpp
|
|
Scenarios/DoublePrecisionScenario.cpp
|
|
Scenarios/UniformInitializerScenario.cpp
|
|
Scenarios/SwizzleAccessRoutineScenario.cpp
|
|
Scenarios/IterationRPFirstReductionScenario.cpp
|
|
Scenarios/IterationRPProgram203Scenario.cpp
|
|
Scenarios/IterationRPScratchFixScenario.cpp
|
|
Scenarios/ProgramPipelineScenario.cpp
|
|
Scenarios/ImageLoadStoreSsoScenario.cpp
|
|
Scenarios/ImageTargetKindScenario.cpp
|
|
Scenarios/ImageFormatQualifierScenario.cpp
|
|
Scenarios/NonCoreImageFormatScenario.cpp
|
|
Scenarios/ImageSizeAfterRespecScenario.cpp
|
|
Scenarios/SsboDeclarationFormScenario.cpp
|
|
Scenarios/Glsl420DeclarationScenario.cpp
|
|
Scenarios/IoBlockNameCollisionScenario.cpp
|
|
Scenarios/TessellationDrawModeScenario.cpp
|
|
Scenarios/GeometryDrawModeScenario.cpp
|
|
Scenarios/PostLinkAttachScenario.cpp
|
|
Scenarios/FormatlessImageBakeScenario.cpp
|
|
Scenarios/FragmentOutputArrayIndexScenario.cpp
|
|
Scenarios/BufferTextureScenario.cpp
|
|
Scenarios/VertexAttribBindingScenario.cpp
|
|
Scenarios/XfbCaptureBufferReuseScenario.cpp
|
|
Scenarios/XfbPrimitiveQueryScenario.cpp
|
|
Scenarios/VertexArrayEnableDisableScenario.cpp
|
|
Scenarios/CopyImageLevelRangeScenario.cpp
|
|
Scenarios/CopyImageLayeredScenario.cpp
|
|
Scenarios/TextureViewScenario.cpp
|
|
Scenarios/PackedWordReadbackScenario.cpp
|
|
Scenarios/LayeredAttachmentBarrierScenario.cpp
|
|
Scenarios/LayeredTextureReadbackScenario.cpp
|
|
Scenarios/AtomicCounterScenario.cpp
|
|
Scenarios/SsboArrayDynamicIndexScenario.cpp
|
|
Scenarios/StorageBufferRegrowScenario.cpp
|
|
Scenarios/RelinkStageSetScenario.cpp
|
|
Scenarios/GuiBatchScenario.cpp
|
|
Scenarios/UnboundImageDescriptorScenario.cpp
|
|
)
|
|
|
|
target_include_directories(MobileGLIntegrationTest PRIVATE
|
|
${MGL_ITEST_ROOT}/include
|
|
${MGL_ITEST_ROOT}/MobileGL
|
|
)
|
|
|
|
# gtest, not gtest_main: Main.cpp installs the harness banner itself.
|
|
target_link_libraries(MobileGLIntegrationTest PRIVATE
|
|
GTest::gtest
|
|
${MGL_ITEST_MOBILEGL_TARGET}
|
|
)
|
|
|
|
if (ANDROID)
|
|
find_library(MGL_ITEST_ANDROID_LIBRARY android REQUIRED)
|
|
find_library(MGL_ITEST_LOG_LIBRARY log REQUIRED)
|
|
find_library(MGL_ITEST_MEDIANDK_LIBRARY mediandk REQUIRED)
|
|
target_link_libraries(MobileGLIntegrationTest PRIVATE
|
|
${MGL_ITEST_ANDROID_LIBRARY}
|
|
${MGL_ITEST_LOG_LIBRARY}
|
|
${MGL_ITEST_MEDIANDK_LIBRARY}
|
|
)
|
|
endif()
|
|
|
|
if (MSVC)
|
|
# Same reason as MG_Test/Backend/DirectVulkan: the GLES headers declare gl*
|
|
# as dllimport on Windows, so the in-library GL entry-point definitions only
|
|
# resolve if the whole static library is part of the link.
|
|
target_link_options(MobileGLIntegrationTest PRIVATE /WHOLEARCHIVE:MobileGL_s)
|
|
endif()
|
|
target_compile_definitions(MobileGLIntegrationTest PRIVATE -DNOMINMAX)
|
|
|
|
if (ANDROID)
|
|
return()
|
|
endif()
|
|
|
|
# --- ctest wiring --------------------------------------------------------
|
|
# A bare libEGL on a glvnd box resolves to whatever vendor comes first, which is
|
|
# usually Mesa/llvmpipe - a software rasteriser silently replacing the GPU under
|
|
# a GPU test. Pin the vendor/ICD json the same way MG_Benchmark's
|
|
# run_driver_bench.sh does.
|
|
#
|
|
# Leaving these empty is not a neutral default, it is the failure mode: an
|
|
# unpinned libEGL lands on llvmpipe and the suite goes green having tested a
|
|
# software rasteriser. So they are DETECTED here rather than defaulted to empty,
|
|
# and an empty result is a loud warning.
|
|
#
|
|
# mgl_itest_find_driver_json(<outVar> <description> <glob> [<glob>...])
|
|
# Picks the first json a real hardware vendor owns, in preference order, and
|
|
# never picks a software rasteriser (llvmpipe / lavapipe / swrast) - landing on
|
|
# one of those silently is the exact accident this pinning exists to prevent.
|
|
function(mgl_itest_find_driver_json outVar)
|
|
set(candidates "")
|
|
foreach(pattern IN LISTS ARGN)
|
|
file(GLOB matches "${pattern}")
|
|
list(APPEND candidates ${matches})
|
|
endforeach()
|
|
list(SORT candidates)
|
|
# Vendors ship an i686 json beside the x86_64 one and it sorts first. Pinning
|
|
# the wrong word size is worse than not pinning at all - the loader finds no
|
|
# driver and the whole suite skips - so drop the mismatched ones outright.
|
|
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
|
list(FILTER candidates EXCLUDE REGEX "i686|i386")
|
|
else()
|
|
list(FILTER candidates EXCLUDE REGEX "x86_64|aarch64")
|
|
endif()
|
|
set(software "")
|
|
foreach(vendor IN ITEMS nvidia amdgpu amd radeon intel_hasvk intel broadcom freedreno panfrost)
|
|
foreach(candidate IN LISTS candidates)
|
|
get_filename_component(leaf "${candidate}" NAME)
|
|
string(TOLOWER "${leaf}" leaf)
|
|
if (leaf MATCHES "${vendor}")
|
|
set(${outVar} "${candidate}" PARENT_SCOPE)
|
|
return()
|
|
endif()
|
|
endforeach()
|
|
endforeach()
|
|
# Nothing recognised as hardware. Report the first non-software entry if there
|
|
# is one; otherwise report nothing, so the warning below fires.
|
|
foreach(candidate IN LISTS candidates)
|
|
get_filename_component(leaf "${candidate}" NAME)
|
|
string(TOLOWER "${leaf}" leaf)
|
|
if (NOT leaf MATCHES "lvp|llvmpipe|lavapipe|swrast|softpipe")
|
|
set(${outVar} "${candidate}" PARENT_SCOPE)
|
|
return()
|
|
endif()
|
|
set(software "${candidate}")
|
|
endforeach()
|
|
set(${outVar} "" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
set(MGL_ITEST_DETECTED_EGL_VENDOR "")
|
|
set(MGL_ITEST_DETECTED_VK_ICD "")
|
|
if (UNIX AND NOT APPLE AND NOT ANDROID)
|
|
mgl_itest_find_driver_json(MGL_ITEST_DETECTED_EGL_VENDOR
|
|
"/usr/share/glvnd/egl_vendor.d/*.json"
|
|
"/etc/glvnd/egl_vendor.d/*.json")
|
|
mgl_itest_find_driver_json(MGL_ITEST_DETECTED_VK_ICD
|
|
"/usr/share/vulkan/icd.d/*.json"
|
|
"/etc/vulkan/icd.d/*.json")
|
|
endif()
|
|
|
|
set(MOBILEGL_ITEST_EGL_VENDOR "${MGL_ITEST_DETECTED_EGL_VENDOR}" CACHE FILEPATH
|
|
"glvnd EGL vendor json to pin for the integration tests (empty: leave the loader alone)")
|
|
set(MOBILEGL_ITEST_VK_ICD "${MGL_ITEST_DETECTED_VK_ICD}" CACHE FILEPATH
|
|
"Vulkan ICD json to pin for the DirectVulkan integration tests (empty: leave the loader alone)")
|
|
|
|
if (MOBILEGL_ITEST_EGL_VENDOR)
|
|
message(STATUS "Integration tests: pinning EGL vendor ${MOBILEGL_ITEST_EGL_VENDOR}")
|
|
else()
|
|
message(WARNING
|
|
"Integration tests: no EGL vendor json found or configured (MOBILEGL_ITEST_EGL_VENDOR is empty). "
|
|
"An unpinned libEGL on a glvnd system resolves to whichever vendor comes first, which is usually "
|
|
"Mesa/llvmpipe - the scenarios would then go green against a software rasteriser instead of the GPU. "
|
|
"Set -DMOBILEGL_ITEST_EGL_VENDOR=/usr/share/glvnd/egl_vendor.d/<vendor>.json.")
|
|
endif()
|
|
if (MOBILEGL_ITEST_VK_ICD)
|
|
message(STATUS "Integration tests: pinning Vulkan ICD ${MOBILEGL_ITEST_VK_ICD}")
|
|
else()
|
|
message(WARNING
|
|
"Integration tests: no Vulkan ICD json found or configured (MOBILEGL_ITEST_VK_ICD is empty). "
|
|
"DirectVulkan would then load whichever ICD the loader enumerates first, quite possibly lavapipe. "
|
|
"Set -DMOBILEGL_ITEST_VK_ICD=/usr/share/vulkan/icd.d/<vendor>.json.")
|
|
endif()
|
|
|
|
# Turns "no usable GPU" from a clean skip into a failure - see ScenarioFixture.h.
|
|
# Without it the integration-gpu label is unfalsifiable: a run that skipped every
|
|
# scenario and a run that passed every scenario are the same green in ctest.
|
|
option(MOBILEGL_ITEST_REQUIRE_GPU
|
|
"Fail (rather than skip) the integration scenarios when the headless harness is unusable" OFF)
|
|
|
|
# No EGL_PLATFORM knob here on purpose. The harness pins EGL_PLATFORM=surfaceless
|
|
# itself before its first EGL call (HeadlessGL.cpp, EnsureHeadlessPlatform) so a
|
|
# developer's machine and a CI runner take the SAME path whether or not a window
|
|
# system happens to be running. This used to inject "x11", which is how the lane
|
|
# came up green on a workstation with WSLg and died on a runner with no X server.
|
|
#
|
|
# A build-system knob would not just be redundant, it would be a trap: `set(...
|
|
# CACHE ...)` does not rewrite an existing cache, so every build directory
|
|
# configured before this change would keep injecting EGL_PLATFORM=x11 and go on
|
|
# binding to a window system - silently, and only on the machines that have one.
|
|
# Someone reproducing a platform-specific bug sets EGL_PLATFORM in their own
|
|
# environment, which the harness still honours.
|
|
|
|
set(MGL_ITEST_COMMON_ENV "")
|
|
if (MOBILEGL_ITEST_EGL_VENDOR)
|
|
list(APPEND MGL_ITEST_COMMON_ENV "__EGL_VENDOR_LIBRARY_FILENAMES=${MOBILEGL_ITEST_EGL_VENDOR}")
|
|
endif()
|
|
unset(MOBILEGL_ITEST_EGL_PLATFORM CACHE) # see above: an old cache must not resurrect x11
|
|
if (MOBILEGL_ITEST_REQUIRE_GPU)
|
|
list(APPEND MGL_ITEST_COMMON_ENV "MOBILEGL_ITEST_REQUIRE_GPU=1")
|
|
endif()
|
|
|
|
set(MGL_ITEST_VULKAN_ENV ${MGL_ITEST_COMMON_ENV})
|
|
if (MOBILEGL_ITEST_VK_ICD)
|
|
list(APPEND MGL_ITEST_VULKAN_ENV "VK_ICD_FILENAMES=${MOBILEGL_ITEST_VK_ICD}")
|
|
# The three iterationRP repairs are tri-state quirks that default to device
|
|
# auto-detection, and lavapipe is not on any auto list - so on lavapipe the
|
|
# iterationRP scenarios run unrepaired and Program 203 misses its golden
|
|
# output. CI's integration-gpu job exports these three by hand; pinning them
|
|
# to the ICD instead means a local `ctest -L integration-gpu` measures the
|
|
# same thing the gate does, with no environment to remember.
|
|
if (MOBILEGL_ITEST_VK_ICD MATCHES "lvp_icd|lavapipe")
|
|
message(STATUS "Integration tests: lavapipe ICD - forcing the iterationRP repairs on")
|
|
list(APPEND MGL_ITEST_VULKAN_ENV
|
|
"MOBILEGL_FIX_ITERATIONRP_SUBGROUP_SCRATCH=1"
|
|
"MOBILEGL_DERIVE_NUM_SUBGROUPS=1"
|
|
"MOBILEGL_ITERATIONRP_FIX_BARRIER=1")
|
|
endif()
|
|
endif()
|
|
|
|
# The ENVIRONMENT test property is itself a `;`-list, and gtest_discover_tests
|
|
# forwards PROPERTIES as a flat list - so a plain `;`-joined value arrives as
|
|
# four separate arguments and everything after the first is silently read as
|
|
# another property name. Escaping the separators keeps the whole thing one list
|
|
# element until set_tests_properties expands it back. Without this only
|
|
# MOBILEGL_BACKEND_TYPE reaches the test and the vendor/ICD pinning is lost.
|
|
function(mgl_itest_join_environment outVar)
|
|
set(joined "")
|
|
foreach(entry IN LISTS ARGN)
|
|
if (joined)
|
|
string(APPEND joined "\\;${entry}")
|
|
else()
|
|
set(joined "${entry}")
|
|
endif()
|
|
endforeach()
|
|
set(${outVar} "${joined}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
mgl_itest_join_environment(MGL_ITEST_GLES_ENVIRONMENT
|
|
"MOBILEGL_BACKEND_TYPE=DirectGLES" ${MGL_ITEST_COMMON_ENV})
|
|
mgl_itest_join_environment(MGL_ITEST_VULKAN_ENVIRONMENT
|
|
"MOBILEGL_BACKEND_TYPE=DirectVulkan" ${MGL_ITEST_VULKAN_ENV})
|
|
mgl_itest_join_environment(MGL_ITEST_VULKAN_ASYNC_ENVIRONMENT
|
|
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_ASYNC_SHADER_COMPILE=1" ${MGL_ITEST_VULKAN_ENV})
|
|
mgl_itest_join_environment(MGL_ITEST_GLES_FORCED_DS_ENVIRONMENT
|
|
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_ESPRYT_FORCE_DS_READBACK_EMULATION=1" ${MGL_ITEST_COMMON_ENV})
|
|
|
|
# The shader-compiler configurations AsyncCompileScenario needs, and the one
|
|
# ViewportArrayScenario's negative control needs.
|
|
#
|
|
# These used to be poked into MG_Config::Features from inside the test bodies. They
|
|
# cannot be any more - on Android this module links the SHIPPING libMobileGL.so, which
|
|
# exports nothing internal - and they should not have been anyway: half of what each of
|
|
# them decides is latched before the first GL call (the compile pool and its threads;
|
|
# the advertised extension list, which a backend builds once from the configuration in
|
|
# force at its first use), so an in-process write could only ever have moved the other
|
|
# half. Every one of them is a whole-process property, and a whole-process property is
|
|
# spelled with an environment variable and a ctest entry of its own.
|
|
#
|
|
# Note the shape of every list here: it APPENDS to MGL_ITEST_COMMON_ENV /
|
|
# MGL_ITEST_VULKAN_ENV rather than standing alone. A ctest ENVIRONMENT property REPLACES
|
|
# the job environment rather than adding to it, so an entry that lists only its mode
|
|
# variable would silently lose the EGL vendor and Vulkan ICD pinning and run against
|
|
# whatever the loader found first.
|
|
mgl_itest_join_environment(MGL_ITEST_GLES_ASYNC_ON_ENVIRONMENT
|
|
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_ASYNC_SHADER_COMPILE=1" ${MGL_ITEST_COMMON_ENV})
|
|
mgl_itest_join_environment(MGL_ITEST_GLES_ASYNC_OFF_ENVIRONMENT
|
|
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_ASYNC_SHADER_COMPILE=0" ${MGL_ITEST_COMMON_ENV})
|
|
mgl_itest_join_environment(MGL_ITEST_VULKAN_ASYNC_ON_ENVIRONMENT
|
|
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_ASYNC_SHADER_COMPILE=1" ${MGL_ITEST_VULKAN_ENV})
|
|
mgl_itest_join_environment(MGL_ITEST_VULKAN_ASYNC_OFF_ENVIRONMENT
|
|
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_ASYNC_SHADER_COMPILE=0" ${MGL_ITEST_VULKAN_ENV})
|
|
mgl_itest_join_environment(MGL_ITEST_GLES_OPTIMISTIC_ENVIRONMENT
|
|
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_ASYNC_SHADER_COMPILE=1"
|
|
"MOBILEGL_ASYNC_OPTIMISTIC_SHADER_STATUS=1" ${MGL_ITEST_COMMON_ENV})
|
|
mgl_itest_join_environment(MGL_ITEST_VULKAN_OPTIMISTIC_ENVIRONMENT
|
|
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_ASYNC_SHADER_COMPILE=1"
|
|
"MOBILEGL_ASYNC_OPTIMISTIC_SHADER_STATUS=1" ${MGL_ITEST_VULKAN_ENV})
|
|
mgl_itest_join_environment(MGL_ITEST_GLES_NO_VIEWPORT_EMULATION_ENVIRONMENT
|
|
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_FORCE_VIEWPORT_ARRAY_EMULATION=0" ${MGL_ITEST_COMMON_ENV})
|
|
|
|
# TIMEOUT on every entry: a GPU test that wedges must fail the run, not hang it.
|
|
set(MGL_ITEST_TIMEOUT 120)
|
|
|
|
include(GoogleTest)
|
|
|
|
# Discovery runs `--gtest_list_tests`, which does not construct the harness and
|
|
# so needs no GPU. One registration per backend; TEST_PREFIX keeps the two sets
|
|
# of ctest names apart.
|
|
gtest_discover_tests(MobileGLIntegrationTest
|
|
TEST_PREFIX "DirectGLES."
|
|
DISCOVERY_TIMEOUT 30
|
|
PROPERTIES
|
|
LABELS integration-gpu
|
|
TIMEOUT ${MGL_ITEST_TIMEOUT}
|
|
ENVIRONMENT "${MGL_ITEST_GLES_ENVIRONMENT}"
|
|
)
|
|
|
|
gtest_discover_tests(MobileGLIntegrationTest
|
|
TEST_PREFIX "DirectVulkan."
|
|
DISCOVERY_TIMEOUT 30
|
|
PROPERTIES
|
|
LABELS integration-gpu
|
|
TIMEOUT ${MGL_ITEST_TIMEOUT}
|
|
ENVIRONMENT "${MGL_ITEST_VULKAN_ENVIRONMENT}"
|
|
)
|
|
|
|
# A third registration, of ONE scenario, with asynchronous shader compilation
|
|
# pinned on. Not a second code path in the renderer: a second ALLOCATION pattern.
|
|
# The async pipeline's job objects change which of the freed blocks the capture
|
|
# phase is handed, and that is what decides whether the destroyed-VAO address is
|
|
# reached at all - on the ablated (pre-fix) tree async=1 reproduced 3 runs out of
|
|
# 3 where the ambient default reproduced 2 of 3. Pinning it here means the
|
|
# high-signal configuration runs whatever the shipped default becomes, instead of
|
|
# the suite quietly weakening the day that default flips. It must be process-wide
|
|
# (the ENVIRONMENT property), not an in-process scope: the compile pool and its
|
|
# threads are stood up at initialization, and their allocations are half the
|
|
# point. DirectVulkan only - the memo this pins is DirectVulkan's.
|
|
gtest_discover_tests(MobileGLIntegrationTest
|
|
TEST_PREFIX "DirectVulkan.AsyncCompile."
|
|
TEST_FILTER "XfbAfterClipDistanceScenario.*"
|
|
DISCOVERY_TIMEOUT 30
|
|
PROPERTIES
|
|
LABELS integration-gpu
|
|
TIMEOUT ${MGL_ITEST_TIMEOUT}
|
|
ENVIRONMENT "${MGL_ITEST_VULKAN_ASYNC_ENVIRONMENT}"
|
|
)
|
|
|
|
# A fourth registration, of the depth/stencil readback scenarios, with the ES
|
|
# shader-sampling emulation forced on. Not paranoia - without it these scenarios are
|
|
# UNFALSIFIABLE on the machines this suite runs on: OpenGL ES has no depth or stencil
|
|
# readback in core, but Mesa accepts the reads anyway, so on llvmpipe every one of them
|
|
# goes green through a native path that the Adreno device does not have. Deleting the
|
|
# entire emulation left all of them passing. With the flag the native spellings are off
|
|
# the table and only the path the device actually takes remains. DirectGLES only - the
|
|
# emulation is DirectGLES's.
|
|
gtest_discover_tests(MobileGLIntegrationTest
|
|
TEST_PREFIX "DirectGLES.ForcedDepthStencilEmulation."
|
|
TEST_FILTER "DepthStencilReadback*Scenario.*"
|
|
DISCOVERY_TIMEOUT 30
|
|
PROPERTIES
|
|
LABELS integration-gpu
|
|
TIMEOUT ${MGL_ITEST_TIMEOUT}
|
|
ENVIRONMENT "${MGL_ITEST_GLES_FORCED_DS_ENVIRONMENT}"
|
|
)
|
|
|
|
# AsyncCompileScenario, with asynchronous compilation PINNED ON per backend.
|
|
#
|
|
# Not a duplicate of what the two ambient registrations already run: they run whatever
|
|
# MobileGL's built-in default happens to be, and the day that default flips they would
|
|
# stop covering the asynchronous path without anything going red. These entries are the
|
|
# ones that keep the asynchronous half tested no matter what ships. They are also the
|
|
# only place ExtensionStringMatchesTheConfiguration can assert that the extension IS
|
|
# advertised - the case derives its expectation from this variable and nothing else, and
|
|
# skips where it is unset, precisely so that it is not asserting the implementation
|
|
# against itself.
|
|
gtest_discover_tests(MobileGLIntegrationTest
|
|
TEST_PREFIX "DirectGLES.AsyncOn."
|
|
TEST_FILTER "AsyncCompileScenario.*"
|
|
DISCOVERY_TIMEOUT 30
|
|
PROPERTIES
|
|
LABELS integration-gpu
|
|
TIMEOUT ${MGL_ITEST_TIMEOUT}
|
|
ENVIRONMENT "${MGL_ITEST_GLES_ASYNC_ON_ENVIRONMENT}"
|
|
)
|
|
gtest_discover_tests(MobileGLIntegrationTest
|
|
TEST_PREFIX "DirectVulkan.AsyncOn."
|
|
TEST_FILTER "AsyncCompileScenario.*"
|
|
DISCOVERY_TIMEOUT 30
|
|
PROPERTIES
|
|
LABELS integration-gpu
|
|
TIMEOUT ${MGL_ITEST_TIMEOUT}
|
|
ENVIRONMENT "${MGL_ITEST_VULKAN_ASYNC_ON_ENVIRONMENT}"
|
|
)
|
|
|
|
# The other side of the same switch: asynchronous compilation OFF, so
|
|
# GL_KHR_parallel_shader_compile must be WITHDRAWN from both spellings of the extension
|
|
# list and GL_MAX_SHADER_COMPILER_THREADS_KHR must read 0. Only that one case is
|
|
# registered here because it is the only one that has anything to say in this
|
|
# configuration - the other four exist to observe worker-built artifacts, and there are
|
|
# none - so registering the whole scenario would buy four guaranteed skips per backend.
|
|
# Together with the AsyncOn. entries above, one ctest run still covers both flag states,
|
|
# which is what the in-process forcing used to be for.
|
|
gtest_discover_tests(MobileGLIntegrationTest
|
|
TEST_PREFIX "DirectGLES.AsyncOff."
|
|
TEST_FILTER "AsyncCompileScenario.ExtensionStringMatchesTheConfiguration"
|
|
DISCOVERY_TIMEOUT 30
|
|
PROPERTIES
|
|
LABELS integration-gpu
|
|
TIMEOUT ${MGL_ITEST_TIMEOUT}
|
|
ENVIRONMENT "${MGL_ITEST_GLES_ASYNC_OFF_ENVIRONMENT}"
|
|
)
|
|
gtest_discover_tests(MobileGLIntegrationTest
|
|
TEST_PREFIX "DirectVulkan.AsyncOff."
|
|
TEST_FILTER "AsyncCompileScenario.ExtensionStringMatchesTheConfiguration"
|
|
DISCOVERY_TIMEOUT 30
|
|
PROPERTIES
|
|
LABELS integration-gpu
|
|
TIMEOUT ${MGL_ITEST_TIMEOUT}
|
|
ENVIRONMENT "${MGL_ITEST_VULKAN_ASYNC_OFF_ENVIRONMENT}"
|
|
)
|
|
|
|
# The optimistic-status quirk's end-to-end shape. Its own entries and not part of the
|
|
# AsyncOn. ones because the quirk is not neutral for the rest of the scenario: with it in
|
|
# force glGetShaderiv(GL_COMPILE_STATUS) deliberately answers without joining, which is
|
|
# exactly what CompletionStatusPollingThenForcedJoin asserts must NOT happen. Off by
|
|
# default and never advertised, so - unlike asynchronous compilation, which announces
|
|
# itself through the extension string - the variable is the only thing that can tell the
|
|
# case it is in force.
|
|
gtest_discover_tests(MobileGLIntegrationTest
|
|
TEST_PREFIX "DirectGLES.OptimisticShaderStatus."
|
|
TEST_FILTER "AsyncCompileScenario.IrisShapedTwoPhaseBatchRendersCorrectly"
|
|
DISCOVERY_TIMEOUT 30
|
|
PROPERTIES
|
|
LABELS integration-gpu
|
|
TIMEOUT ${MGL_ITEST_TIMEOUT}
|
|
ENVIRONMENT "${MGL_ITEST_GLES_OPTIMISTIC_ENVIRONMENT}"
|
|
)
|
|
gtest_discover_tests(MobileGLIntegrationTest
|
|
TEST_PREFIX "DirectVulkan.OptimisticShaderStatus."
|
|
TEST_FILTER "AsyncCompileScenario.IrisShapedTwoPhaseBatchRendersCorrectly"
|
|
DISCOVERY_TIMEOUT 30
|
|
PROPERTIES
|
|
LABELS integration-gpu
|
|
TIMEOUT ${MGL_ITEST_TIMEOUT}
|
|
ENVIRONMENT "${MGL_ITEST_VULKAN_OPTIMISTIC_ENVIRONMENT}"
|
|
)
|
|
|
|
# The negative control for the DirectGLES gl_ViewportIndex emulation, in a process that
|
|
# has it switched off. One case, because it is the only one the switch may touch: with
|
|
# the emulation off the three positive cases in the same fixture describe behaviour the
|
|
# backend does not have, so a whole-scenario registration would be three guaranteed reds.
|
|
# DirectGLES only - the flag steers nothing on DirectVulkan, which routes natively.
|
|
gtest_discover_tests(MobileGLIntegrationTest
|
|
TEST_PREFIX "DirectGLES.NoViewportArrayEmulation."
|
|
TEST_FILTER "ViewportArrayScenario.WithoutTheEmulationEveryIndexCollapsesOntoViewportZero"
|
|
DISCOVERY_TIMEOUT 30
|
|
PROPERTIES
|
|
LABELS integration-gpu
|
|
TIMEOUT ${MGL_ITEST_TIMEOUT}
|
|
ENVIRONMENT "${MGL_ITEST_GLES_NO_VIEWPORT_EMULATION_ENVIRONMENT}"
|
|
)
|