mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-13 14:48:32 +09:00
102 lines
6.4 KiB
C++
102 lines
6.4 KiB
C++
// MobileGL - MobileGL/MG_IntegrationTest/Harness/PipeSlotPeek.h
|
|
// 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
|
|
//
|
|
// The CLIENT slot allocator's occupancy, read from a scenario.
|
|
//
|
|
// It exists for one assertion, P3a's C-1: a frontend object that dies must return its
|
|
// MGPipeHandle slot WHATEVER BACKEND IS RUNNING. That question has no answer in the GL API -
|
|
// the leak it rules out is entirely inside the library, and it is invisible in pixels, in GL
|
|
// names and in `glGetError` - so the only honest observable is the allocator's own live count
|
|
// and high-water mark. Reading them is what makes the case fail on the backend it actually
|
|
// failed on (DirectVulkan, which installs no StateObjectDeathOps) rather than only on the one
|
|
// where a backend-owned free happened to exist.
|
|
//
|
|
// A separate translation unit for BackendCapsPeek.h's reason, verbatim: the scenario sources
|
|
// include the GL headers with prototypes and MobileGL's umbrella header is not meant to meet
|
|
// them in one file.
|
|
|
|
#pragma once
|
|
|
|
namespace MGITest {
|
|
|
|
// Which client-side object kind to ask about. Mirrors MG_Pipe::MGPipeKind for exactly the
|
|
// kinds a scenario has a reason to count, so that the enum does not travel through this
|
|
// header and the GL headers together.
|
|
enum class PipeSlotKind {
|
|
Buffer,
|
|
VertexElementsCso,
|
|
// P4a's six (G8b). Every one of them is a kind the CLIENT mints and the client alone
|
|
// frees (BRIEF-P4A.md D-I1: one death helper per kind, called from the frontend
|
|
// object's own destructor, whatever backend is running), so every one of them can leak
|
|
// the P3a C-1 way - and the leak is invisible in pixels, in GL names and in
|
|
// glGetError, exactly as the VertexElementsCso one was.
|
|
Texture,
|
|
Renderbuffer,
|
|
// Framebuffer has a HANDLE but no wire lifetime (D-I2): no create_*, no destroy row in
|
|
// the catalogue, and its death helper does the notice and the free and emits nothing.
|
|
// That makes the allocator the ONLY observable of its lifetime, so this row matters
|
|
// more here than the others rather than less.
|
|
Framebuffer,
|
|
SamplerCso,
|
|
SamplerViewCso,
|
|
// ShaderCso covers BOTH the ordinary program slots and the program-pipeline COMPOSITES
|
|
// minted out of the reserved high band (MGPipeHandles.h:86-107, D-H7). One kind, because
|
|
// that is what the allocator has: the band is a second dense table inside the same kind
|
|
// and LiveCount counts both.
|
|
//
|
|
// THE TWO SPACES' HIGH-WATER MARKS ARE NOT ONE NUMBER, and the correction matters here
|
|
// more than anywhere else. c0b split them (contract-v2.md 4.3): HighWater(ShaderCso) is
|
|
// now the ORDINARY space only and the band's own mark is CompositeHighWater(), because
|
|
// a merged mark is pinned at ~983k from the first composite mint onward and every "the
|
|
// high-water mark did not move over N churn rounds" assertion about ordinary programs
|
|
// would be vacuously true for the rest of the process. The composite's leak case is a
|
|
// separate CASE and reads the BAND'S OWN counters below (PeekPipeCompositeSlot*) - a
|
|
// composite's slot has TWO independent release paths (the pipeline cache's LRU eviction
|
|
// and the composite ProgramObject's destructor), and a slot that never comes back to
|
|
// the band moves neither of the ordinary numbers.
|
|
ShaderCso,
|
|
};
|
|
|
|
// Live slots of this kind right now, and one past the highest slot ever handed out.
|
|
// Both return false, touching nothing, where the allocator is out of reach: in a PULL
|
|
// build there is no allocator at all (it is `#if MOBILEGL_PIPE_PUSH`), and on Android this
|
|
// module links the shipping libMobileGL.so built -fvisibility=hidden, so no internal symbol
|
|
// resolves. A caller that gets false must SKIP rather than pass - "could not look" is not
|
|
// "did not leak".
|
|
bool PeekPipeSlotLiveCount(PipeSlotKind kind, unsigned* outLive);
|
|
bool PeekPipeSlotHighWater(PipeSlotKind kind, unsigned* outHighWater);
|
|
|
|
// The ShaderCso COMPOSITE BAND's own three numbers, the seventh..ninth members
|
|
// contract-v2.md 4.3 asks this header for. There is no `kind` argument because the band is
|
|
// ShaderCso's alone - AllocateComposite is the one door into it and no other kind has one.
|
|
// All three return false on the same terms as the two above, and a caller that gets false
|
|
// must SKIP.
|
|
//
|
|
// PeekPipeCompositeSlotLiveCount = MGPipeSlotAllocator::CompositeLiveCount(), the band's
|
|
// share of LiveCount(ShaderCso).
|
|
// PeekPipeCompositeSlotHighWater = CompositeHighWater() VERBATIM, i.e. one past the
|
|
// highest band slot ever handed out. It is an ABSOLUTE
|
|
// slot number and therefore starts at the band's base,
|
|
// not at zero - "no composite was ever minted" reads as
|
|
// `high water == band base`, which is what the third
|
|
// member is for. It is not returned base-relative
|
|
// because a peek whose name says HighWater and whose
|
|
// value is a delta is exactly the kind of quietly
|
|
// redefined counter this member exists to correct.
|
|
// PeekPipeCompositeSlotBandBase = kMGPipeShaderCsoCompositeSlotBase, the floor the
|
|
// other two are read against. A constant, but it
|
|
// reaches a scenario only through this header: the
|
|
// MG_Pipe headers and the GL headers are not meant to
|
|
// meet in one translation unit, which is why this
|
|
// harness exists at all.
|
|
bool PeekPipeCompositeSlotLiveCount(unsigned* outLive);
|
|
bool PeekPipeCompositeSlotHighWater(unsigned* outHighWater);
|
|
bool PeekPipeCompositeSlotBandBase(unsigned* outBandBase);
|
|
|
|
} // namespace MGITest
|