[Refactor] (MG_State/Framebuffer, MG_Backend/DirectGLES): Versioned framebuffer sync

This commit is contained in:
2026-02-03 16:50:20 +08:00
parent 751c5745b0
commit 202922613b
5 changed files with 187 additions and 134 deletions
@@ -220,7 +220,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
const auto& currentFBO = const auto& currentFBO =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(); MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
if (currentFBO) { if (currentFBO) {
for (const auto& attachment : currentFBO->GetAllAttachments()) { for (const auto& attachment : currentFBO->GetAllAttachmentObjects()) {
if (!attachment.IsTexture()) continue; if (!attachment.IsTexture()) continue;
auto textureObject = attachment.GetTexture(); auto textureObject = attachment.GetTexture();
if (textureObject) { if (textureObject) {
+120 -84
View File
@@ -787,6 +787,42 @@ namespace MobileGL::MG_Backend::DirectGLES {
MG_External::GLES::glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_backendFBOId); MG_External::GLES::glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_backendFBOId);
} }
Bool BackendFramebufferObject::SyncAttachmentObject(
GLenum glFBOTarget, const MG_State::GLState::FramebufferAttachmentObject& attachmentObject,
GLenum glBackendAttachment) {
if (attachmentObject.IsTexture()) {
const auto& textureObject = attachmentObject.GetTexture();
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
MGLOG_E("ReadBuffer: No backend texture found for FBO attachment, cannot bind texture.");
return false;
}
const auto& backendTextureObject = backendTextureIt->second;
auto glTextureTarget = MG_Util::ConvertTextureTargetToGLEnum(textureObject->GetTarget());
backendTextureObject->Bind(glTextureTarget);
MG_External::GLES::glFramebufferTexture2D(glFBOTarget, glBackendAttachment, glTextureTarget,
backendTextureObject->GetBackendTextureId(),
static_cast<GLint>(attachmentObject.GetTextureLevel()));
} else if (attachmentObject.IsRenderbuffer()) {
const auto& renderbufferObject = attachmentObject.GetRenderbuffer();
const auto& backendRenderbufferIt =
RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject);
SharedPtr<RenderbufferImpl::BackendRenderbufferObject> backendRenderbufferObject;
if (backendRenderbufferIt == RenderbufferImpl::g_backendRenderbufferObjects.end()) {
backendRenderbufferObject = MakeShared<RenderbufferImpl::BackendRenderbufferObject>();
RenderbufferImpl::g_backendRenderbufferObjects[renderbufferObject] = backendRenderbufferObject;
} else {
backendRenderbufferObject = backendRenderbufferIt->second;
}
backendRenderbufferObject->SyncToBackend(renderbufferObject);
backendRenderbufferObject->Bind();
MG_External::GLES::glFramebufferRenderbuffer(glFBOTarget, glBackendAttachment, GL_RENDERBUFFER,
backendRenderbufferObject->GetBackendRenderbufferId());
}
return true;
}
void BackendFramebufferObject::SyncToBackend(SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject, void BackendFramebufferObject::SyncToBackend(SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject,
FramebufferTarget asTarget) { FramebufferTarget asTarget) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
@@ -801,60 +837,31 @@ namespace MobileGL::MG_Backend::DirectGLES {
GLenum glFBOTarget = MG_Util::ConvertFramebufferTargetToGLEnum(asTarget); GLenum glFBOTarget = MG_Util::ConvertFramebufferTargetToGLEnum(asTarget);
Bind(asTarget); Bind(asTarget);
// Handle all attachments FramebufferAttachmentType* frontendAttachmentToSync = nullptr;
const auto& attachments = stateFBOObject->GetAllAttachments(); GLenum* backendAttachmentToSync = nullptr;
for (SizeT i = 0; i < attachments.size(); ++i) { Int frontendAttachmentToSyncCount = 0;
const auto& attachment = attachments[i]; switch (asTarget) {
if (!attachment.IsValid() || attachment.IsEmpty()) { case FramebufferTarget::Draw: {
continue; auto &stateDrawBuffers = stateFBOObject->GetDrawBuffers();
}
FramebufferAttachmentType type = static_cast<FramebufferAttachmentType>(i); // Check if still clean, skip if clean
GLenum glAttachment = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(type); if (memcmp(m_frontendDrawBuffers,
if (attachment.IsTexture()) { stateDrawBuffers.data(),
const auto& textureObject = attachment.GetTexture(); FramebufferObject::MAX_DRAW_BUFFERS * sizeof(FramebufferAttachmentType)) == 0) {
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject); break;
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
MGLOG_E("No backend texture found for FBO attachment, cannot bind texture.");
continue;
}
const auto& backendTextureObject = backendTextureIt->second;
auto glTextureTarget = MG_Util::ConvertTextureTargetToGLEnum(textureObject->GetTarget());
backendTextureObject->Bind(glTextureTarget);
MG_External::GLES::glFramebufferTexture2D(glFBOTarget, glAttachment, glTextureTarget,
backendTextureObject->GetBackendTextureId(),
static_cast<GLint>(attachment.GetTextureLevel()));
} else if (attachment.IsRenderbuffer()) {
const auto& renderbufferObject = attachment.GetRenderbuffer();
const auto& backendRenderbufferIt =
RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject);
SharedPtr<RenderbufferImpl::BackendRenderbufferObject> backendRenderbufferObject;
if (backendRenderbufferIt == RenderbufferImpl::g_backendRenderbufferObjects.end()) {
backendRenderbufferObject = MakeShared<RenderbufferImpl::BackendRenderbufferObject>();
RenderbufferImpl::g_backendRenderbufferObjects[renderbufferObject] = backendRenderbufferObject;
} else {
backendRenderbufferObject = backendRenderbufferIt->second;
} }
backendRenderbufferObject->SyncToBackend(renderbufferObject);
backendRenderbufferObject->Bind();
MG_External::GLES::glFramebufferRenderbuffer(glFBOTarget, glAttachment, GL_RENDERBUFFER,
backendRenderbufferObject->GetBackendRenderbufferId());
}
}
// Handle draw buffers for DRAW_FRAMEBUFFER
if (asTarget == FramebufferTarget::Draw) {
// Create mappings for draw buffers // Create mappings for draw buffers
int nBuffers = 0; int nBuffers = 0;
std::fill(m_frontendDrawBuffers, std::fill(m_frontendDrawBuffers,
m_frontendDrawBuffers + MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS, m_frontendDrawBuffers + FramebufferObject::MAX_DRAW_BUFFERS,
FramebufferAttachmentType::None); FramebufferAttachmentType::None);
std::fill(m_compactedFrontendDrawBuffers, std::fill(m_compactedFrontendDrawBuffers,
m_compactedFrontendDrawBuffers + MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS, m_compactedFrontendDrawBuffers + FramebufferObject::MAX_DRAW_BUFFERS,
FramebufferAttachmentType::None); FramebufferAttachmentType::None);
std::fill(m_backendDrawBuffers, std::fill(m_backendDrawBuffers,
m_backendDrawBuffers + MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS, GL_NONE); m_backendDrawBuffers + FramebufferObject::MAX_DRAW_BUFFERS, GL_NONE);
auto& stateDrawBuffers = stateFBOObject->GetDrawBuffers(); for (GLint i = 0; i < FramebufferObject::MAX_DRAW_BUFFERS; ++i) {
for (GLint i = 0; i < MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS; ++i) {
if (stateDrawBuffers[i] == FramebufferAttachmentType::None) { if (stateDrawBuffers[i] == FramebufferAttachmentType::None) {
m_frontendDrawBuffers[i] = FramebufferAttachmentType::None; m_frontendDrawBuffers[i] = FramebufferAttachmentType::None;
continue; continue;
@@ -867,51 +874,80 @@ namespace MobileGL::MG_Backend::DirectGLES {
m_compactedFrontendDrawBuffers[nBuffers] = m_frontendDrawBuffers[i]; m_compactedFrontendDrawBuffers[nBuffers] = m_frontendDrawBuffers[i];
nBuffers++; nBuffers++;
} }
MG_External::GLES::glDrawBuffers(nBuffers, m_backendDrawBuffers); MG_External::GLES::glDrawBuffers(nBuffers, m_backendDrawBuffers);
stateFBOObject->ClearDrawBuffersDirtyState();
frontendAttachmentToSync = m_compactedFrontendDrawBuffers;
backendAttachmentToSync = m_backendDrawBuffers;
frontendAttachmentToSyncCount = nBuffers;
break;
} }
// Handle read buffer for READ_FRAMEBUFFER case FramebufferTarget::Read: {
else if (asTarget == FramebufferTarget::Read) { auto frontendReadBuf = stateFBOObject->GetReadBuffer();
m_frontendReadBuffer = stateFBOObject->GetReadBuffer(); if (frontendReadBuf == m_frontendReadBuffer)
GLenum frontendAtt = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(m_frontendReadBuffer); break;
GLenum backendAtt = GL_NONE; m_frontendReadBuffer = frontendReadBuf;
const auto& readAttachment = attachments[(SizeT)m_frontendReadBuffer];
GLenum glAttachment = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(m_frontendReadBuffer); // For consistency, we need to find the compacted attachment index of this read buffer
if (!readAttachment.IsValid() || readAttachment.IsEmpty()) { auto it = std::find(
m_compactedFrontendDrawBuffers,
m_compactedFrontendDrawBuffers + FramebufferObject::MAX_DRAW_BUFFERS,
frontendReadBuf);
Bool notFound = (it == m_compactedFrontendDrawBuffers + FramebufferObject::MAX_DRAW_BUFFERS);
if (notFound) {
MGLOG_D("%s: read buffer not found in draw buffer, use as in frontend", __func__);
}
auto backendReadBuffer = notFound ? frontendReadBuf : *it;
GLenum glBackendReadBuffer = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(backendReadBuffer);
if (m_backendReadBuffer == glBackendReadBuffer)
break;
m_backendReadBuffer = glBackendReadBuffer;
MG_External::GLES::glReadBuffer(glBackendReadBuffer);
frontendAttachmentToSync = &m_frontendReadBuffer;
backendAttachmentToSync = &m_backendReadBuffer;
frontendAttachmentToSyncCount = 1;
break;
}
default:
MOBILEGL_ASSERT(false, "%s: Unreachable!", __func__);
return; return;
} }
if (readAttachment.IsTexture()) {
const auto& textureObject = readAttachment.GetTexture();
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
MGLOG_E("ReadBuffer: No backend texture found for FBO attachment, cannot bind texture.");
return;
}
const auto& backendTextureObject = backendTextureIt->second;
auto glTextureTarget = MG_Util::ConvertTextureTargetToGLEnum(textureObject->GetTarget());
backendTextureObject->Bind(glTextureTarget);
MG_External::GLES::glFramebufferTexture2D(glFBOTarget, glAttachment, glTextureTarget,
backendTextureObject->GetBackendTextureId(),
static_cast<GLint>(readAttachment.GetTextureLevel()));
} else if (readAttachment.IsRenderbuffer()) {
const auto& renderbufferObject = readAttachment.GetRenderbuffer();
const auto& backendRenderbufferIt =
RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject);
SharedPtr<RenderbufferImpl::BackendRenderbufferObject> backendRenderbufferObject;
if (backendRenderbufferIt == RenderbufferImpl::g_backendRenderbufferObjects.end()) {
backendRenderbufferObject = MakeShared<RenderbufferImpl::BackendRenderbufferObject>();
RenderbufferImpl::g_backendRenderbufferObjects[renderbufferObject] = backendRenderbufferObject;
} else {
backendRenderbufferObject = backendRenderbufferIt->second;
}
backendRenderbufferObject->SyncToBackend(renderbufferObject); // Sync texture/buffer to attachment
backendRenderbufferObject->Bind(); const auto& attachmentObjects = stateFBOObject->GetAllAttachmentObjects();
MG_External::GLES::glFramebufferRenderbuffer(glFBOTarget, glAttachment, GL_RENDERBUFFER, auto& attachmentVersions = stateFBOObject->GetAllFramebufferAttachmentVersions();
backendRenderbufferObject->GetBackendRenderbufferId()); for (Int i = 0; i < frontendAttachmentToSyncCount; ++i) {
auto frontendAttachment = frontendAttachmentToSync[i];
if (attachmentVersions[(SizeT)frontendAttachment] == m_syncedAttachmentVersions[(SizeT)frontendAttachment]) {
continue;
} }
MG_External::GLES::glReadBuffer(glAttachment); m_syncedAttachmentVersions[(SizeT)frontendAttachment] = attachmentVersions[(SizeT)frontendAttachment];
const auto& attachmentObject = stateFBOObject->GetAttachment(frontendAttachment);
if (!attachmentObject.IsValid() || attachmentObject.IsEmpty()) {
continue;
}
auto glBackendAttachment = backendAttachmentToSync[i];
SyncAttachmentObject(glFBOTarget, attachmentObject, glBackendAttachment);
}
FramebufferAttachmentType auxAtt[] = { FramebufferAttachmentType::Depth, FramebufferAttachmentType::Stencil };
for (auto & att : auxAtt) {
auto frontendAttachment = att;
if (attachmentVersions[(SizeT)frontendAttachment] == m_syncedAttachmentVersions[(SizeT)frontendAttachment]) {
continue;
}
m_syncedAttachmentVersions[(SizeT)frontendAttachment] = attachmentVersions[(SizeT)frontendAttachment];
const auto& attachmentObject = stateFBOObject->GetAttachment(frontendAttachment);
if (!attachmentObject.IsValid() || attachmentObject.IsEmpty()) {
continue;
}
auto glBackendAttachment = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(att);
SyncAttachmentObject(glFBOTarget, attachmentObject, glBackendAttachment);
} }
} }
@@ -124,6 +124,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
FramebufferTarget asTarget); FramebufferTarget asTarget);
Uint GetBackendFramebufferId() { return m_backendFBOId; } Uint GetBackendFramebufferId() { return m_backendFBOId; }
void Bind(FramebufferTarget target); void Bind(FramebufferTarget target);
bool SyncAttachmentObject(GLenum glFBOTarget,
const MG_State::GLState::FramebufferAttachmentObject& attachmentObject,
GLenum glBackendAttachment);
FramebufferAttachmentType GetCompactedAttachmentTypeAtDrawBufferIndex(Int index); FramebufferAttachmentType GetCompactedAttachmentTypeAtDrawBufferIndex(Int index);
private: private:
@@ -152,6 +155,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
*/ */
GLenum m_backendDrawBuffers[MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS] = {GL_NONE}; GLenum m_backendDrawBuffers[MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS] = {GL_NONE};
FramebufferAttachmentType m_frontendReadBuffer = FramebufferAttachmentType::Color0; FramebufferAttachmentType m_frontendReadBuffer = FramebufferAttachmentType::Color0;
GLenum m_backendReadBuffer = GL_COLOR_ATTACHMENT0;
using FramebufferObject = MG_State::GLState::FramebufferObject;
FramebufferObject::FramebufferAttachmentVersionArray m_syncedAttachmentVersions = {0};
}; };
extern UnorderedMap<SharedPtr<MG_State::GLState::FramebufferObject>, SharedPtr<BackendFramebufferObject>> extern UnorderedMap<SharedPtr<MG_State::GLState::FramebufferObject>, SharedPtr<BackendFramebufferObject>>
@@ -77,48 +77,49 @@ namespace MobileGL {
// FramebufferObject // FramebufferObject
FramebufferObject::FramebufferObject(Uint externalIndex) : m_externalIndex(externalIndex) { FramebufferObject::FramebufferObject(Uint externalIndex) : m_externalIndex(externalIndex) {
m_attachments.fill(FramebufferAttachmentObject(false)); m_attachmentObjects.fill(FramebufferAttachmentObject(false));
m_drawBuffers.fill(FramebufferAttachmentType::None); m_drawBuffers.fill(FramebufferAttachmentType::None);
m_drawBuffers[0] = FramebufferAttachmentType::Color0; m_drawBuffers[0] = FramebufferAttachmentType::Color0;
m_attachmentVersions.fill(0);
} }
void FramebufferObject::AttachTexture(FramebufferAttachmentType type, SharedPtr<ITextureObject> texture, void FramebufferObject::AttachTexture(FramebufferAttachmentType type, SharedPtr<ITextureObject> texture,
int level) { int level) {
m_attachments[static_cast<SizeT>(type)] = FramebufferAttachmentObject(std::move(texture), level); m_attachmentObjects[static_cast<SizeT>(type)] = FramebufferAttachmentObject(std::move(texture), level);
m_drawBuffersDirty = true; BumpAttachmentVersion(type);
} }
void FramebufferObject::AttachRenderbuffer(FramebufferAttachmentType type, void FramebufferObject::AttachRenderbuffer(FramebufferAttachmentType type,
std::shared_ptr<RenderbufferObject> renderbuffer) { std::shared_ptr<RenderbufferObject> renderbuffer) {
m_attachments[static_cast<SizeT>(type)] = FramebufferAttachmentObject(renderbuffer); m_attachmentObjects[static_cast<SizeT>(type)] = FramebufferAttachmentObject(renderbuffer);
m_drawBuffersDirty = true; BumpAttachmentVersion(type);
} }
void FramebufferObject::Detach(FramebufferAttachmentType type) { void FramebufferObject::Detach(FramebufferAttachmentType type) {
m_attachments[static_cast<SizeT>(type)] = FramebufferAttachmentObject(false); m_attachmentObjects[static_cast<SizeT>(type)] = FramebufferAttachmentObject(false);
m_drawBuffersDirty = true; BumpAttachmentVersion(type);
} }
const FramebufferAttachmentObject& FramebufferObject::GetAttachment(FramebufferAttachmentType type) const { const FramebufferAttachmentObject& FramebufferObject::GetAttachment(FramebufferAttachmentType type) const {
return m_attachments[static_cast<SizeT>(type)]; return m_attachmentObjects[static_cast<SizeT>(type)];
} }
const FramebufferObject::FramebufferAttachmentObjectArray& FramebufferObject::GetAllAttachments() const { const FramebufferObject::FramebufferAttachmentObjectArray& FramebufferObject::GetAllAttachmentObjects() const {
return m_attachments; return m_attachmentObjects;
} }
Bool FramebufferObject::CheckCompleteness() const { Bool FramebufferObject::CheckCompleteness() const {
if (m_attachments.empty()) { if (m_attachmentObjects.empty()) {
return false; return false;
} }
Int width = -1, height = -1; Int width = -1, height = -1;
Int validAttachmentCount = 0; Int validAttachmentCount = 0;
for (SizeT i = 0; i < m_attachments.size(); ++i) { for (SizeT i = 0; i < m_attachmentObjects.size(); ++i) {
if (!m_attachments[i].IsValid()) continue; if (!m_attachmentObjects[i].IsValid()) continue;
++validAttachmentCount; ++validAttachmentCount;
const auto& attachment = m_attachments[i]; const auto& attachment = m_attachmentObjects[i];
auto attachmentSize = attachment.GetSize(); auto attachmentSize = attachment.GetSize();
Int w = attachmentSize.x(); Int w = attachmentSize.x();
Int h = attachmentSize.y(); Int h = attachmentSize.y();
@@ -141,18 +142,9 @@ namespace MobileGL {
void FramebufferObject::SetDrawBuffer(Uint index, FramebufferAttachmentType buffer) { void FramebufferObject::SetDrawBuffer(Uint index, FramebufferAttachmentType buffer) {
if (m_drawBuffers[index] == buffer) return; if (m_drawBuffers[index] == buffer) return;
m_drawBuffersDirty = true;
m_drawBuffers[index] = buffer; m_drawBuffers[index] = buffer;
} }
// void FramebufferObject::SetDrawBuffers(const Vector<FramebufferAttachmentType>& buffers) {
// m_drawBuffers = buffers;
// m_drawBuffersDirty = true;
// }
// void SetDrawBuffer(Uint index, FramebufferAttachmentType buffer) {
//
// }
const FramebufferObject::FramebufferAttachmentArray& FramebufferObject::GetDrawBuffers() const { const FramebufferObject::FramebufferAttachmentArray& FramebufferObject::GetDrawBuffers() const {
return m_drawBuffers; return m_drawBuffers;
} }
@@ -160,6 +152,11 @@ namespace MobileGL {
Uint FramebufferObject::GetExternalIndex() const { Uint FramebufferObject::GetExternalIndex() const {
return m_externalIndex; return m_externalIndex;
} }
void FramebufferObject::BumpAttachmentVersion(FramebufferAttachmentType type) {
++m_attachmentVersions[static_cast<SizeT>(type)];
++m_objectVersion;
}
} // namespace GLState } // namespace GLState
} // namespace MG_State } // namespace MG_State
} // namespace MobileGL } // namespace MobileGL
@@ -100,6 +100,8 @@ namespace MobileGL {
using FramebufferAttachmentObjectArray = using FramebufferAttachmentObjectArray =
Array<FramebufferAttachmentObject, static_cast<SizeT>(FramebufferAttachmentType::FramebufferAttachmentTypeCount)>; Array<FramebufferAttachmentObject, static_cast<SizeT>(FramebufferAttachmentType::FramebufferAttachmentTypeCount)>;
using FramebufferAttachmentArray = Array<FramebufferAttachmentType, MAX_DRAW_BUFFERS>; using FramebufferAttachmentArray = Array<FramebufferAttachmentType, MAX_DRAW_BUFFERS>;
using FramebufferAttachmentVersionArray =
Array<Uint16, static_cast<SizeT>(FramebufferAttachmentType::FramebufferAttachmentTypeCount)>;
FramebufferObject(Uint externalIndex); FramebufferObject(Uint externalIndex);
@@ -108,24 +110,35 @@ namespace MobileGL {
std::shared_ptr<RenderbufferObject> renderbuffer); std::shared_ptr<RenderbufferObject> renderbuffer);
void Detach(FramebufferAttachmentType type); void Detach(FramebufferAttachmentType type);
const FramebufferAttachmentObject& GetAttachment(FramebufferAttachmentType type) const; const FramebufferAttachmentObject& GetAttachment(FramebufferAttachmentType type) const;
const FramebufferAttachmentObjectArray& GetAllAttachments() const; const FramebufferAttachmentObjectArray& GetAllAttachmentObjects() const;
Bool CheckCompleteness() const; Bool CheckCompleteness() const;
// aka. `buffer` as in glDrawBuffers/glReadBuffers // aka. `buffer` as in glDrawBuffers/glReadBuffers
void SetDrawBuffer(Uint index, FramebufferAttachmentType buffer); void SetDrawBuffer(Uint index, FramebufferAttachmentType buffer);
bool DrawBuffersIsDirty() const { return m_drawBuffersDirty; }
void ClearDrawBuffersDirtyState() { m_drawBuffersDirty = false; }
const FramebufferAttachmentArray& GetDrawBuffers() const; const FramebufferAttachmentArray& GetDrawBuffers() const;
void SetReadBuffer(FramebufferAttachmentType buf) { m_readBuffer = buf; } void SetReadBuffer(FramebufferAttachmentType buf) { m_readBuffer = buf; }
FramebufferAttachmentType GetReadBuffer() const { return m_readBuffer; } FramebufferAttachmentType GetReadBuffer() const { return m_readBuffer; }
const FramebufferAttachmentVersionArray GetAllFramebufferAttachmentVersions() const {
return m_attachmentVersions;
}
Uint16 GetObjectVersion() const { return m_objectVersion; }
Uint GetExternalIndex() const; Uint GetExternalIndex() const;
private: private:
const Uint m_externalIndex = 0; void BumpAttachmentVersion(FramebufferAttachmentType type);
FramebufferAttachmentObjectArray m_attachments; void BumpBufferAttachVersion();
FramebufferAttachmentArray m_drawBuffers;
FramebufferAttachmentType m_readBuffer = FramebufferAttachmentType::Color0;
Bool m_drawBuffersDirty = false; const Uint m_externalIndex = 0;
FramebufferAttachmentObjectArray m_attachmentObjects;
FramebufferAttachmentVersionArray m_attachmentVersions;
FramebufferAttachmentArray m_drawBuffers; // Probably no versioning needed for this, just check equality
FramebufferAttachmentType m_readBuffer = FramebufferAttachmentType::Color0; // ditto
// This version will bump when draw/read buffer changes (by `glDrawBuffer(s)`/`glReadBuffer`)
Uint16 m_objectVersion = 0;
}; };
} // namespace GLState } // namespace GLState