diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.cpp b/MobileGL/MG_Backend/DirectGLES/Managers.cpp index 6f77f126..2a30c4a1 100644 --- a/MobileGL/MG_Backend/DirectGLES/Managers.cpp +++ b/MobileGL/MG_Backend/DirectGLES/Managers.cpp @@ -4974,13 +4974,18 @@ namespace MobileGL::MG_Backend::DirectGLES { } void ResolveRecordArmFamilies() { - const Bool allArmed = FramebufferSubsystemEnabled() && TextureResourceSubsystemEnabled() && - SamplerSubsystemEnabled() && ProgramSubsystemEnabled() && - BufferImpl::ResourceSubsystemEnabled() && BufferImpl::VertexInputSubsystemEnabled(); - if (!allArmed) { + // The masks are ConfigLoader's to refuse (any mask clearing bits 0-13 stops at startup), + // so the one question left is the driver's: MGPFramebufferState::Color[8] is the wire's + // width and this is the RAW ES cap, which nothing clamps. The framebuffer family used to + // refuse its bit and fall back to the legacy arm here (D-C3); with one arm, a driver + // reporting more stops by name instead of having the record truncate its attachments. + const Uint32 cap = static_cast(std::max(g_GLESCapabilities.MaxColorAttachments, 0)); + if (cap > MG_Pipe::kMGPipeMaxColorAttachments) { + MGLOG_E("MGPipe: this driver reports GL_MAX_COLOR_ATTACHMENTS = %u, above " + "MGPFramebufferState::Color[%u]'s wire width", cap, MG_Pipe::kMGPipeMaxColorAttachments); BufferImpl::StopOnArmlessPipeSubsystem( - "an Espryt family refused the record arm at bring-up (see the line above), and the " - "record arm is the only arm since P13 W6"); + "kMGPipeSubsystemFramebuffer (bit 9) cannot carry this driver's colour attachments, and " + "the record arm is the only arm since P13 W6"); } } diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.h b/MobileGL/MG_Backend/DirectGLES/Managers.h index 4d9f82d8..3e5482ac 100644 --- a/MobileGL/MG_Backend/DirectGLES/Managers.h +++ b/MobileGL/MG_Backend/DirectGLES/Managers.h @@ -756,10 +756,9 @@ namespace MobileGL::MG_Backend::DirectGLES { Bool ResolveSamplerSubsystemArm(); Bool ResolveProgramSubsystemArm(); // P13 W6: every family runs the record arm - the frontend arms these resolvers used to choose - // between are gone, so no site asks them any more. What they still decide is whether this - // configuration and this driver CAN run it (a mask missing a family's dependency, a - // colour-attachment cap above the wire's width), and that is asked once, at capability - // bring-up, and stops by name when the answer is no. + // between are gone, so no draw-path site asks them any more (the integration peeks still read + // the latches). The one refusal a running process can still meet - a driver whose colour- + // attachment cap exceeds the wire's width - is checked once, at capability bring-up. void ResolveRecordArmFamilies(); inline Bool FramebufferSubsystemEnabled() { diff --git a/MobileGL/MG_Test/Pipe/PipeCatalogueTest.cpp b/MobileGL/MG_Test/Pipe/PipeCatalogueTest.cpp index 9d2e2f26..dad23b9f 100644 --- a/MobileGL/MG_Test/Pipe/PipeCatalogueTest.cpp +++ b/MobileGL/MG_Test/Pipe/PipeCatalogueTest.cpp @@ -1455,23 +1455,15 @@ TEST(PipeCatalogue, EveryUnmigratedEmulationIsNamedOnce) { // `Transport != Monolith` return, so no transport ever reached it and on monolith it was a // no-op; the call and the name went together (notes/p8/SE.md). // - // TWO, NOT THREE (P13 W6): "get-tex-image-shadow" sat in GetTexImageViaShadowConversion, the - // monolith frontend arm's shadow readback; that arm went with the frontend data arm. - const char* const kNames[] = { - "generate-mipmap-storage", // EnsureGenerateMipmapStorageAllocated (monolith grow) - "generate-mipmap-cpu-fallback", // GenerateThreeChannelFloatMipmapOnCpu - }; - EXPECT_EQ(std::size(kNames), 2u); - // No duplicates: two sites sharing a name would make the grepped count and this list - // disagree in the one direction nobody would notice. - for (SizeT i = 0; i < std::size(kNames); ++i) { - for (SizeT j = i + 1; j < std::size(kNames); ++j) { - EXPECT_STRNE(kNames[i], kNames[j]); - } - } - // In monolith it really is a no-op: calling it changes nothing and returns nothing. The - // teeth are a split server's, and the call site is what P8 gives them to. - for (const char* name : kNames) MGPipeUnmigratedEmulation(name); + // NONE (P13 W6). "get-tex-image-shadow" sat in GetTexImageViaShadowConversion, the monolith + // frontend arm's shadow readback, and the two mipmap names in that arm's storage grow and CPU + // filter; all three went with the frontend data arm. The list is EMPTY and the audit + // (scripts/ci/unmigrated_emulation_sites.py) now holds the tree at zero call sites: a new + // emulation that reaches into client memory has to be named here before it can land. The one + // entry below is the array's terminator, not a name - C++ has no empty braced array. + const char* const kNames[] = {nullptr}; + EXPECT_EQ(std::size(kNames), 1u); + EXPECT_EQ(kNames[0], nullptr); } // THE ShaderCso COMPOSITE BAND IS A SECOND SPACE, AND THE ALLOCATOR REPORTS IT SEPARATELY. diff --git a/scripts/ci/fatal_census_baseline.json b/scripts/ci/fatal_census_baseline.json index 4b250baa..a7d06b3a 100644 --- a/scripts/ci/fatal_census_baseline.json +++ b/scripts/ci/fatal_census_baseline.json @@ -1,11 +1,11 @@ { - "abort_sites": 76, + "abort_sites": 73, "abort_sites_by_file": { "MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp": 12, - "MobileGL/MG_Backend/DirectGLES/Managers.cpp": 12, + "MobileGL/MG_Backend/DirectGLES/Managers.cpp": 10, "MobileGL/MG_Backend/DirectGLES/MultiDraw.cpp": 2, "MobileGL/MG_Backend/DirectGLES/Utils.cpp": 1, - "MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp": 2, + "MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp": 1, "MobileGL/MG_Backend/DirectVulkan/Renderer/MagmaPipeArms.h": 1, "MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferManager.cpp": 10, "MobileGL/MG_Backend/Init.cpp": 2,