[Refactor] (P13 W3b): strip the push/legacy-memo guards from MG_State, MG_Util and the config

This commit is contained in:
2026-10-06 04:04:43 -04:00
parent 9e14c16d4c
commit 7184a40a47
28 changed files with 0 additions and 278 deletions
-2
View File
@@ -377,7 +377,6 @@ namespace MobileGL::MG_Config {
// the semantic gate that replaces byte identity, and it catches the dangerous
// direction - a dirty bit that fires too RARELY - which no purity gate can see.
Bool PipeVerify = false;
#if MOBILEGL_PIPE_PUSH
// The three knobs of the MOBILEGL_PIPE_VERIFY build (P1 brief D2). Compiled only
// under MOBILEGL_PIPE_PUSH so the pull build's FeaturesTable does not change size.
// MOBILEGL_PIPE_VERIFY_FATAL: the first divergence aborts (default). 0 logs and
@@ -408,7 +407,6 @@ namespace MobileGL::MG_Config {
// measurement and for what the control still leaves standing. Under
// MOBILEGL_PIPE_PUSH only, so it cannot exist in a shipping pull build.
Bool PipeHandleAbaControl = false;
#endif
// MOBILEGL_PIPE_STATS: dump the boundary counters (bytes, calls, roundtrips,
// texture pulls, upload shapes, residual-block bytes, index mirror bytes).
Bool PipeStats = false;
-10
View File
@@ -10,12 +10,10 @@
#include <sys/system_properties.h>
#endif
#include "Config.h"
#if MOBILEGL_PIPE_PUSH
// For kMGPipeSubsystemsMigratedAtP5e, the push build's PipePush default (the P2, P3a and P4a
// constants beside it are the phase-by-phase controls, not the default). Push-only, so the
// pull build's translation unit is unchanged.
#include <MG_Pipe/MGPipe.h>
#endif
#include <cerrno>
#include <cstdio>
@@ -386,27 +384,19 @@ namespace MobileGL::MG_ConfigLoader {
// MGPipe. Nothing here needs adding to an allow-list: InitializeAcceptedEnvVariables
// accepts every MOBILEGL_ / LIBGL_ prefixed variable in the environment, so a name
// that starts with MOBILEGL_ is visible to these queries by construction.
#if MOBILEGL_PIPE_PUSH
// A push build with the knob unset runs every subsystem migrated so far, so the
// shipped path is the one the gates measure; MOBILEGL_PIPE_PUSH=0 in the
// environment is the all-subsystems-pull control that reproduces P1 exactly, and
// kMGPipeSubsystemsMigratedAtP3a (0x1ff) is the phase-by-phase control - P4a's four
// subsystems off, everything P3a landed still on.
features.PipePush = QueryEnvUint64("MOBILEGL_PIPE_PUSH", MG_Pipe::kMGPipeSubsystemsMigratedAtP5e);
#else
// Meaningless in a pull build: there is nothing to push. Config.h documents 0 as
// "pull everything" and that stays literally true.
features.PipePush = QueryEnvUint64("MOBILEGL_PIPE_PUSH", 0);
#endif
features.PipeVerify = QueryEnvFlag("MOBILEGL_PIPE_VERIFY");
#if MOBILEGL_PIPE_PUSH
// Defaults ON: read as a tri-state so only an explicitly falsy value turns it off.
features.PipeVerifyFatal =
QueryEnvQuirkOverride("MOBILEGL_PIPE_VERIFY_FATAL") != MG_Config::QuirkOverride::ForceOff;
QueryEnvVariable("MOBILEGL_PIPE_VERIFY_CORRUPT", features.PipeVerifyCorrupt, "");
QueryEnvVariable("MOBILEGL_PIPE_POISON_OMIT", features.PipePoisonOmit, "");
features.PipeHandleAbaControl = QueryEnvFlag("MOBILEGL_PIPE_HANDLE_ABA_CONTROL");
#endif
features.PipeStats = QueryEnvFlag("MOBILEGL_PIPE_STATS");
// Defaults ON, so the flag has to be read as a tri-state rather than as a plain
// truthy check: unset must keep the memos, and only an explicitly falsy value may
@@ -82,7 +82,6 @@ namespace MobileGL::MG_State::GLState {
BufferObject::BufferObject(Uint externalIndex)
: m_externalIndex(externalIndex), m_size(0), m_usage(BufferUsage::StaticDraw), m_isMapped(false),
m_mappingAccess(BufferMappingAccessBit::Null), m_mappedRange({0, 0}), m_ownsStagingData{} {
#if MOBILEGL_PIPE_PUSH
// P3a D-A2: a resource EXISTS before anything can name it, so resource_create is
// emitted from the constructor and carries no storage - the store is defined lazily
// by the first respecify and every backend already tolerates a resource with none.
@@ -90,7 +89,6 @@ namespace MobileGL::MG_State::GLState {
// set_vertex_buffers names this buffer by handle out of a different subsystem.
MG_Pipe::MGPipeMintResourceHandle(*this);
if (MG_Pipe::MGPipeResourceSubsystemEnabled()) MG_Pipe::MGPipeEmitResourceCreate(*this);
#endif
}
BufferObject::~BufferObject() {
@@ -101,7 +99,6 @@ namespace MobileGL::MG_State::GLState {
// for a buffer that was never a member.
MG_Remote::Client::PersistentMapTracker::Instance().Forget(*this);
#endif
#if MOBILEGL_PIPE_PUSH
// P3a D-L: the buffer's death crosses as resource_destroy, which is the catalogue
// call for it - no seventh NotifyStateObjectDestroyed raiser is added, because that
// header exists for kinds that have no such call. The emit-then-free ORDER is fixed
@@ -112,7 +109,6 @@ namespace MobileGL::MG_State::GLState {
// a pipe record to drop and no legacy backend object, and one constructed the other
// way round has the opposite, so the create's answer is the only one that pairs.
if (MG_Pipe::MGPipeEmitResourceDestroyAndFree(*this)) return;
#endif
if (m_resource.Backend() && g_bufferBackendOps && g_bufferBackendOps->OnDestroy) {
g_bufferBackendOps->OnDestroy(m_resource.ReleaseBackend());
}
@@ -121,12 +117,10 @@ namespace MobileGL::MG_State::GLState {
void BufferObject::NotifyRespecify() {
++m_changeSerial;
MGP_NOTE_AGGREGATE(BufferChange);
#if MOBILEGL_PIPE_PUSH
if (MG_Pipe::MGPipeResourceSubsystemEnabled()) {
MG_Pipe::MGPipeEmitResourceRespecify(*this);
return;
}
#endif
if (g_bufferBackendOps && g_bufferBackendOps->Respecify) {
g_bufferBackendOps->Respecify(*this);
}
@@ -137,12 +131,10 @@ namespace MobileGL::MG_State::GLState {
MGP_NOTE_AGGREGATE(BufferChange);
if (size == 0) return;
m_hasDefinedContent = true;
#if MOBILEGL_PIPE_PUSH
if (MG_Pipe::MGPipeResourceSubsystemEnabled()) {
MG_Pipe::MGPipeEmitResourceSubData(*this, offset, size);
return;
}
#endif
if (g_bufferBackendOps && g_bufferBackendOps->SubData) {
g_bufferBackendOps->SubData(*this, offset, size);
}
@@ -153,7 +145,6 @@ namespace MobileGL::MG_State::GLState {
MGP_NOTE_AGGREGATE(BufferChange);
if (range.start >= range.end) return;
m_hasDefinedContent = true;
#if MOBILEGL_PIPE_PUSH
if (MG_Pipe::MGPipeResourceSubsystemEnabled()) {
static_assert(sizeof(appAccess.GetRaw()) <= sizeof(Uint32),
"MGPFlushRange::AccessFlags is a Uint32 and carries the application's "
@@ -162,7 +153,6 @@ namespace MobileGL::MG_State::GLState {
static_cast<Uint32>(appAccess.GetRaw()));
return;
}
#endif
if (g_bufferBackendOps && g_bufferBackendOps->FlushMappedRange) {
g_bufferBackendOps->FlushMappedRange(*this, range, appAccess);
}
@@ -293,12 +283,10 @@ namespace MobileGL::MG_State::GLState {
if (m_size < kLargeBufferAdoptBytes) return;
if (m_resource.IsGpuResident()) return;
if (m_isMapped) return;
#if MOBILEGL_PIPE_PUSH
if (MG_Pipe::MGPipeResourceSubsystemEnabled()) {
if (void* base = MG_Pipe::MGPipeEmitMapPersistent(*this)) m_resource.AdoptPersistentMap(base);
return;
}
#endif
#if MOBILEGL_BUILD_DISAGGREGATED
// R-6 IS "ALWAYS", AND THIS IS ITS SECOND DOOR. MGPipeApplyMapPersistent declines
// every acquisition under split - but a split build whose backend registered no
@@ -588,7 +576,6 @@ namespace MobileGL::MG_State::GLState {
// phase only gives the client a conservative set, and a zero-range announcement stays
// illegal until P8/P9 make it mean "fully narrowed - nothing is dirty".
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
#if MOBILEGL_PIPE_PUSH
if (m_size != 0 && MG_Pipe::MGPipeResourceSubsystemEnabled() && m_resource.IsGpuResident()) {
// P11 B2: A T0 STORE IS READ WHERE IT IS. Under split a store is resident only
// when T0 adopted it - its pages ARE the client's AHardwareBuffer - so no bytes
@@ -631,7 +618,6 @@ namespace MobileGL::MG_State::GLState {
// emission was synchronous and the writeback has already cleared the flag.
MG_Remote::Client::AwaitBufferWriteback(*this);
}
#endif
// A buffer with no readback route - no size, or a backend that registered no
// resource ops - can never catch up, and retrying on every subsequent read would
// only repeat the same no-op. That is the ONE case the monolith clear covers that
@@ -645,7 +631,6 @@ namespace MobileGL::MG_State::GLState {
// Cleared unconditionally: without a readback op the shadow can never catch up,
// and retrying on every subsequent read would only repeat the same no-op.
m_gpuWritePending = false;
#if MOBILEGL_PIPE_PUSH
if (m_size != 0 && MG_Pipe::MGPipeResourceSubsystemEnabled()) {
// The answer comes back through the reverse channel's OnBufferWriteback, which
// resolves this handle to this object and writes the shadow before the server
@@ -655,7 +640,6 @@ namespace MobileGL::MG_State::GLState {
MG_Pipe::MGPipeEmitResourceReadback(*this);
return;
}
#endif
if (m_size == 0 || g_bufferBackendOps == nullptr || g_bufferBackendOps->ReadbackFromGpu == nullptr) {
return;
}
@@ -704,7 +688,6 @@ namespace MobileGL::MG_State::GLState {
// NotifyContentWrite on a resident store only bumps the serial: the backend has no
// separate copy to sync, so no transfer op runs.
void BufferObject::LandBytesIntoResidentStore(SizeT offset, DataPtr bytes) {
#if MOBILEGL_PIPE_PUSH
// buffer_subdata_resident stays NULLABLE and stays asymmetric: one backend
// deliberately does not implement it, and the frontend checks the pipe table exactly
// as it checks the op table it replaces, so a backend without it keeps the legacy
@@ -727,7 +710,6 @@ namespace MobileGL::MG_State::GLState {
NotifyContentWrite(offset, bytes.size);
return;
}
#endif
if (bytes.size > 0 && g_bufferBackendOps && g_bufferBackendOps->ResidentSubData) {
g_bufferBackendOps->ResidentSubData(*this, offset, bytes);
m_hasDefinedContent = true;
@@ -762,14 +744,10 @@ namespace MobileGL::MG_State::GLState {
// fills in place anyway, so a whole-arena clear would allocate a whole arena
// for nothing.
if (m_resource.IsGpuResident() &&
#if MOBILEGL_PIPE_PUSH
// The same question, asked of whichever table owns the family in this build.
(MG_Pipe::MGPipeResourceSubsystemEnabled()
? MG_Pipe::MGPipeResourceOpsHaveSubDataResident()
: (g_bufferBackendOps && g_bufferBackendOps->ResidentSubData))
#else
g_bufferBackendOps && g_bufferBackendOps->ResidentSubData
#endif
) {
Vector<Uint8> expanded(size);
if (pattern.size == 1) {
@@ -878,14 +856,12 @@ namespace MobileGL::MG_State::GLState {
if (m_isMapped) {
return false;
}
#if MOBILEGL_PIPE_PUSH
if (m_size != 0 && MG_Pipe::MGPipeResourceSubsystemEnabled()) {
void* pushedBase = MG_Pipe::MGPipeEmitMapPersistent(*this);
if (pushedBase == nullptr) return false;
m_resource.AdoptPersistentMap(pushedBase);
return true;
}
#endif
#if MOBILEGL_BUILD_DISAGGREGATED
// R-6's second door, as in TryAdoptLargeStorage above.
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) return false;
@@ -943,7 +919,6 @@ namespace MobileGL::MG_State::GLState {
// returning; AdoptPersistentMap then releases the shadow. Falls back to the
// shadow when the backend declines (returns null). Only attempted once - the
// storage is immutable and outlives unmap/remap.
#if MOBILEGL_PIPE_PUSH
if (!m_resource.IsGpuResident() && (access & BufferMappingAccessBit::Write) &&
!(access & BufferMappingAccessBit::FlushExplicit) &&
MG_Pipe::MGPipeResourceSubsystemEnabled()) {
@@ -967,7 +942,6 @@ namespace MobileGL::MG_State::GLState {
}
return m_resource.Bytes() + range.start;
}
#endif
if (!m_resource.IsGpuResident() && (access & BufferMappingAccessBit::Write) &&
!(access & BufferMappingAccessBit::FlushExplicit) &&
#if MOBILEGL_BUILD_DISAGGREGATED
@@ -40,7 +40,6 @@ namespace MobileGL::MG_State::GLState {
if (bindingPoint.GetBoundObject() == bufferObject) {
bindingPoint.Bind(nullptr);
bindingPoint.ClearRange();
#if MOBILEGL_PIPE_PUSH
// An UNBIND, and the one writer of an indexed point that is not an
// entry point (GL_Buffer.cpp's BindBuffer{Base,Range}_State and
// Core.cpp's transform-feedback writers bump their own): without the
@@ -51,7 +50,6 @@ namespace MobileGL::MG_State::GLState {
// "BackendSlotTable.Generation"} (DeletedBoundBufferScenario).
NoteBindPointChanged(BufferBindPointTargets[static_cast<SizeT>(
&bindingPointArray - m_bufferBindPointTargets.data())]);
#endif
}
}
}
@@ -63,7 +63,6 @@ namespace MobileGL::MG_State::GLState {
// resets the deleting context's bindings, and other contexts keep their own).
void UnbindBufferObject(const SharedPtr<BufferObject>& bufferObject);
#if MOBILEGL_PIPE_PUSH
// P2 brief D4: "did the contents of ANY buffer object move". One counter for every
// BufferObject ++m_changeSerial site, which is what NEW_VERTEX_BUFFERS /
// NEW_INDEX_BUFFER / NEW_CONST_BUFFERS / NEW_SHADER_BUFFERS / NEW_SO_TARGETS all
@@ -102,13 +101,10 @@ namespace MobileGL::MG_State::GLState {
if (it == BufferBindPointTargets.end()) return 0;
return m_bindPointGeneration[std::distance(BufferBindPointTargets.begin(), it)];
}
#endif
private:
#if MOBILEGL_PIPE_PUSH
Uint64 m_anyBufferChangeGeneration = 0;
Array<Uint64, BufferBindPointTargets.size()> m_bindPointGeneration{};
#endif
Array<BindingSlot<BufferObject>, GlobalBufferTargets.size()> m_bindingSlots;
// TODO: query the count somewhere globally?
// For glBindBufferBase / glBindBufferRange
-10
View File
@@ -277,11 +277,9 @@ namespace MobileGL::MG_State {
current.intValue[component] = static_cast<Int32>(value[component]);
current.uintValue[component] = static_cast<Uint32>(value[component]);
}
#if MOBILEGL_PIPE_PUSH
// The two views above are CONVERSIONS, not bit copies, so which one was written
// is part of the value; set_vertex_attrib_defaults carries it.
m_currentVertexAttributeClasses[index] = kVertexAttribValueClassFloat;
#endif
MGP_NOTE_AGGREGATE(VertexAttribDefault);
}
@@ -297,9 +295,7 @@ namespace MobileGL::MG_State {
current.floatValue[component] = static_cast<Float>(value[component]);
current.uintValue[component] = static_cast<Uint32>(value[component]);
}
#if MOBILEGL_PIPE_PUSH
m_currentVertexAttributeClasses[index] = kVertexAttribValueClassInt;
#endif
MGP_NOTE_AGGREGATE(VertexAttribDefault);
}
@@ -315,9 +311,7 @@ namespace MobileGL::MG_State {
current.floatValue[component] = static_cast<Float>(value[component]);
current.intValue[component] = static_cast<Int32>(value[component]);
}
#if MOBILEGL_PIPE_PUSH
m_currentVertexAttributeClasses[index] = kVertexAttribValueClassUint;
#endif
MGP_NOTE_AGGREGATE(VertexAttribDefault);
}
@@ -1427,13 +1421,11 @@ namespace MobileGL::MG_State {
}
void GLContext::RestoreBoundTransformFeedbackState() {
#if MOBILEGL_PIPE_PUSH
// The FOURTH writer of the transform-feedback binding points (a bind or a delete of
// the bound transform-feedback object swaps the whole set in): it moves the generation
// like the other three, so bit 17 cannot miss a swap whose two objects happen to carry
// the same capture-span generation.
NoteBufferBindPointChanged(BufferTarget::TransformFeedback);
#endif
const auto& object = m_transformFeedbackObjects[m_boundTransformFeedback];
for (Uint i = 0; i < MAX_TRANSFORM_FEEDBACK_BUFFERS; ++i) {
auto& point = m_bufferState.GetBindingPoint(BufferTarget::TransformFeedback, i);
@@ -1638,7 +1630,6 @@ namespace MobileGL::MG_State {
Bool hasExplicitRange) {
if (bufferIndex >= MAX_TRANSFORM_FEEDBACK_BUFFERS) return;
if (index == m_boundTransformFeedback) {
#if MOBILEGL_PIPE_PUSH
// P5e (sb): the THIRD writer of a transform-feedback binding point, and the one
// a reader of GL_Buffer.cpp alone would miss - glTransformFeedbackBufferBase /
// ...Range on the CURRENTLY BOUND object land here rather than in
@@ -1648,7 +1639,6 @@ namespace MobileGL::MG_State {
// POINT at all (it writes the named object's own table) and deliberately bumps
// nothing.
NoteBufferBindPointChanged(BufferTarget::TransformFeedback);
#endif
auto& point = m_bufferState.GetBindingPoint(BufferTarget::TransformFeedback, bufferIndex);
point.Bind(buffer);
if (buffer && hasExplicitRange) {
-8
View File
@@ -41,7 +41,6 @@ namespace MobileGL {
#endif
namespace GLState {
#if MOBILEGL_PIPE_PUSH
// MGPAttribValue::ValueClass' encoding (MG_Pipe/MGPipeTypes.h documents the order
// "Float | Int | Uint | Double"). It lives here rather than in MG_Pipe because the
// FRONTEND is the only thing that knows which of the three views below a value was
@@ -50,7 +49,6 @@ namespace MobileGL {
inline constexpr Uint32 kVertexAttribValueClassFloat = 0;
inline constexpr Uint32 kVertexAttribValueClassInt = 1;
inline constexpr Uint32 kVertexAttribValueClassUint = 2;
#endif
struct CurrentVertexAttributeValue {
Array<Float, 4> floatValue{0.f, 0.f, 0.f, 1.f};
@@ -186,14 +184,12 @@ namespace MobileGL {
m_textureState.NoteUnitTouched(unit, bindingChanged);
}
Int GetMaxTouchedTextureUnit() const { return m_textureState.GetMaxTouchedUnit(); }
#if MOBILEGL_PIPE_PUSH
// The IMAGE-unit high-water mark, which is a different namespace from the
// texture-unit one above - see TextureState::NoteImageUnitTouched for why it is a
// second mark and why it only grows. Push builds only, so the pull build's
// GLContext is untouched (G1).
void NoteImageUnitTouched(Int unit) { m_textureState.NoteImageUnitTouched(unit); }
Int GetMaxTouchedImageUnit() const { return m_textureState.GetMaxTouchedImageUnit(); }
#endif
// Monotonic counter bumped whenever a texture bind/unbind/delete changes which
// texture is bound at a unit; lets a backend skip re-resolving an unchanged
// per-draw sampled-texture set.
@@ -268,7 +264,6 @@ namespace MobileGL {
Uint GetBoundProgramPipelineName() const { return m_boundProgramPipeline; }
const SharedPtr<ProgramPipelineObject>& GetBoundProgramPipeline() const;
#if MOBILEGL_PIPE_PUSH
// ---- the aggregate generations (P2 brief D4) ----
//
// The bump points sit on OBJECTS - a VertexArrayObject, a TextureObject, a
@@ -334,7 +329,6 @@ namespace MobileGL {
? m_currentVertexAttributeClasses[index]
: kVertexAttribValueClassFloat;
}
#endif
// RenderState
Uint GetRenderStateParametersVersion() const;
@@ -665,11 +659,9 @@ namespace MobileGL {
Bool m_transformFeedbackPaused = false;
GLenum m_transformFeedbackPrimitiveMode = GL_POINTS;
SharedPtr<ProgramObject> m_transformFeedbackProgram;
#if MOBILEGL_PIPE_PUSH
Uint64 m_anyVertexAttribDefaultGeneration = 0;
// Parallel to m_currentVertexAttributes; see GetCurrentVertexAttributeClass.
Array<Uint32, VertexArrayObject::MAX_VERTEX_ATTRIBS> m_currentVertexAttributeClasses{};
#endif
Uint64 m_transformFeedbackGeneration = 0;
// Source of the per-span ids above; never rolls back with an object switch.
Uint64 m_transformFeedbackNextGeneration = 0;
@@ -23,7 +23,6 @@ namespace MobileGL::MG_State::GLState {
return s_nextFramebufferLifetimeId.fetch_add(1, std::memory_order_relaxed);
}
#if MOBILEGL_PIPE_PUSH
FramebufferObject::~FramebufferObject() {
// P4a D-I2: A FRAMEBUFFER HAS A HANDLE AND NO WIRE LIFETIME. PipeCalls.def carries
// resource_destroy and five delete_* rows and NO framebuffer delete, because a
@@ -42,7 +41,6 @@ namespace MobileGL::MG_State::GLState {
// record's ContentHash.
MG_Pipe::MGPipeEmitFramebufferDestroyAndFree(m_lifetimeId);
}
#endif
// FramebufferAttachmentObject
FramebufferAttachmentObject::FramebufferAttachmentObject(
@@ -115,12 +115,10 @@ namespace MobileGL {
Array<Uint16, static_cast<SizeT>(FramebufferAttachmentType::FramebufferAttachmentTypeCount)>;
FramebufferObject(Uint externalIndex);
#if MOBILEGL_PIPE_PUSH
// P2 step e2. Out of line, and declared only where there is a notice to raise:
// in a pull build this class keeps its implicit destructor, which is what keeps
// the pull build's symbol set byte-for-byte the pre-P2 one (G1).
~FramebufferObject();
#endif
void AttachTexture(FramebufferAttachmentType type, const SharedPtr<ITextureObject>& texture,
TextureUploadTarget textureUploadTarget = TextureUploadTarget::Unknown, int level = 0,
@@ -38,19 +38,15 @@ namespace MobileGL::MG_State::GLState {
SharedPtr<FramebufferObject> FindFramebufferObjectByLifetimeId(Uint64 lifetimeId) const;
#endif
#if MOBILEGL_PIPE_PUSH
// P2 brief D4: "did the attachment set or the default geometry of ANY framebuffer
// move". It does NOT cover a BIND - a bind writes a BindingSlot, not the object - so
// MGPipeTracker pairs this counter with the bound draw framebuffer identity, which
// is one extra load and keeps the bump points on the object where they belong.
void NoteAttachmentChanged() { ++m_anyAttachmentGeneration; }
Uint64 GetAnyAttachmentGeneration() const { return m_anyAttachmentGeneration; }
#endif
private:
#if MOBILEGL_PIPE_PUSH
Uint64 m_anyAttachmentGeneration = 0;
#endif
UnorderedMap<Uint, SharedPtr<FramebufferObject>> m_framebufferObjects;
IndexGenerator<Uint> m_indexGenerator;
Array<BindingSlot<FramebufferObject>, static_cast<SizeT>(FramebufferTarget::FramebufferTargetCount)>
@@ -32,7 +32,6 @@ namespace MobileGL::MG_State::GLState {
ProgramObject::~ProgramObject() {
CancelLink();
#if MOBILEGL_PIPE_PUSH
// P2 step e2: ANNOUNCE the death instead of leaving the backend to discover it in a
// garbage sweep. This is the last SharedPtr to this object dropping - not
// glDeleteProgram, which only marks the name and leaves a still-bound object very much
@@ -56,7 +55,6 @@ namespace MobileGL::MG_State::GLState {
// a proven no-op, because the slot allocator refuses a slot that is not live at that
// generation.
MG_Pipe::MGPipeEmitShaderCsoDestroyAndFree(m_lifetimeId);
#endif
}
// EnsureLinkJoined() is defined inline in ProgramObject.h (see the comment there for
@@ -1115,7 +1115,6 @@ namespace MobileGL::MG_State::GLState {
return Artifacts();
}
#if MOBILEGL_PIPE_PUSH
// The phase-B twin of GetLinkReflection, and it exists for exactly one caller:
// create_shader_state publishes the WHOLE SpirvArtifacts beside the whole
// LinkArtifacts, because the archive the far side deserialises into is those two
@@ -1130,7 +1129,6 @@ namespace MobileGL::MG_State::GLState {
const SpirvArtifacts& GetSpirvReflection() const {
return Spirv();
}
#endif
static Bool IsValidUniformLocation(const LinkArtifacts& artifacts, Int location) {
if (location < 0 || location > static_cast<Int>(artifacts.maxUniformLocation)) return false;
@@ -30,7 +30,6 @@ namespace MobileGL {
}
RenderbufferObject::RenderbufferObject(Uint externalIndex) : m_externalIndex(externalIndex) {
#if MOBILEGL_PIPE_PUSH
// P4a D-D1: resource_create from the constructor, carrying no storage. A
// renderbuffer is an INDEPENDENT class on the wire - it shares MGPResourceDesc's
// shape with textures and buffers and nothing else - and its handle is minted
@@ -42,10 +41,8 @@ namespace MobileGL {
// PipeFill.cpp decides.
MG_Pipe::MGPipeMintRenderbufferHandle(*this);
MG_Pipe::MGPipeEmitRenderbufferResourceCreate(*this);
#endif
}
#if MOBILEGL_PIPE_PUSH
RenderbufferObject::~RenderbufferObject() {
// P4a D-I1, the fixed three-step order: the wire delete first (published-gated,
// because a slot is not evidence of a record), then the death notice - the P2
@@ -57,7 +54,6 @@ namespace MobileGL {
// is deleted, not kept, for the reason ~TextureObjectBase states in full.
MG_Pipe::MGPipeEmitRenderbufferDestroyAndFree(m_lifetimeId);
}
#endif
Uint RenderbufferObject::GetExternalIndex() const {
return m_externalIndex;
@@ -114,28 +110,21 @@ namespace MobileGL {
void RenderbufferObject::SetInternalFormat(TextureInternalFormat format) {
m_internalFormat = format;
m_componentSizes = MG_Util::GetComponentSizesForInternalFormat(format);
#if MOBILEGL_PIPE_PUSH
PipePublishDescriptor();
#endif
}
void RenderbufferObject::AllocateStorage(IntVec2 size) {
m_width = size.x();
m_height = size.y();
m_allocated = true;
#if MOBILEGL_PIPE_PUSH
PipePublishDescriptor();
#endif
}
void RenderbufferObject::SetSamples(Int samples) {
m_samples = samples;
#if MOBILEGL_PIPE_PUSH
PipePublishDescriptor();
#endif
}
#if MOBILEGL_PIPE_PUSH
// D-D2: THE RENDERBUFFER PUBLICATION HOLE, CLOSED BY EMISSION AND NOT BY A NEW
// VERSION. These three setters bump no version and raise no notice, so
// `glBindRenderbuffer; glRenderbufferStorage(newSize)` on an attached renderbuffer
@@ -160,7 +149,6 @@ namespace MobileGL {
MG_Pipe::MGPipeEmitRenderbufferResourceRespecify(*this);
MGP_NOTE_AGGREGATE(FramebufferAttachment);
}
#endif
} // namespace GLState
} // namespace MG_State
} // namespace MobileGL
@@ -25,12 +25,10 @@ namespace MobileGL {
using TargetEnum = RenderbufferTarget;
RenderbufferObject(Uint externalIndex);
#if MOBILEGL_PIPE_PUSH
// P2 step e2. Out of line, and declared only where there is a notice to raise:
// in a pull build this class stays trivially destructible, which is what keeps
// the pull build's symbol set byte-for-byte the pre-P2 one (G1).
~RenderbufferObject();
#endif
Uint GetExternalIndex() const;
void SetInternalFormat(TextureInternalFormat format);
@@ -59,13 +57,11 @@ namespace MobileGL {
private:
static Uint64 AllocateLifetimeId();
#if MOBILEGL_PIPE_PUSH
// P4a D-D2: resource_respecify, from every storage-defining setter. Non-virtual
// and push-only, so the pull build's object layout is untouched (P4a's
// admitted-resize set is EMPTY); defined in RenderbufferObject.cpp, which is the
// one translation unit that includes the client emitter.
void PipePublishDescriptor();
#endif
Uint m_externalIndex = 0;
const Uint64 m_lifetimeId = AllocateLifetimeId();
@@ -26,7 +26,6 @@ namespace MobileGL {
SamplerObject::SamplerObject(Uint externalIndex)
: m_externalIndex(externalIndex), m_lifetimeId(AllocateLifetimeId()) {}
#if MOBILEGL_PIPE_PUSH
SamplerObject::~SamplerObject() {
// P2 step e2: ANNOUNCE the death instead of leaving the backend to discover it in a
// garbage sweep. This is the last SharedPtr to this object dropping - not the
@@ -53,7 +52,6 @@ namespace MobileGL {
// and exactly as before, is the notice.
MG_Pipe::MGPipeEmitSamplerCsoDestroyAndFree(m_lifetimeId);
}
#endif
void SamplerObject::BumpVersion() {
++m_version;
@@ -16,12 +16,10 @@ namespace MobileGL {
class SamplerObject {
public:
SamplerObject(Uint externalIndex);
#if MOBILEGL_PIPE_PUSH
// P2 step e2. Out of line, and declared only where there is a notice to raise:
// in a pull build this class keeps its implicit destructor, which is what keeps
// the pull build's symbol set byte-for-byte the pre-P2 one (G1).
~SamplerObject();
#endif
void SetWrapS(SamplerWrapMode mode);
void SetWrapT(SamplerWrapMode mode);
@@ -9,7 +9,6 @@
#pragma once
#include <Includes.h>
#if MOBILEGL_PIPE_PUSH
#include <MG_Pipe/MGPipeHandles.h>
// P2 step e2, the frontend half: TELL the backend that a state object died, instead of
@@ -59,4 +58,3 @@ namespace MobileGL::MG_State::GLState {
}
} // namespace MobileGL::MG_State::GLState
#endif // MOBILEGL_PIPE_PUSH
@@ -34,7 +34,6 @@ namespace MobileGL {
return s_nextTextureLifetimeId.fetch_add(1, std::memory_order_relaxed);
}
#if MOBILEGL_PIPE_PUSH
TextureObjectBase::~TextureObjectBase() {
// P4a D-I1: BACKEND-NEUTRAL FROM DAY ONE, and the three-step order is fixed.
//
@@ -110,7 +109,6 @@ namespace MobileGL {
MG_Pipe::MGPipeNoteTextureLevelDirty(*this, static_cast<Uint32>(uploadTarget),
static_cast<Uint32>(mipmapLevel));
}
#endif
void TextureObjectBase::BumpShapeVersion() {
++m_shapeVersion;
@@ -142,7 +140,6 @@ namespace MobileGL {
m_sampler->SetWrapT(SamplerWrapMode::ClampToEdge);
m_sampler->SetWrapR(SamplerWrapMode::ClampToEdge);
}
#if MOBILEGL_PIPE_PUSH
// P4a D-D1: A RESOURCE EXISTS BEFORE ANYTHING CAN NAME IT, so resource_create is
// emitted from the constructor and carries no storage - the store is defined
// lazily by the first respecify and every backend already tolerates a resource
@@ -169,7 +166,6 @@ namespace MobileGL {
(void)externalIndex;
MG_Pipe::MGPipeMintTextureHandle(*this);
MG_Pipe::MGPipeEmitTextureResourceCreate(*this);
#endif
}
TextureInternalFormat TextureObjectBase::GetFormat() const {
@@ -217,14 +213,12 @@ namespace MobileGL {
BumpShapeVersion();
++m_textureParamsVersion;
MGP_NOTE_AGGREGATE(TextureParams);
#if MOBILEGL_PIPE_PUSH
// The format is BOTH halves: a descriptor field the backend allocates from and a
// parameter the swizzle / depth-stencil push reads, so both records move. It is
// also the last statement of both glTexBuffer entry points, which is what
// publishes a buffer texture's window without a call site in MG_Impl/GLImpl.
PipePublishDescriptor();
PipePublishParams();
#endif
}
Uint TextureObjectBase::GetExternalIndex() const {
@@ -251,9 +245,7 @@ namespace MobileGL {
m_sampler->SetBorderColor(color);
++m_textureParamsVersion;
MGP_NOTE_AGGREGATE(TextureParams);
#if MOBILEGL_PIPE_PUSH
PipePublishParams();
#endif
}
const IntVec4& TextureObjectBase::GetBorderColorI() const {
@@ -269,9 +261,7 @@ namespace MobileGL {
m_sampler->SetBorderColorI(color);
++m_textureParamsVersion;
MGP_NOTE_AGGREGATE(TextureParams);
#if MOBILEGL_PIPE_PUSH
PipePublishParams();
#endif
}
const UintVec4& TextureObjectBase::GetBorderColorUI() const {
@@ -287,9 +277,7 @@ namespace MobileGL {
m_sampler->SetBorderColorUI(color);
++m_textureParamsVersion;
MGP_NOTE_AGGREGATE(TextureParams);
#if MOBILEGL_PIPE_PUSH
PipePublishParams();
#endif
}
BorderColorForm TextureObjectBase::GetBorderColorForm() const {
@@ -340,9 +328,7 @@ namespace MobileGL {
}
++m_textureParamsVersion;
MGP_NOTE_AGGREGATE(TextureParams);
#if MOBILEGL_PIPE_PUSH
PipePublishParams();
#endif
}
void TextureObjectBase::SetSwizzleParamRGBA(const Vec4<TextureSwizzleParam>& values) {
@@ -351,9 +337,7 @@ namespace MobileGL {
m_swizzleParams = values;
++m_textureParamsVersion;
MGP_NOTE_AGGREGATE(TextureParams);
#if MOBILEGL_PIPE_PUSH
PipePublishParams();
#endif
}
const UintVec2& TextureObjectBase::GetLevelRange() const {
@@ -373,12 +357,10 @@ namespace MobileGL {
++m_textureParamsVersion;
MGP_NOTE_AGGREGATE(TextureParams);
BumpShapeVersion();
#if MOBILEGL_PIPE_PUSH
// The level range is PARAMS, not a descriptor field: the record carries
// BaseLevel / MaxLevel and the storage is untouched. The descriptor is deduped on
// its own bytes, so the shape bump above costs nothing here.
PipePublishParams();
#endif
}
void TextureObjectBase::SetMaxLevel(Uint maxLevel) {
@@ -391,9 +373,7 @@ namespace MobileGL {
++m_textureParamsVersion;
MGP_NOTE_AGGREGATE(TextureParams);
BumpShapeVersion();
#if MOBILEGL_PIPE_PUSH
PipePublishParams();
#endif
}
Bool TextureObjectBase::IsImmutable() const {
@@ -414,14 +394,12 @@ namespace MobileGL {
}
++m_textureParamsVersion;
MGP_NOTE_AGGREGATE(TextureParams);
#if MOBILEGL_PIPE_PUSH
// Immutable is a descriptor fact the backend reads - and NOT a request for an
// acknowledgement: MGPipeResourceRespecifyNeedsAck names the buffer target
// explicitly, because texture allocation is lazy in monolith and stays lazy in
// split. The level clamp above is params.
PipePublishDescriptor();
PipePublishParams();
#endif
}
Uint16 TextureObjectBase::GetTextureParamsVersion() const {
@@ -460,9 +438,7 @@ namespace MobileGL {
m_samples = samples;
++m_textureParamsVersion;
MGP_NOTE_AGGREGATE(TextureParams);
#if MOBILEGL_PIPE_PUSH
PipePublishDescriptor();
#endif
}
Bool TextureObjectBase::HasFixedSampleLocations() const {
@@ -473,9 +449,7 @@ namespace MobileGL {
m_fixedSampleLocations = fixedSampleLocations;
++m_textureParamsVersion;
MGP_NOTE_AGGREGATE(TextureParams);
#if MOBILEGL_PIPE_PUSH
PipePublishDescriptor();
#endif
}
Uint64 TextureObjectBase::GetLifetimeId() const {
@@ -507,7 +481,6 @@ namespace MobileGL {
MipmapInput input) {
BumpShapeVersion();
m_textureStorage.AllocateLevel(GetIndexOfTextureUploadTarget(uploadTarget), mipmapLevel, input);
#if MOBILEGL_PIPE_PUSH
// AFTER the allocation, never before: BumpShapeVersion runs first and a descriptor
// built there would describe the level set this call is about to change. Every
// storage-defining GL entry point - glTexImage*, glCompressedTexImage*,
@@ -517,17 +490,14 @@ namespace MobileGL {
// C-1): this call replaced ONE level's storage, and only that level's pending
// upload may go with it.
PipePublishLevelDescriptor(uploadTarget, mipmapLevel);
#endif
}
void TextureObjectWithOneMipmap::TruncateMipmapLevels(TextureUploadTarget uploadTarget, Uint levelCount) {
BumpShapeVersion();
m_textureStorage.TruncateToLevelCount(GetIndexOfTextureUploadTarget(uploadTarget), levelCount);
#if MOBILEGL_PIPE_PUSH
// The levels at and above the cut are gone; the ones below keep their pending
// uploads (final review C-1).
PipePublishTruncatedDescriptor(uploadTarget, levelCount);
#endif
}
void TextureObjectWithOneMipmap::UpdateMipmapSubData(TextureUploadTarget uploadTarget, Uint mipmapLevel,
@@ -546,11 +516,9 @@ namespace MobileGL {
MGP_NOTE_AGGREGATE(TextureContent);
}
m_textureStorage.MarkDirty(GetIndexOfTextureUploadTarget(uploadTarget), mipmapLevel, dirty);
#if MOBILEGL_PIPE_PUSH
// THE DRAIN LIST HAS NO CLEAN ARM (see TextureEmit.h): a level that goes clean
// is collected at the next drain, whose first test is IsStorageDirty.
if (dirty) PipeNoteLevelDirty(uploadTarget, mipmapLevel);
#endif
}
Bool TextureObjectWithOneMipmap::IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const {
@@ -563,13 +531,11 @@ namespace MobileGL {
MGP_NOTE_AGGREGATE(TextureContent);
m_textureStorage.MarkDirtyRegion(GetIndexOfTextureUploadTarget(uploadTarget), mipmapLevel, offset,
size);
#if MOBILEGL_PIPE_PUSH
// THE DRAIN LIST IS KEYED ON THE STORAGE OWNER FOR FREE: TextureObjectView
// forwards this call to the OWNER's method after remapping the level and the
// region, so an upload through a view and an upload through the owner arrive here
// on the same object with the same owner-side coordinates.
PipeNoteLevelDirty(uploadTarget, mipmapLevel);
#endif
}
MipmapDirtyRegion TextureObjectWithOneMipmap::GetStorageDirtyRegion(TextureUploadTarget uploadTarget,
@@ -117,15 +117,11 @@ namespace MobileGL::MG_State::GLState {
class TextureObjectBase : public ITextureObject {
public:
TextureObjectBase(TextureTarget target, Uint externalIndex);
#if MOBILEGL_PIPE_PUSH
// P2 step e2. Out of line, and declared only where there is a notice to raise: in a
// pull build this stays the implicit `= default` the pre-P2 tree had, which is what
// keeps the pull build's symbol set byte-for-byte the pre-P2 one (G1). Declared on the
// BASE, so every concrete texture class - 2D, 3D, cube, buffer, view - announces once.
virtual ~TextureObjectBase();
#else
virtual ~TextureObjectBase() = default;
#endif
TextureInternalFormat GetFormat() const override;
TextureTarget GetTarget() const override;
@@ -190,12 +186,10 @@ namespace MobileGL::MG_State::GLState {
m_depthStencilTextureMode = mode;
++m_textureParamsVersion;
MGP_NOTE_AGGREGATE(TextureParams);
#if MOBILEGL_PIPE_PUSH
// D-E3's whole point, at the one site that proves it: the depth-stencil mode of a
// texture that is ONLY the READ framebuffer's attachment reaches the driver, because
// set_texture_params is addressed by resource and is independent of every binding.
PipePublishParams();
#endif
}
protected:
@@ -207,7 +201,6 @@ namespace MobileGL::MG_State::GLState {
// otherwise invisible to such a memo (no bind moved).
void BumpShapeVersion();
#if MOBILEGL_PIPE_PUSH
// ---- P4a's client emission points (brief D-D1, D-D3, D-E1, D-I1) ----
//
// NON-VIRTUAL AND PUSH-ONLY, both deliberately: a virtual would grow the vtable and a
@@ -245,7 +238,6 @@ namespace MobileGL::MG_State::GLState {
// level that goes clean is collected at the next drain, where !IsStorageDirty is the
// first test EmitOneLevel makes.
void PipeNoteLevelDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel);
#endif
const Uint m_externalIndex;
const Uint64 m_lifetimeId;
@@ -31,21 +31,17 @@ namespace MobileGL {
MipmapInput input) {
BumpShapeVersion();
m_textureStorage.AllocateLevel(GetIndexOfTextureUploadTarget(uploadTarget), mipmapLevel, input);
#if MOBILEGL_PIPE_PUSH
// AFTER the allocation, for TextureObjectWithOneMipmap's reason: BumpShapeVersion
// runs first and a descriptor built there would describe the level set this call
// is about to change. The FACE rides in `uploadTarget`, so the key the emitter
// drops is that face's level and no other face's (final review C-1).
PipePublishLevelDescriptor(uploadTarget, mipmapLevel);
#endif
}
void TextureObject2DCube::TruncateMipmapLevels(TextureUploadTarget uploadTarget, Uint levelCount) {
BumpShapeVersion();
m_textureStorage.TruncateToLevelCount(GetIndexOfTextureUploadTarget(uploadTarget), levelCount);
#if MOBILEGL_PIPE_PUSH
PipePublishTruncatedDescriptor(uploadTarget, levelCount);
#endif
}
void TextureObject2DCube::UpdateMipmapSubData(TextureUploadTarget uploadTarget, Uint mipmapLevel,
@@ -63,11 +59,9 @@ namespace MobileGL {
MGP_NOTE_AGGREGATE(TextureContent);
}
m_textureStorage.MarkDirty(GetIndexOfTextureUploadTarget(uploadTarget), mipmapLevel, dirty);
#if MOBILEGL_PIPE_PUSH
// SIX FACES, SIX BLOBS, SIX DRAIN KEYS: the upload target is the face, and it is
// what the sub-data record's Target byte carries beside the resource target.
if (dirty) PipeNoteLevelDirty(uploadTarget, mipmapLevel);
#endif
}
bool TextureObject2DCube::IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const {
@@ -80,9 +74,7 @@ namespace MobileGL {
MGP_NOTE_AGGREGATE(TextureContent);
m_textureStorage.MarkDirtyRegion(GetIndexOfTextureUploadTarget(uploadTarget), mipmapLevel, offset,
size);
#if MOBILEGL_PIPE_PUSH
PipeNoteLevelDirty(uploadTarget, mipmapLevel);
#endif
}
MipmapDirtyRegion TextureObject2DCube::GetStorageDirtyRegion(TextureUploadTarget uploadTarget,
@@ -29,7 +29,6 @@ namespace MobileGL {
void SetBufferRange(SizeT offset, SizeT size) {
m_bufferRangeOffset = offset;
m_bufferRangeSize = size;
#if MOBILEGL_PIPE_PUSH
// Both glTexBuffer entry points bind the backing buffer and then set the
// window, so this is the first statement at which the descriptor's
// BufferForTexBuffer / BufOffset / BufSize trio is complete. SetInternalFormat
@@ -37,7 +36,6 @@ namespace MobileGL {
// not move - which is exactly the case a re-attach of a DIFFERENT buffer at
// the same format would otherwise fall through.
PipePublishDescriptor();
#endif
}
SizeT GetBufferRangeOffset() const { return m_bufferRangeOffset; }
// Resolved against the buffer's current size, so kWholeBuffer tracks it.
@@ -79,7 +79,6 @@ namespace MobileGL::MG_State::GLState {
// to the view. GetImmutableLevels() forwards to the owner for the actual GL query, which
// GL 4.6 core 8.18 defines as the ORIGINAL texture's value.
SetImmutableLevels(numLevels);
#if MOBILEGL_PIPE_PUSH
// ViewOf, and it is published from HERE rather than left to SetImmutableLevels above,
// which early-returns when the composed level count happens to be the base class's
// current value - a degenerate view (the spec's min() composition narrowed to zero
@@ -90,7 +89,6 @@ namespace MobileGL::MG_State::GLState {
// at creation, which is what the spec's additive min-level rule describes and what the
// assertion above pins, so the owner named here is never itself a view.
PipePublishDescriptor();
#endif
}
Uint TextureObjectView::GetImmutableLevels() const {
@@ -38,7 +38,6 @@ namespace MobileGL::MG_State::GLState {
Access = access;
Format = format;
++Version;
#if MOBILEGL_PIPE_PUSH
// P4a D-A4 / final review M-A: the EARLIEST producer of kMGPipeBindShaderImage. The
// ImageBindableHint the bit feeds prevents the texture re-mint (a texture the server
// knows may be image-bound is allocated image-bindable up front, P9 W2), so it has
@@ -46,7 +45,6 @@ namespace MobileGL::MG_State::GLState {
// the bind, not at the next validate point's image walk. Push-only through the
// contract's door, like every other hook in this directory (G1).
if (Texture) MG_Pipe::MGPipeNoteTextureImageBound(*Texture);
#endif
}
};
@@ -107,7 +105,6 @@ namespace MobileGL::MG_State::GLState {
}
}
Int GetMaxTouchedUnit() const { return m_maxTouchedUnit; }
#if MOBILEGL_PIPE_PUSH
// High-water mark of IMAGE units ever bound by glBindImageTexture, and it is a SECOND
// mark rather than a widening of the one above because the two index different
// namespaces: GL 4.6 core 8.22's image units are their own array, and folding them
@@ -139,7 +136,6 @@ namespace MobileGL::MG_State::GLState {
}
// -1 until an image unit is bound for the first time, i.e. "there is nothing to sweep".
Int GetMaxTouchedImageUnit() const { return m_maxTouchedImageUnit; }
#endif
Uint64 GetTextureBindGeneration() const { return m_textureBindGeneration; }
// Both counters below are pushed PipeInputs fields AND are moved by writes the
// backends make into frontend objects during their own verb - a synthesised fallback
@@ -181,7 +177,6 @@ namespace MobileGL::MG_State::GLState {
// again (the unit tests do exactly that between cases).
Uint64 GetContextId() const { return m_contextId; }
#if MOBILEGL_PIPE_PUSH
// P2 brief D4, the two texture aggregates. CONTENT is an upload or a dirty region;
// PARAMS is a glTexParameter or a glSamplerParameter. They are separate because
// NEW_SAMPLER_VIEWS and NEW_SAMPLERS are separate dirty bits and a Minecraft frame
@@ -190,15 +185,12 @@ namespace MobileGL::MG_State::GLState {
Uint64 GetAnyTextureContentGeneration() const { return m_anyTextureContentGeneration; }
void NoteTextureParamsChanged() { ++m_anyTextureParamsGeneration; }
Uint64 GetAnyTextureParamsGeneration() const { return m_anyTextureParamsGeneration; }
#endif
private:
#if MOBILEGL_PIPE_PUSH
Uint64 m_anyTextureContentGeneration = 0;
Uint64 m_anyTextureParamsGeneration = 0;
// See NoteImageUnitTouched: the image-unit twin of m_maxTouchedUnit, push builds only.
Int m_maxTouchedImageUnit = -1;
#endif
static Uint64 AllocateContextId();
const Uint64 m_contextId;
@@ -38,7 +38,6 @@ namespace MobileGL::MG_State::GLState {
}
}
#if MOBILEGL_PIPE_PUSH
VertexArrayObject::~VertexArrayObject() {
// P2 step e2 / P3a C-1: ANNOUNCE the death instead of leaving the backend to discover
// it in a garbage sweep, and RETURN THE CLIENT'S OWN SLOT while doing it. This is the
@@ -62,7 +61,6 @@ namespace MobileGL::MG_State::GLState {
// (BufferObject.cpp -> MGPipeEmitResourceDestroyAndFree).
MG_Pipe::MGPipeEmitVertexElementsDestroyAndFree(m_lifetimeId);
}
#endif
void VertexArrayObject::EnableAttribute(Uint index) {
if (index >= MAX_VERTEX_ATTRIBS) return;
@@ -25,12 +25,10 @@ namespace MobileGL {
static constexpr int MAX_VERTEX_ATTRIB_BINDINGS = 32;
VertexArrayObject(Uint externIndex);
#if MOBILEGL_PIPE_PUSH
// P2 step e2. Out of line, and declared only where there is a notice to raise:
// in a pull build this class keeps its implicit destructor, which is what keeps
// the pull build's symbol set byte-for-byte the pre-P2 one (G1).
~VertexArrayObject();
#endif
void EnableAttribute(Uint index);
void DisableAttribute(Uint index);
@@ -106,71 +104,6 @@ namespace MobileGL {
// "any vertex-input state changed" with one compare.
Uint32 GetConfigVersion() const { return m_configVersion; }
#if MOBILEGL_PIPE_LEGACY_MEMOS
// ---- THE BACKEND'S THREE MEMOS ON THE FRONTEND OBJECT ----
//
// P2 D12.5 (ARCHITECTURE.md 9.5) retires all three: a frontend state object
// must not hold the backend's raw pointers, and under split it cannot - the
// backend is in another process and its cache entry has no address the client
// could store. Magma's handle arm keeps the same three facts in a slot-indexed
// table it owns itself (VertexInputStateFactory::VaoBackendMemos), keyed on the
// VAO's {slot, gen} and validated by the same config version, so nothing is
// recomputed more often than it was.
//
// They stay compiled under MOBILEGL_PIPE_LEGACY_MEMOS - which a PULL build
// forces ON - because that is the arm the pre-handle A/B runs, and because G1
// admits no change to the pull build. They are deleted outright with the pull
// path at P13.
//
// Backend-owned content-hash memo, valid while the config version matches
// (same idea as ProgramObject's hash memo — avoids re-hashing all
// attributes on every draw).
Bool GetBackendHashMemo(Uint64& outHash) const {
if (m_backendHashMemoVersion != m_configVersion) return false;
outHash = m_backendHashMemo;
return true;
}
void SetBackendHashMemo(Uint64 hash) const {
m_backendHashMemo = hash;
m_backendHashMemoVersion = m_configVersion;
}
// Backend-owned resolved-state memo: an opaque pointer into the
// backend's vertex-input-state cache plus the cache's eviction
// epoch, valid while the config version matches. Lets the
// per-draw path skip the content hash AND the cache lookup; the
// epoch guards against the cache evicting the pointee.
Bool GetBackendStateMemo(const void*& outState, Uint64& outEpoch) const {
if (m_backendStateMemoVersion != m_configVersion) return false;
outState = m_backendStateMemo;
outEpoch = m_backendStateMemoEpoch;
return true;
}
void SetBackendStateMemo(const void* state, Uint64 epoch) const {
m_backendStateMemo = state;
m_backendStateMemoEpoch = epoch;
m_backendStateMemoVersion = m_configVersion;
}
// Backend-owned aux memo: two opaque VALUE words (no pointee, so unlike the
// state memo above they need no eviction-epoch guard), valid while the config
// version matches. They live next to m_configVersion, which every per-draw
// path already loads, so a backend can re-read small derived facts about this
// VAO's configuration (e.g. a layout hash and attribute masks) without
// chasing into its own cache's heap entry - that chase is a guaranteed cache
// miss when an app cycles hundreds of VAOs per frame.
Bool GetBackendAuxMemo(Uint64& outAux0, Uint64& outAux1) const {
if (m_backendAuxMemoVersion != m_configVersion) return false;
outAux0 = m_backendAuxMemo0;
outAux1 = m_backendAuxMemo1;
return true;
}
void SetBackendAuxMemo(Uint64 aux0, Uint64 aux1) const {
m_backendAuxMemo0 = aux0;
m_backendAuxMemo1 = aux1;
m_backendAuxMemoVersion = m_configVersion;
}
#endif // MOBILEGL_PIPE_LEGACY_MEMOS
private:
void BumpAttributeFormatVersion(Uint index);
@@ -210,19 +143,6 @@ namespace MobileGL {
Array<Bool, MAX_VERTEX_ATTRIBS> m_attributeUsesBindingModel = {};
Uint32 m_configVersion = 0;
#if MOBILEGL_PIPE_LEGACY_MEMOS
// The storage behind the three accessors above; retired with them (D12.5).
// A pull build forces MOBILEGL_PIPE_LEGACY_MEMOS ON, so sizeof(this) does not
// move there and G1 sees no change.
mutable Uint64 m_backendHashMemo = 0;
mutable Uint32 m_backendHashMemoVersion = ~0u;
mutable const void* m_backendStateMemo = nullptr;
mutable Uint64 m_backendStateMemoEpoch = 0;
mutable Uint32 m_backendStateMemoVersion = ~0u;
mutable Uint64 m_backendAuxMemo0 = 0;
mutable Uint64 m_backendAuxMemo1 = 0;
mutable Uint32 m_backendAuxMemoVersion = ~0u;
#endif // MOBILEGL_PIPE_LEGACY_MEMOS
};
} // namespace GLState
} // namespace MG_State
@@ -28,7 +28,6 @@ namespace MobileGL {
const SharedPtr<VertexArrayObject>& GetBoundVertexArray();
Vector<SharedPtr<VertexArrayObject>>& GetAllVertexArrays();
#if MOBILEGL_PIPE_PUSH
// P2 brief D4: "did the attribute configuration of ANY vertex array move".
// Bumped from every VertexArrayObject::BumpAttribute*Version through
// MGP_NOTE_AGGREGATE(VaoAttribute), which is coarser than the per-object
@@ -36,12 +35,9 @@ namespace MobileGL {
// re-push costs a push while a missed one renders stale.
void NoteAttributeChanged() { ++m_anyVaoAttributeGeneration; }
Uint64 GetAnyAttributeGeneration() const { return m_anyVaoAttributeGeneration; }
#endif
private:
#if MOBILEGL_PIPE_PUSH
Uint64 m_anyVaoAttributeGeneration = 0;
#endif
// "Nothing bound" (an out-of-range or never-created name was bound). Distinct from
// being bound to a live slot so that a slot filled AFTER such a bind does not
// retroactively become the bound VAO.
-26
View File
@@ -164,11 +164,9 @@ namespace MobileGL::MG_Util::PipeStats {
Counter g_totalGateMiss[kGateCount];
Counter g_totalPayloadBuckets[kPayloadHistogramBuckets];
Counter g_frameCount{0};
#if MOBILEGL_PIPE_PUSH
// P6 gate 8's second histogram, and push-only for the same reason its accessor is: its
// only sampler is the wire encoder, which a pull build does not compile.
Counter g_totalStagedBlobBuckets[kStagedBlobHistogramBuckets];
#endif
// Window bases: the run totals as of the previous summary line. Only ever touched
// from OnPresent()/Shutdown() (the present thread), so plain integers.
@@ -178,13 +176,11 @@ namespace MobileGL::MG_Util::PipeStats {
Uint64 g_windowBaseGateMiss[kGateCount] = {};
Uint64 g_windowBaseFrames = 0;
Bool g_shutdownDone = false;
#if MOBILEGL_PIPE_PUSH
// The gauges' storage. Relaxed atomics like every other counter here: the publisher is
// the GL thread at a frame boundary and the reader is whoever formats the line, which
// under split can be the apply thread.
Counter g_gauges[static_cast<Uint32>(Gauge::Count)] = {};
constexpr Uint32 kGaugeCount = static_cast<Uint32>(Gauge::Count);
#endif
// Frames per summary line, latched by Init() from MOBILEGL_PIPE_STATS_PERIOD.
Uint64 g_summaryPeriod = kDefaultSummaryFramePeriod;
@@ -225,14 +221,11 @@ namespace MobileGL::MG_Util::PipeStats {
"stage-buffer", "stage-texture", "stage-ubo-global",
"stage-ubo-named", "stage-vertex-client", "stage-index-client",
"stage-indirect-cmd", "persistent-map-push", "residual-value-block",
#if MOBILEGL_PIPE_PUSH
"cso-blob-bytes", "stage-segment-bytes",
#endif
};
const char* const kCallClassNames[kCallClassCount] = {
"draws", "accessor-calls", "tex-upload-emissions", "tex-upload-box", "tex-upload-rect",
"tex-upload-jobs",
#if MOBILEGL_PIPE_PUSH
"render-state-cso-mints", "render-state-cso-binds", "map-persistent-roundtrips",
"framebuffer-emissions", "sampler-view-emissions", "sampler-state-emissions",
"shader-image-emissions", "client-tex-upload-emissions", "tex-remint-pulls",
@@ -241,7 +234,6 @@ namespace MobileGL::MG_Util::PipeStats {
"wire-indirect-native-draws", "wire-indirect-cpu-expansions", "wire-indirect-barriers",
"wire-host-waits", "wire-host-waits-indirect", "wire-host-wait-us",
"wire-indirect-native-dispatches",
#endif
};
const char* const kGateNames[kGateCount] = {
"espryt-render-state", "espryt-texture-sync-list", "espryt-unit-bindings-epoch",
@@ -264,9 +256,7 @@ namespace MobileGL::MG_Util::PipeStats {
// recorded baseline stops meaning anything.
const char* const kByteClassShort[kByteClassCount] = {"buf", "tex", "ubog", "ubon", "vtxc",
"idxc", "icmd", "pmap", "resid",
#if MOBILEGL_PIPE_PUSH
"csob-blob", "seg",
#endif
};
const char* const kGateShort[kGateCount] = {"ers", "etl", "eub", "mfp", "mpm", "mdt"};
@@ -294,16 +284,12 @@ namespace MobileGL::MG_Util::PipeStats {
}
g_frameCount.store(0, std::memory_order_relaxed);
g_windowBaseFrames = 0;
#if MOBILEGL_PIPE_PUSH
for (Uint32 i = 0; i < kStagedBlobHistogramBuckets; ++i) {
g_totalStagedBlobBuckets[i].store(0, std::memory_order_relaxed);
}
#endif
#if MOBILEGL_PIPE_PUSH
for (Uint32 i = 0; i < kGaugeCount; ++i) {
g_gauges[i].store(0, std::memory_order_relaxed);
}
#endif
}
void EmitSummaryLine() {
@@ -436,7 +422,6 @@ namespace MobileGL::MG_Util::PipeStats {
Bump(g_totalCalls[index], count);
}
#if MOBILEGL_PIPE_PUSH
// A STORE, NOT A BUMP, and the difference is the whole reason these are a separate kind.
// The publisher hands over its OWN run total (a maximum, or a count it has been keeping
// since the session opened), so accumulating deltas here would double every reading; and a
@@ -447,7 +432,6 @@ namespace MobileGL::MG_Util::PipeStats {
}
Uint64 GaugeValue(Gauge gauge) { return Read(g_gauges[static_cast<Uint32>(gauge)]); }
#endif
void CountGate(Gate gate, Bool hit) {
const Uint32 index = static_cast<Uint32>(gate);
@@ -462,14 +446,12 @@ namespace MobileGL::MG_Util::PipeStats {
void RecordDrawPayloadBytes(Uint64 bytes) { Bump(g_totalPayloadBuckets[PayloadBucketOf(bytes)], 1); }
#if MOBILEGL_PIPE_PUSH
// P6 gate 8's staged-blob distribution. A count, not a sum: the bytes already have a home
// in stage-segment-bytes, and what this exists to answer is the SHAPE (how many blobs there
// were and how big each one was), which a total cannot express.
void RecordStagedBlobBytes(Uint64 bytes) {
Bump(g_totalStagedBlobBuckets[PayloadBucketOf(bytes)], 1);
}
#endif
void OnPresent() {
// Every frame accumulator is EXCHANGED for zero, and the exchanged value is what gets
@@ -526,11 +508,9 @@ namespace MobileGL::MG_Util::PipeStats {
Uint64 TotalPayloadBucket(Uint32 bucket) {
return bucket < kPayloadHistogramBuckets ? Read(g_totalPayloadBuckets[bucket]) : 0;
}
#if MOBILEGL_PIPE_PUSH
Uint64 TotalStagedBlobBucket(Uint32 bucket) {
return bucket < kStagedBlobHistogramBuckets ? Read(g_totalStagedBlobBuckets[bucket]) : 0;
}
#endif
Uint64 FrameCount() { return Read(g_frameCount); }
const char* NameOf(ByteClass byteClass) { return kByteClassNames[static_cast<Uint32>(byteClass)]; }
@@ -590,7 +570,6 @@ namespace MobileGL::MG_Util::PipeStats {
line += " box=" + std::to_string(calls[static_cast<Uint32>(CallClass::TextureUploadBoxEmissions)]);
line += " rect=" + std::to_string(calls[static_cast<Uint32>(CallClass::TextureUploadRectEmissions)]);
line += " jobs=" + std::to_string(calls[static_cast<Uint32>(CallClass::TextureUploadJobs)]);
#if MOBILEGL_PIPE_PUSH
// Push-only, like the two counters themselves: in a pull build there is no CSO to
// mint, and a "csom=0 csob=0" that can never be anything else is noise on the one
// line an operator greps.
@@ -704,7 +683,6 @@ namespace MobileGL::MG_Util::PipeStats {
line += " whwus=" + std::to_string(calls[static_cast<Uint32>(CallClass::WireHostWaitMicros)]);
// P8-SV: the indirect dispatches, on the same bracket (their barriers are in `wibar`).
line += " wdsp=" + std::to_string(calls[static_cast<Uint32>(CallClass::WireIndirectNativeDispatches)]);
#endif
line += "] gates[";
for (Uint32 i = 0; i < kGateCount; ++i) {
if (i != 0) {
@@ -759,7 +737,6 @@ namespace MobileGL::MG_Util::PipeStats {
", \"miss\": " + std::to_string(Read(g_totalGateMiss[i])) + "}";
json += (i + 1 == kGateCount) ? "\n" : ",\n";
}
#if MOBILEGL_PIPE_PUSH
// The gauges, under their long names. Run totals here as on the summary line.
json += " },\n \"wire\": {\n";
json += " \"max-record-bytes\": " +
@@ -790,7 +767,6 @@ namespace MobileGL::MG_Util::PipeStats {
std::to_string(Read(g_gauges[static_cast<Uint32>(Gauge::WireDeferredBytesPeak)])) + ",\n";
json += " \"wire-deferred-syncs\": " +
std::to_string(Read(g_gauges[static_cast<Uint32>(Gauge::WireDeferredSyncs)])) + "\n";
#endif
json += " },\n \"cmd-bytes-per-draw-histogram\": [";
for (Uint32 i = 0; i < kPayloadHistogramBuckets; ++i) {
if (i != 0) {
@@ -798,7 +774,6 @@ namespace MobileGL::MG_Util::PipeStats {
}
json += std::to_string(Read(g_totalPayloadBuckets[i]));
}
#if MOBILEGL_PIPE_PUSH
// P6 gate 8's two per-frame numbers have their JSON homes where every other ByteClass and
// CallClass already does - the `bytes` and `calls` blocks above, under their long names
// (stage-segment-bytes, wire-records) - so there is nothing to add for them here. The
@@ -814,7 +789,6 @@ namespace MobileGL::MG_Util::PipeStats {
}
json += std::to_string(Read(g_totalStagedBlobBuckets[i]));
}
#endif
json += "]\n}\n";
return json;
}
-8
View File
@@ -73,7 +73,6 @@ namespace MobileGL::MG_Util::PipeStats {
// PLACEHOLDER (plan section 6.3): the residual value block does not exist yet. The
// class is minted now so the counter names never churn; it stays at 0 until P2.
ResidualValueBlock,
#if MOBILEGL_PIPE_PUSH
// P4a's, and THE PUSH GUARD IS NEW ON THIS ENUM: CallClass has had one since P2 and
// ByteClass has never had one, so the block is opened here rather than the member
// simply appended. Without it the pull build's two counter arrays, the name table, the
@@ -113,7 +112,6 @@ namespace MobileGL::MG_Util::PipeStats {
// is what MOBILEGL_IPC_STAGE_MB has to hold for one record. The per-blob distribution
// this average hides is the staged-blob histogram below.
StageSegmentBytes,
#endif
Count
};
@@ -139,7 +137,6 @@ namespace MobileGL::MG_Util::PipeStats {
// Driver upload jobs issued by those emissions: 1 per box emission, N per rect-list
// emission.
TextureUploadJobs,
#if MOBILEGL_PIPE_PUSH
// P2's two, and they are PUSH-ONLY on purpose: a render-state CSO exists only in a
// push build, and the pull build has to stay symbol-identical (G1) - growing this
// enum there would resize the counter arrays, the name table and FormatWindowLine
@@ -287,11 +284,9 @@ namespace MobileGL::MG_Util::PipeStats {
// wire store (VulkanRenderer::DispatchWireComputeIndirect). Their barriers count in `wibar`
// with the draws': one barrier per shader write, whichever indirect read consumes it.
WireIndirectNativeDispatches,
#endif
Count
};
#if MOBILEGL_PIPE_PUSH
// P5's GAUGES, and they are a THIRD KIND of counter rather than three more CallClass rows.
//
// A ByteClass and a CallClass are SUMS this module owns and a call site increments. These
@@ -385,7 +380,6 @@ namespace MobileGL::MG_Util::PipeStats {
// the call sites are per-frame, not per-record.
void PublishGauge(Gauge gauge, Uint64 value);
Uint64 GaugeValue(Gauge gauge);
#endif
// Memo gates. Each is a place where a backend decides "nothing moved, skip the work".
// Hit == the gate short-circuited; Miss == it fell through and did the work. The six
@@ -414,7 +408,6 @@ namespace MobileGL::MG_Util::PipeStats {
// emit records only has to add the one call.
inline constexpr Uint32 kPayloadHistogramBuckets = 24;
#if MOBILEGL_PIPE_PUSH
// Per-STAGED-BLOB size histogram, and it is a SECOND histogram rather than a wider
// kPayloadHistogramBuckets because the two answer different questions about different
// populations: the one above is the command payload of a draw (plan section 4.5.7, sizing
@@ -436,7 +429,6 @@ namespace MobileGL::MG_Util::PipeStats {
// Sample one staged blob. Called by the wire encoder where a blob is staged, behind the
// usual Enabled() predicate.
void RecordStagedBlobBytes(Uint64 bytes);
#endif
// Frames between two summary lines when MOBILEGL_PIPE_STATS=1.
inline constexpr Uint64 kDefaultSummaryFramePeriod = 120;