Files
MobileGL/MobileGL/MG_State/GLState/RenderbufferState/RenderbufferObject.cpp
T
swung0x48 eb81705130 [Fix] (Espryt): tell the backend when a frontend object dies instead of discovering it in a garbage sweep
- P2 step e2, as far as the file-ownership table lets one package take it. New frontend
  header MG_State/GLState/StateObjectDeathNotice.h carries BufferBackendOps' shape for the
  other six kinds: an ops table the backend fills in, and one entry point that takes
  {kind, lifetimeId} rather than the object, because by the time the last SharedPtr has
  dropped there is no object left to pass and the lifetime id is exactly what the client
  slot allocator resolves a handle from. Declared only under MOBILEGL_PIPE_PUSH, so the
  pull build's symbol set is untouched.
- BackendSlotTable::DestroyByLifetimeId drops the twin and returns the slot at the moment
  the object goes, instead of at the next sweep - which for a renderbuffer or a texture
  atlas is the difference between freeing the driver allocation now and freeing it 64
  creations from now. It returns the slot only when THIS table holds it: two holders of one
  kind already exist (the ScopedDirectGLESTextureBindings fixture; Magma's subsystem-4
  table shares the VertexElementsCso kind), and a table that never twinned the object must
  not free a slot the other one still names. The legacy arm keys on the frontend heap
  address, cannot answer a notice at all, and keeps the sweep - which is the announced-
  versus-discovered half of the A/B the compile-time arm exists for.
- Managers.cpp registers one dispatcher for all six kinds from ResolveEsprytSlotTablesArm(),
  i.e. exactly when the arm that can answer a notice is the arm that runs, and drops a
  notice that arrives after exit() has begun.
- FIRING it needs a destructor per class, and the P2 ownership table gives
  {Texture,Framebuffer,Sampler,VertexArray}State/* to other packages, so only ProgramObject
  and RenderbufferObject raise it here. The other four still rely on the sweep; their four
  one-line calls retire it entirely.
- Three cases pin the three halves: the slot comes back with no sweep and the notice is
  idempotent and does not free another holder's slot; a program and a renderbuffer announce
  their own death when the last SharedPtr drops and not before; and the handle arm actually
  installs a consumer, rather than the two halves each being fine on their own.
2026-09-07 23:18:09 -04:00

113 lines
4.1 KiB
C++

// MobileGL - MobileGL/MG_State/GLState/RenderbufferState/RenderbufferObject.cpp
// 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
#include "RenderbufferObject.h"
#include <MG_Util/Metrics/TextureMetrics.h>
#include <MG_State/GLState/StateObjectDeathNotice.h>
#include <atomic>
namespace MobileGL {
namespace MG_State {
namespace GLState {
namespace {
// Starts at 1 so a zero-initialized cache slot can never carry a live
// renderbuffer's id.
std::atomic<Uint64> g_nextRenderbufferLifetimeId{1};
}
Uint64 RenderbufferObject::AllocateLifetimeId() {
return g_nextRenderbufferLifetimeId.fetch_add(1, std::memory_order_relaxed);
}
RenderbufferObject::RenderbufferObject(Uint externalIndex) : m_externalIndex(externalIndex) {}
#if MOBILEGL_PIPE_PUSH
RenderbufferObject::~RenderbufferObject() {
// 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
// glDeleteRenderbuffers, which 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::Renderbuffer, m_lifetimeId);
}
#endif
Uint RenderbufferObject::GetExternalIndex() const {
return m_externalIndex;
}
Int RenderbufferObject::GetWidth() const {
return m_width;
}
Int RenderbufferObject::GetHeight() const {
return m_height;
}
TextureInternalFormat RenderbufferObject::GetInternalFormat() const {
return m_internalFormat;
}
Bool RenderbufferObject::IsAllocated() const {
return m_allocated;
}
Int RenderbufferObject::GetRedSize() const {
return m_componentSizes.Red;
}
Int RenderbufferObject::GetGreenSize() const {
return m_componentSizes.Green;
}
Int RenderbufferObject::GetBlueSize() const {
return m_componentSizes.Blue;
}
Int RenderbufferObject::GetAlphaSize() const {
return m_componentSizes.Alpha;
}
Int RenderbufferObject::GetDepthSize() const {
return m_componentSizes.Depth;
}
Int RenderbufferObject::GetStencilSize() const {
return m_componentSizes.Stencil;
}
Int RenderbufferObject::GetSamples() const {
return m_samples;
}
const ComponentSizes& RenderbufferObject::GetComponentSizes() const {
return m_componentSizes;
}
void RenderbufferObject::SetInternalFormat(TextureInternalFormat format) {
m_internalFormat = format;
m_componentSizes = MG_Util::GetComponentSizesForInternalFormat(format);
}
void RenderbufferObject::AllocateStorage(IntVec2 size) {
m_width = size.x();
m_height = size.y();
m_allocated = true;
}
void RenderbufferObject::SetSamples(Int samples) {
m_samples = samples;
}
} // namespace GLState
} // namespace MG_State
} // namespace MobileGL