mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-11 21:58:31 +09:00
[Fix] (Espryt, State): let the last four object classes announce their own death and delete the twin table's garbage collector
- e2 was landed for two of six kinds, so Texture, Framebuffer, SamplerCso and VertexElementsCso still discovered death in a sweep and ROADMAP.md:18's "delete the GC" was undelivered. TextureObjectBase (the one base every concrete texture derives from), FramebufferObject, SamplerObject and VertexArrayObject now raise NotifyStateObjectDestroyed from their destructor, on RenderbufferObject's pattern: out of line, declared only under MOBILEGL_PIPE_PUSH, so the pull build keeps its implicit destructor and its symbol set (G1 still 0 added / 0 removed / 0 renamed and 0 resized against p2/contract). - With all six announcing, BackendSlotTable loses BOTH sweep drivers: no draw tick, no creation tick, no kGCInterval / kCreationGCInterval / m_gcTick / m_creationTick. CollectGarbageIfNeeded() is empty on this arm; CollectGarbageNow() stays as an EXPLICIT collection and is the backstop for a notice that InProcessTeardown() drops. - The seven CollectGarbageIfNeeded call sites in DirectGLES.cpp keep their spelling because they are the legacy registry's driver and that arm is still compiled beside this one; the registry's body is now guarded on MOBILEGL_PIPE_LEGACY_MEMOS, so a build without the legacy arm has no collector at all. On the handle arm each site is a predicted branch. - The weak_ptr per entry stays for exactly two jobs it is honest about: ForEachLive()'s strong hand-over to ScopedDetachedTextureFramebufferAttachments, and the explicit collection. It is never an identity test; Gen is. - Tests: AProgramAndARenderbufferAnnounceTheirOwnDeath becomes EveryReKeyedObjectClassAnnouncesItsOwnDeath and drives all six classes, by membership rather than count because every texture owns a private sampler that also announces; ObjectChurnAloneDrivesTheSweep becomes AnnouncedDeathKeepsObjectChurnFromAccumulatingWithoutASweep and pins that 256 churned objects hold one live twin at a time with no CollectGarbage* call anywhere.
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
// End of Source File Header
|
||||
|
||||
#include "FramebufferObject.h"
|
||||
#include "MG_State/GLState/StateObjectDeathNotice.h"
|
||||
#include "MG_Util/Types.h"
|
||||
|
||||
#include <atomic>
|
||||
@@ -21,6 +22,20 @@ namespace MobileGL::MG_State::GLState {
|
||||
return s_nextFramebufferLifetimeId.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
FramebufferObject::~FramebufferObject() {
|
||||
// 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
|
||||
// glDelete* that only marks the name and leaves a still-bound object very much
|
||||
// alive - so it is the exact moment the backend's twin, and the driver storage
|
||||
// that twin owns, stop being reachable. The notice carries the lifetime id
|
||||
// because the object no longer exists to be passed, and because the lifetime id
|
||||
// is what the client slot allocator resolves the handle from. No-op unless a
|
||||
// backend registered the ops (a pull build declares none at all).
|
||||
NotifyStateObjectDestroyed(MG_Pipe::MGPipeKind::Framebuffer, m_lifetimeId);
|
||||
}
|
||||
#endif
|
||||
|
||||
// FramebufferAttachmentObject
|
||||
FramebufferAttachmentObject::FramebufferAttachmentObject(
|
||||
const SharedPtr<MG_State::GLState::ITextureObject>& texture, TextureUploadTarget textureUploadTarget, Int level,
|
||||
|
||||
@@ -115,6 +115,12 @@ 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,
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "SamplerObject.h"
|
||||
|
||||
#include <MG_State/GLState/Core.h>
|
||||
#include <MG_State/GLState/StateObjectDeathNotice.h>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
@@ -24,6 +25,20 @@ 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
|
||||
// glDelete* that only marks the name and leaves a still-bound object very much
|
||||
// alive - so it is the exact moment the backend's twin, and the driver storage
|
||||
// that twin owns, stop being reachable. The notice carries the lifetime id
|
||||
// because the object no longer exists to be passed, and because the lifetime id
|
||||
// is what the client slot allocator resolves the handle from. No-op unless a
|
||||
// backend registered the ops (a pull build declares none at all).
|
||||
NotifyStateObjectDestroyed(MG_Pipe::MGPipeKind::SamplerCso, m_lifetimeId);
|
||||
}
|
||||
#endif
|
||||
|
||||
void SamplerObject::BumpVersion() {
|
||||
++m_version;
|
||||
// Every setter early-outs on an unchanged value, so this only runs on a real
|
||||
|
||||
@@ -16,6 +16,12 @@ 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);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "TextureObject.h"
|
||||
#include "MG_State/GLState/Core.h"
|
||||
#include "MG_State/GLState/StateObjectDeathNotice.h"
|
||||
#include "MG_Util/Types.h"
|
||||
#include <MG_Util/Metrics/TextureMetrics.h>
|
||||
|
||||
@@ -25,6 +26,20 @@ namespace MobileGL {
|
||||
return s_nextTextureLifetimeId.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
TextureObjectBase::~TextureObjectBase() {
|
||||
// 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
|
||||
// glDelete* that only marks the name and leaves a still-bound object very much
|
||||
// alive - so it is the exact moment the backend's twin, and the driver storage
|
||||
// that twin owns, stop being reachable. The notice carries the lifetime id
|
||||
// because the object no longer exists to be passed, and because the lifetime id
|
||||
// is what the client slot allocator resolves the handle from. No-op unless a
|
||||
// backend registered the ops (a pull build declares none at all).
|
||||
NotifyStateObjectDestroyed(MG_Pipe::MGPipeKind::Texture, m_lifetimeId);
|
||||
}
|
||||
#endif
|
||||
|
||||
void TextureObjectBase::BumpShapeVersion() {
|
||||
++m_shapeVersion;
|
||||
// Shape is what mipmap-completeness is computed from, and completeness decides
|
||||
|
||||
@@ -116,7 +116,15 @@ 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;
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
#include "VertexArrayObject.h"
|
||||
|
||||
#include <MG_State/GLState/StateObjectDeathNotice.h>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
@@ -37,6 +39,20 @@ namespace MobileGL::MG_State::GLState {
|
||||
}
|
||||
}
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
VertexArrayObject::~VertexArrayObject() {
|
||||
// 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
|
||||
// glDelete* that only marks the name and leaves a still-bound object very much
|
||||
// alive - so it is the exact moment the backend's twin, and the driver storage
|
||||
// that twin owns, stop being reachable. The notice carries the lifetime id
|
||||
// because the object no longer exists to be passed, and because the lifetime id
|
||||
// is what the client slot allocator resolves the handle from. No-op unless a
|
||||
// backend registered the ops (a pull build declares none at all).
|
||||
NotifyStateObjectDestroyed(MG_Pipe::MGPipeKind::VertexElementsCso, m_lifetimeId);
|
||||
}
|
||||
#endif
|
||||
|
||||
void VertexArrayObject::EnableAttribute(Uint index) {
|
||||
if (index >= MAX_VERTEX_ATTRIBS) return;
|
||||
|
||||
|
||||
@@ -25,6 +25,12 @@ 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);
|
||||
|
||||
Reference in New Issue
Block a user