From b4b2ccfe7b28f8a2bec51ad5289e31cc365584b8 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Sun, 18 Oct 2026 15:55:03 -0400 Subject: [PATCH] [Fix] (MG_Backend/DirectGLES, MG_Test/Backend): advertise 32 fragment texture units - Iris budgets a whole program's samplers against GL_MAX_TEXTURE_IMAGE_UNITS; the ES driver's 16 per stage left iterationT with no pipeline on Espryt - report min(32, max(per-stage, combined)) so unit numbers stay legal - add CapabilityLimitsTest for the Adreno, narrow and wide cases --- .../DirectGLES/BackendObject_DirectGLES.cpp | 9 +++- .../MG_Test/Backend/DirectGLES/CMakeLists.txt | 5 +++ .../DirectGLES/CapabilityLimitsTest.cpp | 43 +++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 MobileGL/MG_Test/Backend/DirectGLES/CapabilityLimitsTest.cpp diff --git a/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp index be3bdfe3..1e5c57e4 100644 --- a/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp @@ -1832,8 +1832,15 @@ namespace MobileGL::MG_Backend::DirectGLES { // GL_MAX_TEXTURE_IMAGE_UNITS must never exceed host-side fixed arrays sized off it (e.g. // Minecraft's 128-entry Blaze3D GlStateManager.TEXTURES[], iterated by Iris), and the combined // limit must stay within our texture-unit state array capacity. + // + // The fragment limit is raised to the desktop value (32) even where the ES driver counts 16 + // per stage: Iris sizes its WHOLE-PROGRAM unit budget off this query (vertex and fragment + // samplers share it, and it refuses the next sampler as soon as the budget is full), so 16 + // leaves shader packs such as iterationT without a pipeline at all. Unit NUMBERS up to the + // driver's combined limit are legal in every stage, and a stage that really samples more + // textures than the driver allows still fails at link with the driver's own log. m_dynamicParameters.MaxTextureImageUnits = - std::min(m_GLESCapabilities.MaxTextureImageUnits, + std::min(std::max(m_GLESCapabilities.MaxTextureImageUnits, m_GLESCapabilities.MaxCombinedTextureImageUnits), static_cast(MG_State::GLState::TextureState::MAX_PER_STAGE_TEXTURE_IMAGE_UNITS)); m_dynamicParameters.MaxVertexTextureImageUnits = std::min(m_GLESCapabilities.MaxVertexTextureImageUnits, diff --git a/MobileGL/MG_Test/Backend/DirectGLES/CMakeLists.txt b/MobileGL/MG_Test/Backend/DirectGLES/CMakeLists.txt index cb66c443..33839a83 100644 --- a/MobileGL/MG_Test/Backend/DirectGLES/CMakeLists.txt +++ b/MobileGL/MG_Test/Backend/DirectGLES/CMakeLists.txt @@ -57,6 +57,11 @@ target_link_libraries( ) include(GoogleTest) +add_executable(CapabilityLimitsTest CapabilityLimitsTest.cpp) +target_include_directories(CapabilityLimitsTest PRIVATE ${MGL_ROOT}/include ${MGL_ROOT}/MobileGL) +target_link_libraries(CapabilityLimitsTest PRIVATE MobileGLTestMain ${LINK_LIBRARIES}) +gtest_discover_tests(CapabilityLimitsTest DISCOVERY_TIMEOUT 30 PROPERTIES LABELS unit) + add_executable(ContextEpochTest ContextEpochTest.cpp) target_include_directories(ContextEpochTest PRIVATE ${MGL_ROOT}/include ${MGL_ROOT}/MobileGL) target_link_libraries(ContextEpochTest PRIVATE MobileGLTestMain ${LINK_LIBRARIES}) diff --git a/MobileGL/MG_Test/Backend/DirectGLES/CapabilityLimitsTest.cpp b/MobileGL/MG_Test/Backend/DirectGLES/CapabilityLimitsTest.cpp new file mode 100644 index 00000000..33b36eef --- /dev/null +++ b/MobileGL/MG_Test/Backend/DirectGLES/CapabilityLimitsTest.cpp @@ -0,0 +1,43 @@ +// MobileGL - MobileGL/MG_Test/Backend/DirectGLES/CapabilityLimitsTest.cpp +// Copyright (c) 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 + +#include +#include +#include + +using namespace MobileGL; + +// Iris budgets every program's samplers (vertex and fragment together) against +// GL_MAX_TEXTURE_IMAGE_UNITS, so an ES driver's 16-per-stage answer leaves shader packs without a +// pipeline. The fragment limit reports the desktop value whenever the driver's combined limit can +// number that many units, and never more than the combined limit or the per-stage cap. +TEST(DirectGLESCapabilityLimits, AdvertisesDesktopFragmentTextureUnitsWhenCombinedLimitAllows) { + constexpr Int kPerStageCap = MG_State::GLState::TextureState::MAX_PER_STAGE_TEXTURE_IMAGE_UNITS; + MG_Backend::DirectGLES::BackendObject_DirectGLES backend; + + MG_External::GLESCapabilities adreno; + adreno.MaxTextureImageUnits = 16; + adreno.MaxVertexTextureImageUnits = 16; + adreno.MaxCombinedTextureImageUnits = 96; + backend.ApplyGLESCapabilitiesForTesting(adreno); + EXPECT_EQ(backend.GetDynamicParameters().MaxTextureImageUnits, kPerStageCap); + EXPECT_EQ(backend.GetDynamicParameters().MaxVertexTextureImageUnits, 16); + EXPECT_EQ(backend.GetDynamicParameters().MaxCombinedTextureImageUnits, 96); + + MG_External::GLESCapabilities narrowCombined; + narrowCombined.MaxTextureImageUnits = 16; + narrowCombined.MaxCombinedTextureImageUnits = 20; + backend.ApplyGLESCapabilitiesForTesting(narrowCombined); + EXPECT_EQ(backend.GetDynamicParameters().MaxTextureImageUnits, 20); + + MG_External::GLESCapabilities wide; + wide.MaxTextureImageUnits = 64; + wide.MaxCombinedTextureImageUnits = 192; + backend.ApplyGLESCapabilitiesForTesting(wide); + EXPECT_EQ(backend.GetDynamicParameters().MaxTextureImageUnits, kPerStageCap); +}