[Fix] (MG_Backend/DirectGLES): re-implement FBO sync, attachment remapping

This commit is contained in:
2026-02-04 14:42:48 +08:00
parent f4ce17af51
commit 1b47f1bb92
3 changed files with 114 additions and 105 deletions
+60 -78
View File
@@ -998,44 +998,26 @@ namespace MobileGL::MG_Backend::DirectGLES {
RenderStateImpl::SyncRenderState(); RenderStateImpl::SyncRenderState();
BindCurrentFBO(FramebufferTarget::Draw); BindCurrentFBO(FramebufferTarget::Draw);
auto backendFBOIt = FramebufferImpl::g_backendFramebufferObjects.find( // auto backendFBOIt = FramebufferImpl::g_backendFramebufferObjects.find(
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject()); // MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject());
if (backendFBOIt == FramebufferImpl::g_backendFramebufferObjects.end()) { // if (backendFBOIt == FramebufferImpl::g_backendFramebufferObjects.end()) {
MGLOG_E("No backend FBO found for current draw FBO, cannot clear buffer."); // MGLOG_E("No backend FBO found for current draw FBO, cannot clear buffer.");
return; // return;
} // }
auto backendFBO = backendFBOIt->second; // auto backendFBO = backendFBOIt->second;
GLint realDrawbuffer = drawbuffer; GLint realDrawbuffer = drawbuffer;
if (buffer == GL_COLOR) { if (buffer == GL_COLOR) {
auto& stateDrawBuffers = backendFBOIt->first->GetDrawBuffers(); // auto& stateDrawBuffers = backendFBOIt->first->GetDrawBuffers();
if (drawbuffer < 0 || drawbuffer >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) { if (drawbuffer < 0 || drawbuffer >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
MGLOG_E("Invalid drawbuffer index: %d", drawbuffer); MGLOG_E("Invalid drawbuffer index: %d", drawbuffer);
return; return;
} }
FramebufferAttachmentType attachmentType = stateDrawBuffers[drawbuffer]; // since `drawbuffer` indicates an index into draw buffer array,
// using GL value directly is OK.
if (attachmentType == FramebufferAttachmentType::None) {
MGLOG_D("Drawbuffer %d has no attachment, skipping clear", drawbuffer);
return;
}
Bool found = false;
for (int i = 0; i < MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS; i++) {
if (backendFBO->GetCompactedAttachmentTypeAtDrawBufferIndex(i) == attachmentType) {
realDrawbuffer = i;
found = true;
break;
}
}
if (!found) {
MGLOG_E("Failed to find backend drawbuffer for attachment type: %d", static_cast<int>(attachmentType));
return;
}
} else if (buffer == GL_DEPTH || buffer == GL_STENCIL) { } else if (buffer == GL_DEPTH || buffer == GL_STENCIL) {
if (drawbuffer != 0) { if (drawbuffer != 0) {
MGLOG_W("Depth/stencil clear buffer index must be 0, got %d. Using 0.", drawbuffer); MGLOG_W("Depth/stencil clear buffer index must be 0, got %d. Using 0.", drawbuffer);
@@ -1051,44 +1033,44 @@ namespace MobileGL::MG_Backend::DirectGLES {
RenderStateImpl::SyncRenderState(); RenderStateImpl::SyncRenderState();
BindCurrentFBO(FramebufferTarget::Draw); BindCurrentFBO(FramebufferTarget::Draw);
auto backendFBOIt = FramebufferImpl::g_backendFramebufferObjects.find( // auto backendFBOIt = FramebufferImpl::g_backendFramebufferObjects.find(
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject()); // MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject());
if (backendFBOIt == FramebufferImpl::g_backendFramebufferObjects.end()) { // if (backendFBOIt == FramebufferImpl::g_backendFramebufferObjects.end()) {
MGLOG_E("No backend FBO found for current draw FBO, cannot clear buffer."); // MGLOG_E("No backend FBO found for current draw FBO, cannot clear buffer.");
return; // return;
} // }
auto backendFBO = backendFBOIt->second; // auto backendFBO = backendFBOIt->second;
GLint realDrawbuffer = drawbuffer; GLint realDrawbuffer = drawbuffer;
if (buffer == GL_COLOR) { if (buffer == GL_COLOR) {
auto& stateDrawBuffers = backendFBOIt->first->GetDrawBuffers(); // auto& stateDrawBuffers = backendFBOIt->first->GetDrawBuffers();
if (drawbuffer < 0 || drawbuffer >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) { if (drawbuffer < 0 || drawbuffer >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
MGLOG_E("Invalid drawbuffer index: %d", drawbuffer); MGLOG_E("Invalid drawbuffer index: %d", drawbuffer);
return; return;
} }
FramebufferAttachmentType attachmentType = stateDrawBuffers[drawbuffer]; // FramebufferAttachmentType attachmentType = stateDrawBuffers[drawbuffer];
if (attachmentType == FramebufferAttachmentType::None) { // if (attachmentType == FramebufferAttachmentType::None) {
MGLOG_D("Drawbuffer %d has no attachment, skipping clear", drawbuffer); // MGLOG_D("Drawbuffer %d has no attachment, skipping clear", drawbuffer);
return; // return;
} // }
Bool found = false; // Bool found = false;
for (int i = 0; i < MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS; i++) { // for (int i = 0; i < MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS; i++) {
if (backendFBO->GetCompactedAttachmentTypeAtDrawBufferIndex(i) == attachmentType) { // if (backendFBO->GetCompactedAttachmentTypeAtDrawBufferIndex(i) == attachmentType) {
realDrawbuffer = i; // realDrawbuffer = i;
found = true; // found = true;
break; // break;
} // }
} // }
if (!found) { // if (!found) {
MGLOG_E("Failed to find backend drawbuffer for attachment type: %d", static_cast<int>(attachmentType)); // MGLOG_E("Failed to find backend drawbuffer for attachment type: %d", static_cast<int>(attachmentType));
return; // return;
} // }
} else if (buffer == GL_STENCIL) { } else if (buffer == GL_STENCIL) {
if (drawbuffer != 0) { if (drawbuffer != 0) {
MGLOG_W("Stencil clear buffer index must be 0, got %d. Using 0.", drawbuffer); MGLOG_W("Stencil clear buffer index must be 0, got %d. Using 0.", drawbuffer);
@@ -1105,44 +1087,44 @@ namespace MobileGL::MG_Backend::DirectGLES {
RenderStateImpl::SyncRenderState(); RenderStateImpl::SyncRenderState();
BindCurrentFBO(FramebufferTarget::Draw); BindCurrentFBO(FramebufferTarget::Draw);
auto backendFBOIt = FramebufferImpl::g_backendFramebufferObjects.find( // auto backendFBOIt = FramebufferImpl::g_backendFramebufferObjects.find(
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject()); // MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject());
if (backendFBOIt == FramebufferImpl::g_backendFramebufferObjects.end()) { // if (backendFBOIt == FramebufferImpl::g_backendFramebufferObjects.end()) {
MGLOG_E("No backend FBO found for current draw FBO, cannot clear buffer."); // MGLOG_E("No backend FBO found for current draw FBO, cannot clear buffer.");
return; // return;
} // }
auto backendFBO = backendFBOIt->second; // auto backendFBO = backendFBOIt->second;
GLint realDrawbuffer = drawbuffer; GLint realDrawbuffer = drawbuffer;
if (buffer == GL_COLOR) { if (buffer == GL_COLOR) {
auto& stateDrawBuffers = backendFBOIt->first->GetDrawBuffers(); // auto& stateDrawBuffers = backendFBOIt->first->GetDrawBuffers();
if (drawbuffer < 0 || drawbuffer >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) { if (drawbuffer < 0 || drawbuffer >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
MGLOG_E("Invalid drawbuffer index: %d", drawbuffer); MGLOG_E("Invalid drawbuffer index: %d", drawbuffer);
return; return;
} }
FramebufferAttachmentType attachmentType = stateDrawBuffers[drawbuffer]; // FramebufferAttachmentType attachmentType = stateDrawBuffers[drawbuffer];
if (attachmentType == FramebufferAttachmentType::None) { // if (attachmentType == FramebufferAttachmentType::None) {
MGLOG_D("Drawbuffer %d has no attachment, skipping clear", drawbuffer); // MGLOG_D("Drawbuffer %d has no attachment, skipping clear", drawbuffer);
return; // return;
} // }
Bool found = false; // Bool found = false;
for (int i = 0; i < MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS; i++) { // for (int i = 0; i < MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS; i++) {
if (backendFBO->GetCompactedAttachmentTypeAtDrawBufferIndex(i) == attachmentType) { // if (backendFBO->GetCompactedAttachmentTypeAtDrawBufferIndex(i) == attachmentType) {
realDrawbuffer = i; // realDrawbuffer = i;
found = true; // found = true;
break; // break;
} // }
} // }
if (!found) { // if (!found) {
MGLOG_E("Failed to find backend drawbuffer for attachment type: %d", static_cast<int>(attachmentType)); // MGLOG_E("Failed to find backend drawbuffer for attachment type: %d", static_cast<int>(attachmentType));
return; // return;
} // }
} else { } else {
MGLOG_E("ClearBufferuiv can only be used with GL_COLOR buffer, got %s", MGLOG_E("ClearBufferuiv can only be used with GL_COLOR buffer, got %s",
MG_Util::ConvertGLEnumToString(buffer).c_str()); MG_Util::ConvertGLEnumToString(buffer).c_str());
+51 -16
View File
@@ -850,24 +850,47 @@ namespace MobileGL::MG_Backend::DirectGLES {
GLenum glFBOTarget = MG_Util::ConvertFramebufferTargetToGLEnum(asTarget); GLenum glFBOTarget = MG_Util::ConvertFramebufferTargetToGLEnum(asTarget);
Bind(asTarget); Bind(asTarget);
// connect attachments (set buffers) // -------------------- Connect attachments (set buffers) -----------------------
// TODO: remapping // 1. Remap draw buffers
auto& stateDrawBuffers = stateFBOObject->GetDrawBuffers(); auto& stateDrawBuffers = stateFBOObject->GetDrawBuffers();
Bool drawBufferDirty = false; Bool drawBufferClean = false;
for (GLint i = 0; i < MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS; ++i) { if (memcmp(m_frontendDrawBuffers, stateDrawBuffers.data(),
auto currentBuf = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(stateDrawBuffers[i]); FramebufferObject::MAX_DRAW_BUFFERS * sizeof(FramebufferAttachmentType)) == 0) {
if (m_backendDrawBuffers[i] != currentBuf) drawBufferClean = true;
drawBufferDirty = true;
m_backendDrawBuffers[i] = currentBuf;
} }
if (drawBufferDirty)
MG_External::GLES::glDrawBuffers(MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS, m_backendDrawBuffers);
auto currentReadBuf = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(stateFBOObject->GetReadBuffer()); if (!drawBufferClean) {
if (m_backendReadBuffer != currentReadBuf) memcpy(m_frontendDrawBuffers, stateDrawBuffers.data(),
MG_External::GLES::glReadBuffer(m_backendReadBuffer); FramebufferObject::MAX_DRAW_BUFFERS * sizeof(FramebufferAttachmentType));
std::fill(m_backendDrawBuffers, m_backendDrawBuffers + FramebufferObject::MAX_DRAW_BUFFERS, GL_NONE);
int nEffectiveBuffers = 0;
for (GLint i = 0; i < FramebufferObject::MAX_DRAW_BUFFERS; ++i) {
if (stateDrawBuffers[i] == FramebufferAttachmentType::None) {
m_backendDrawBuffers[i] = GL_NONE;
continue;
}
// attach texture to fbo // Create compacted mapping
m_backendDrawBuffers[i] = GL_COLOR_ATTACHMENT0 + i;
nEffectiveBuffers = i + 1;
}
MG_External::GLES::glDrawBuffers(nEffectiveBuffers, m_backendDrawBuffers);
}
// 2. Remap read buffer
auto frontendReadBuf = stateFBOObject->GetReadBuffer();
if (frontendReadBuf != m_frontendReadBuffer) {
m_frontendReadBuffer = frontendReadBuf;
GLenum glBackendReadBuffer = GetBackendAttachmentType(frontendReadBuf);
if (m_backendReadBuffer != glBackendReadBuffer) {
m_backendReadBuffer = glBackendReadBuffer;
MG_External::GLES::glReadBuffer(glBackendReadBuffer);
}
}
// -------------------- Attach texture to backend FBO -----------------------
// TODO: attach according to remapped // TODO: attach according to remapped
const auto& attachments = stateFBOObject->GetAllAttachmentObjects(); const auto& attachments = stateFBOObject->GetAllAttachmentObjects();
const auto& attachmentVersions = stateFBOObject->GetAllFramebufferAttachmentVersions(); const auto& attachmentVersions = stateFBOObject->GetAllFramebufferAttachmentVersions();
@@ -885,8 +908,20 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
} }
FramebufferAttachmentType BackendFramebufferObject::GetCompactedAttachmentTypeAtDrawBufferIndex(Int index) { GLenum BackendFramebufferObject::GetBackendAttachmentType(FramebufferAttachmentType frontendAtt) const {
return m_compactedFrontendDrawBuffers[index]; GLenum glBackendReadBuffer = GL_NONE;
auto it = std::find(m_frontendDrawBuffers,
m_frontendDrawBuffers + FramebufferObject::MAX_DRAW_BUFFERS, frontendAtt);
Bool notFound = (it == m_frontendDrawBuffers + FramebufferObject::MAX_DRAW_BUFFERS);
if (notFound) {
MGLOG_D("%s: frontendAtt not found in draw buffer (probably not remapped), just use the same as frontend", __func__);
glBackendReadBuffer = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(frontendAtt);
} else {
MGLOG_D("%s: frontendAtt found in draw buffer, keep it consistent as in read buffers", __func__);
auto index = std::distance(m_frontendDrawBuffers, it);
glBackendReadBuffer = m_backendDrawBuffers[index];
}
return glBackendReadBuffer;
} }
UnorderedMap<SharedPtr<MG_State::GLState::FramebufferObject>, SharedPtr<BackendFramebufferObject>> UnorderedMap<SharedPtr<MG_State::GLState::FramebufferObject>, SharedPtr<BackendFramebufferObject>>
+3 -11
View File
@@ -133,8 +133,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
bool SyncAttachmentObject(GLenum glFBOTarget, bool SyncAttachmentObject(GLenum glFBOTarget,
const MG_State::GLState::FramebufferAttachmentObject& attachmentObject, const MG_State::GLState::FramebufferAttachmentObject& attachmentObject,
GLenum glBackendAttachment); GLenum glBackendAttachment);
FramebufferAttachmentType GetCompactedAttachmentTypeAtDrawBufferIndex(Int index); // FramebufferAttachmentType GetCompactedAttachmentTypeAtDrawBufferIndex(Int index);
GLenum GetBackendAttachmentType(FramebufferAttachmentType frontendAtt) const;
private: private:
Uint m_backendFBOId = 0; Uint m_backendFBOId = 0;
@@ -146,17 +146,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
*/ */
FramebufferAttachmentType m_frontendDrawBuffers[MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS] = { FramebufferAttachmentType m_frontendDrawBuffers[MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS] = {
FramebufferAttachmentType::None}; FramebufferAttachmentType::None};
/* this will save buffers in its compacted GL form,
not consecutive is not allowed
i.e. it could be like [COLOR_ATTACHMENT0, COLOR_ATTACHMENT5, COLOR_ATTACHMENT4]
(no GL_NONE among those)
*/
FramebufferAttachmentType
m_compactedFrontendDrawBuffers[MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS] = {
FramebufferAttachmentType::None};
/* this will save buffers in stricter ES rules /* this will save buffers in stricter ES rules
reversion, absence or not consecutive are not allowed, according to ES spec reversion, absence or not consecutive are not allowed, according to ES spec
i.e. it could be like [COLOR_ATTACHMENT0, COLOR_ATTACHMENT1, NONE, NONE, ...] i.e. it could be like [COLOR_ATTACHMENT0, COLOR_ATTACHMENT1, NONE, COLOR_ATTACHMENT3, ...]
this array could be provided as data directly to ES `glDrawBuffers` function this array could be provided as data directly to ES `glDrawBuffers` function
*/ */
GLenum m_backendDrawBuffers[MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS] = {GL_NONE}; GLenum m_backendDrawBuffers[MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS] = {GL_NONE};