diff --git a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp index fb5e555f..c09b901d 100644 --- a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp @@ -220,7 +220,7 @@ namespace MobileGL::MG_Backend::DirectGLES { const auto& currentFBO = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(); if (currentFBO) { - for (const auto& attachment : currentFBO->GetAllAttachments()) { + for (const auto& attachment : currentFBO->GetAllAttachmentObjects()) { if (!attachment.IsTexture()) continue; auto textureObject = attachment.GetTexture(); if (textureObject) { diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.cpp b/MobileGL/MG_Backend/DirectGLES/Managers.cpp index 07e3bb86..cfdabdcc 100644 --- a/MobileGL/MG_Backend/DirectGLES/Managers.cpp +++ b/MobileGL/MG_Backend/DirectGLES/Managers.cpp @@ -787,6 +787,42 @@ namespace MobileGL::MG_Backend::DirectGLES { 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(attachmentObject.GetTextureLevel())); + } else if (attachmentObject.IsRenderbuffer()) { + const auto& renderbufferObject = attachmentObject.GetRenderbuffer(); + const auto& backendRenderbufferIt = + RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject); + SharedPtr backendRenderbufferObject; + if (backendRenderbufferIt == RenderbufferImpl::g_backendRenderbufferObjects.end()) { + backendRenderbufferObject = MakeShared(); + 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& stateFBOObject, FramebufferTarget asTarget) { #ifdef TRACY_ENABLE @@ -801,117 +837,117 @@ namespace MobileGL::MG_Backend::DirectGLES { GLenum glFBOTarget = MG_Util::ConvertFramebufferTargetToGLEnum(asTarget); Bind(asTarget); - // Handle all attachments - const auto& attachments = stateFBOObject->GetAllAttachments(); - for (SizeT i = 0; i < attachments.size(); ++i) { - const auto& attachment = attachments[i]; - if (!attachment.IsValid() || attachment.IsEmpty()) { + FramebufferAttachmentType* frontendAttachmentToSync = nullptr; + GLenum* backendAttachmentToSync = nullptr; + Int frontendAttachmentToSyncCount = 0; + switch (asTarget) { + case FramebufferTarget::Draw: { + auto &stateDrawBuffers = stateFBOObject->GetDrawBuffers(); + + // Check if still clean, skip if clean + if (memcmp(m_frontendDrawBuffers, + stateDrawBuffers.data(), + FramebufferObject::MAX_DRAW_BUFFERS * sizeof(FramebufferAttachmentType)) == 0) { + break; + } + + // Create mappings for draw buffers + int nBuffers = 0; + std::fill(m_frontendDrawBuffers, + m_frontendDrawBuffers + FramebufferObject::MAX_DRAW_BUFFERS, + FramebufferAttachmentType::None); + std::fill(m_compactedFrontendDrawBuffers, + m_compactedFrontendDrawBuffers + FramebufferObject::MAX_DRAW_BUFFERS, + FramebufferAttachmentType::None); + std::fill(m_backendDrawBuffers, + m_backendDrawBuffers + FramebufferObject::MAX_DRAW_BUFFERS, GL_NONE); + for (GLint i = 0; i < FramebufferObject::MAX_DRAW_BUFFERS; ++i) { + if (stateDrawBuffers[i] == FramebufferAttachmentType::None) { + m_frontendDrawBuffers[i] = FramebufferAttachmentType::None; + continue; + } + + m_frontendDrawBuffers[i] = stateDrawBuffers[i]; + + // Create compacted mapping + m_backendDrawBuffers[nBuffers] = GL_COLOR_ATTACHMENT0 + nBuffers; + m_compactedFrontendDrawBuffers[nBuffers] = m_frontendDrawBuffers[i]; + nBuffers++; + } + MG_External::GLES::glDrawBuffers(nBuffers, m_backendDrawBuffers); + + frontendAttachmentToSync = m_compactedFrontendDrawBuffers; + backendAttachmentToSync = m_backendDrawBuffers; + frontendAttachmentToSyncCount = nBuffers; + + break; + } + case FramebufferTarget::Read: { + auto frontendReadBuf = stateFBOObject->GetReadBuffer(); + if (frontendReadBuf == m_frontendReadBuffer) + break; + m_frontendReadBuffer = frontendReadBuf; + + // For consistency, we need to find the compacted attachment index of this read buffer + 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; + } + + // Sync texture/buffer to attachment + const auto& attachmentObjects = stateFBOObject->GetAllAttachmentObjects(); + auto& attachmentVersions = stateFBOObject->GetAllFramebufferAttachmentVersions(); + for (Int i = 0; i < frontendAttachmentToSyncCount; ++i) { + auto frontendAttachment = frontendAttachmentToSync[i]; + if (attachmentVersions[(SizeT)frontendAttachment] == m_syncedAttachmentVersions[(SizeT)frontendAttachment]) { continue; } - FramebufferAttachmentType type = static_cast(i); - GLenum glAttachment = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(type); - if (attachment.IsTexture()) { - const auto& textureObject = attachment.GetTexture(); - const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject); - 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(attachment.GetTextureLevel())); - } else if (attachment.IsRenderbuffer()) { - const auto& renderbufferObject = attachment.GetRenderbuffer(); - const auto& backendRenderbufferIt = - RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject); - SharedPtr backendRenderbufferObject; - if (backendRenderbufferIt == RenderbufferImpl::g_backendRenderbufferObjects.end()) { - backendRenderbufferObject = MakeShared(); - RenderbufferImpl::g_backendRenderbufferObjects[renderbufferObject] = backendRenderbufferObject; - } else { - backendRenderbufferObject = backendRenderbufferIt->second; - } + m_syncedAttachmentVersions[(SizeT)frontendAttachment] = attachmentVersions[(SizeT)frontendAttachment]; - backendRenderbufferObject->SyncToBackend(renderbufferObject); - backendRenderbufferObject->Bind(); - MG_External::GLES::glFramebufferRenderbuffer(glFBOTarget, glAttachment, GL_RENDERBUFFER, - backendRenderbufferObject->GetBackendRenderbufferId()); + const auto& attachmentObject = stateFBOObject->GetAttachment(frontendAttachment); + if (!attachmentObject.IsValid() || attachmentObject.IsEmpty()) { + continue; } + auto glBackendAttachment = backendAttachmentToSync[i]; + SyncAttachmentObject(glFBOTarget, attachmentObject, glBackendAttachment); } - // Handle draw buffers for DRAW_FRAMEBUFFER - if (asTarget == FramebufferTarget::Draw) { - // Create mappings for draw buffers - int nBuffers = 0; - std::fill(m_frontendDrawBuffers, - m_frontendDrawBuffers + MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS, - FramebufferAttachmentType::None); - std::fill(m_compactedFrontendDrawBuffers, - m_compactedFrontendDrawBuffers + MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS, - FramebufferAttachmentType::None); - std::fill(m_backendDrawBuffers, - m_backendDrawBuffers + MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS, GL_NONE); - auto& stateDrawBuffers = stateFBOObject->GetDrawBuffers(); - for (GLint i = 0; i < MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS; ++i) { - if (stateDrawBuffers[i] == FramebufferAttachmentType::None) { - m_frontendDrawBuffers[i] = FramebufferAttachmentType::None; - continue; - } - m_frontendDrawBuffers[i] = stateDrawBuffers[i]; - - // Create compacted mapping - m_backendDrawBuffers[nBuffers] = GL_COLOR_ATTACHMENT0 + nBuffers; - m_compactedFrontendDrawBuffers[nBuffers] = m_frontendDrawBuffers[i]; - nBuffers++; + 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]; - MG_External::GLES::glDrawBuffers(nBuffers, m_backendDrawBuffers); - stateFBOObject->ClearDrawBuffersDirtyState(); - } - // Handle read buffer for READ_FRAMEBUFFER - else if (asTarget == FramebufferTarget::Read) { - m_frontendReadBuffer = stateFBOObject->GetReadBuffer(); - GLenum frontendAtt = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(m_frontendReadBuffer); - GLenum backendAtt = GL_NONE; - const auto& readAttachment = attachments[(SizeT)m_frontendReadBuffer]; - GLenum glAttachment = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(m_frontendReadBuffer); - if (!readAttachment.IsValid() || readAttachment.IsEmpty()) { - return; + const auto& attachmentObject = stateFBOObject->GetAttachment(frontendAttachment); + if (!attachmentObject.IsValid() || attachmentObject.IsEmpty()) { + continue; } - 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(readAttachment.GetTextureLevel())); - } else if (readAttachment.IsRenderbuffer()) { - const auto& renderbufferObject = readAttachment.GetRenderbuffer(); - const auto& backendRenderbufferIt = - RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject); - SharedPtr backendRenderbufferObject; - if (backendRenderbufferIt == RenderbufferImpl::g_backendRenderbufferObjects.end()) { - backendRenderbufferObject = MakeShared(); - RenderbufferImpl::g_backendRenderbufferObjects[renderbufferObject] = backendRenderbufferObject; - } else { - backendRenderbufferObject = backendRenderbufferIt->second; - } - - backendRenderbufferObject->SyncToBackend(renderbufferObject); - backendRenderbufferObject->Bind(); - MG_External::GLES::glFramebufferRenderbuffer(glFBOTarget, glAttachment, GL_RENDERBUFFER, - backendRenderbufferObject->GetBackendRenderbufferId()); - } - MG_External::GLES::glReadBuffer(glAttachment); + auto glBackendAttachment = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(att); + SyncAttachmentObject(glFBOTarget, attachmentObject, glBackendAttachment); } } diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.h b/MobileGL/MG_Backend/DirectGLES/Managers.h index bb7b25d3..2ae1c551 100644 --- a/MobileGL/MG_Backend/DirectGLES/Managers.h +++ b/MobileGL/MG_Backend/DirectGLES/Managers.h @@ -124,6 +124,9 @@ namespace MobileGL::MG_Backend::DirectGLES { FramebufferTarget asTarget); Uint GetBackendFramebufferId() { return m_backendFBOId; } void Bind(FramebufferTarget target); + bool SyncAttachmentObject(GLenum glFBOTarget, + const MG_State::GLState::FramebufferAttachmentObject& attachmentObject, + GLenum glBackendAttachment); FramebufferAttachmentType GetCompactedAttachmentTypeAtDrawBufferIndex(Int index); private: @@ -152,6 +155,10 @@ namespace MobileGL::MG_Backend::DirectGLES { */ GLenum m_backendDrawBuffers[MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS] = {GL_NONE}; 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> diff --git a/MobileGL/MG_State/GLState/FramebufferState/FramebufferObject.cpp b/MobileGL/MG_State/GLState/FramebufferState/FramebufferObject.cpp index 3298e640..294e9aec 100644 --- a/MobileGL/MG_State/GLState/FramebufferState/FramebufferObject.cpp +++ b/MobileGL/MG_State/GLState/FramebufferState/FramebufferObject.cpp @@ -77,48 +77,49 @@ namespace MobileGL { // FramebufferObject FramebufferObject::FramebufferObject(Uint externalIndex) : m_externalIndex(externalIndex) { - m_attachments.fill(FramebufferAttachmentObject(false)); + m_attachmentObjects.fill(FramebufferAttachmentObject(false)); m_drawBuffers.fill(FramebufferAttachmentType::None); m_drawBuffers[0] = FramebufferAttachmentType::Color0; + m_attachmentVersions.fill(0); } void FramebufferObject::AttachTexture(FramebufferAttachmentType type, SharedPtr texture, int level) { - m_attachments[static_cast(type)] = FramebufferAttachmentObject(std::move(texture), level); - m_drawBuffersDirty = true; + m_attachmentObjects[static_cast(type)] = FramebufferAttachmentObject(std::move(texture), level); + BumpAttachmentVersion(type); } void FramebufferObject::AttachRenderbuffer(FramebufferAttachmentType type, std::shared_ptr renderbuffer) { - m_attachments[static_cast(type)] = FramebufferAttachmentObject(renderbuffer); - m_drawBuffersDirty = true; + m_attachmentObjects[static_cast(type)] = FramebufferAttachmentObject(renderbuffer); + BumpAttachmentVersion(type); } void FramebufferObject::Detach(FramebufferAttachmentType type) { - m_attachments[static_cast(type)] = FramebufferAttachmentObject(false); - m_drawBuffersDirty = true; + m_attachmentObjects[static_cast(type)] = FramebufferAttachmentObject(false); + BumpAttachmentVersion(type); } const FramebufferAttachmentObject& FramebufferObject::GetAttachment(FramebufferAttachmentType type) const { - return m_attachments[static_cast(type)]; + return m_attachmentObjects[static_cast(type)]; } - const FramebufferObject::FramebufferAttachmentObjectArray& FramebufferObject::GetAllAttachments() const { - return m_attachments; + const FramebufferObject::FramebufferAttachmentObjectArray& FramebufferObject::GetAllAttachmentObjects() const { + return m_attachmentObjects; } Bool FramebufferObject::CheckCompleteness() const { - if (m_attachments.empty()) { + if (m_attachmentObjects.empty()) { return false; } Int width = -1, height = -1; Int validAttachmentCount = 0; - for (SizeT i = 0; i < m_attachments.size(); ++i) { - if (!m_attachments[i].IsValid()) continue; + for (SizeT i = 0; i < m_attachmentObjects.size(); ++i) { + if (!m_attachmentObjects[i].IsValid()) continue; ++validAttachmentCount; - const auto& attachment = m_attachments[i]; + const auto& attachment = m_attachmentObjects[i]; auto attachmentSize = attachment.GetSize(); Int w = attachmentSize.x(); Int h = attachmentSize.y(); @@ -141,18 +142,9 @@ namespace MobileGL { void FramebufferObject::SetDrawBuffer(Uint index, FramebufferAttachmentType buffer) { if (m_drawBuffers[index] == buffer) return; - m_drawBuffersDirty = true; m_drawBuffers[index] = buffer; } - // void FramebufferObject::SetDrawBuffers(const Vector& buffers) { - // m_drawBuffers = buffers; - // m_drawBuffersDirty = true; - // } - // void SetDrawBuffer(Uint index, FramebufferAttachmentType buffer) { - // - // } - const FramebufferObject::FramebufferAttachmentArray& FramebufferObject::GetDrawBuffers() const { return m_drawBuffers; } @@ -160,6 +152,11 @@ namespace MobileGL { Uint FramebufferObject::GetExternalIndex() const { return m_externalIndex; } + + void FramebufferObject::BumpAttachmentVersion(FramebufferAttachmentType type) { + ++m_attachmentVersions[static_cast(type)]; + ++m_objectVersion; + } } // namespace GLState } // namespace MG_State } // namespace MobileGL diff --git a/MobileGL/MG_State/GLState/FramebufferState/FramebufferObject.h b/MobileGL/MG_State/GLState/FramebufferState/FramebufferObject.h index 55e8b087..b1cdd071 100644 --- a/MobileGL/MG_State/GLState/FramebufferState/FramebufferObject.h +++ b/MobileGL/MG_State/GLState/FramebufferState/FramebufferObject.h @@ -100,6 +100,8 @@ namespace MobileGL { using FramebufferAttachmentObjectArray = Array(FramebufferAttachmentType::FramebufferAttachmentTypeCount)>; using FramebufferAttachmentArray = Array; + using FramebufferAttachmentVersionArray = + Array(FramebufferAttachmentType::FramebufferAttachmentTypeCount)>; FramebufferObject(Uint externalIndex); @@ -108,24 +110,35 @@ namespace MobileGL { std::shared_ptr renderbuffer); void Detach(FramebufferAttachmentType type); const FramebufferAttachmentObject& GetAttachment(FramebufferAttachmentType type) const; - const FramebufferAttachmentObjectArray& GetAllAttachments() const; + const FramebufferAttachmentObjectArray& GetAllAttachmentObjects() const; Bool CheckCompleteness() const; // aka. `buffer` as in glDrawBuffers/glReadBuffers void SetDrawBuffer(Uint index, FramebufferAttachmentType buffer); - bool DrawBuffersIsDirty() const { return m_drawBuffersDirty; } - void ClearDrawBuffersDirtyState() { m_drawBuffersDirty = false; } const FramebufferAttachmentArray& GetDrawBuffers() const; void SetReadBuffer(FramebufferAttachmentType buf) { m_readBuffer = buf; } FramebufferAttachmentType GetReadBuffer() const { return m_readBuffer; } + + const FramebufferAttachmentVersionArray GetAllFramebufferAttachmentVersions() const { + return m_attachmentVersions; + } + + Uint16 GetObjectVersion() const { return m_objectVersion; } + Uint GetExternalIndex() const; private: - const Uint m_externalIndex = 0; - FramebufferAttachmentObjectArray m_attachments; - FramebufferAttachmentArray m_drawBuffers; - FramebufferAttachmentType m_readBuffer = FramebufferAttachmentType::Color0; + void BumpAttachmentVersion(FramebufferAttachmentType type); + void BumpBufferAttachVersion(); - 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