mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-09 20:58:31 +09:00
[Fix] (MG_Backend/DirectGLES, MG_Impl/GLImpl): draw/read-buffer state could land on the wrong FBO (glDrawBuffer's static-array latch; SyncToBackend emitting glDrawBuffers/glReadBuffer for the non-bound target; no resync on bound-FBO attachment/drawbuffer edits) leaving MC 26.3's OIT color clears as no-ops; apply per bound target and track the FBO object version
This commit is contained in:
@@ -503,11 +503,22 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
for (auto& target : fboTargets) {
|
||||
auto& slot = MG_State::pGLContext->GetFramebufferBindingSlot(target);
|
||||
auto version = slot.GetVersion();
|
||||
if (version == g_fboBindVersions[SizeT(target)]) continue;
|
||||
|
||||
auto& currentFBO = slot.GetBoundObject();
|
||||
|
||||
// The slot version only tracks rebinds; attachment/drawbuffer edits on an
|
||||
// already-bound FBO bump its object version and must re-sync it too (e.g.
|
||||
// Minecraft 26.x reuses one FBO for depth-blit destinations with draw
|
||||
// buffers NONE and for color clears with draw buffer 0 — dropping the
|
||||
// glDrawBuffers change turns every offscreen clear into a no-op).
|
||||
const Uint16 slotVersion = slot.GetVersion();
|
||||
const Uint16 objectVersion = currentFBO ? currentFBO->GetObjectVersion() : 0;
|
||||
auto* currentPtr = currentFBO.get();
|
||||
if (slotVersion == g_fboBindVersions[SizeT(target)] &&
|
||||
objectVersion == g_fboSyncedObjectVersions[SizeT(target)] &&
|
||||
currentPtr == g_fboSyncedObjects[SizeT(target)]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!currentFBO) {
|
||||
MGLOG_E("No FBO is currently bound, cannot sync current FBO.");
|
||||
continue;
|
||||
@@ -520,6 +531,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
if (currentFBO.get() == lastUpdatedFBO) {
|
||||
MGLOG_D("Draw FBO and read FBO are the same, skipping sync.");
|
||||
g_fboSyncedObjectVersions[SizeT(target)] = objectVersion;
|
||||
g_fboSyncedObjects[SizeT(target)] = currentPtr;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -531,6 +544,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
backendObj->SyncToBackend(currentFBO, target);
|
||||
|
||||
g_fboSyncedObjectVersions[SizeT(target)] = objectVersion;
|
||||
g_fboSyncedObjects[SizeT(target)] = currentPtr;
|
||||
lastUpdatedFBO = currentFBO.get();
|
||||
}
|
||||
}
|
||||
@@ -1011,8 +1026,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
auto& slot = MG_State::pGLContext->GetFramebufferBindingSlot(target);
|
||||
SyncAndBindFramebufferObject(slot.GetBoundObject(), target);
|
||||
const auto& fbo = slot.GetBoundObject();
|
||||
SyncAndBindFramebufferObject(fbo, target);
|
||||
FramebufferImpl::g_fboBindVersions[(SizeT)target] = slot.GetVersion();
|
||||
FramebufferImpl::g_fboSyncedObjectVersions[(SizeT)target] = fbo ? fbo->GetObjectVersion() : 0;
|
||||
FramebufferImpl::g_fboSyncedObjects[(SizeT)target] = fbo.get();
|
||||
}
|
||||
|
||||
static void BindCurrentProgramWithResources();
|
||||
@@ -1860,6 +1878,24 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
MGLOG_D("ES %s(%d, %d, %d, %d, %d, %d, %d, %d, 0x%x, %s)", __func__, srcX0, srcY0, srcX1, srcY1,
|
||||
dstX0, dstY0, dstX1, dstY1, mask, MG_Util::ConvertGLEnumToString(filter).c_str());
|
||||
g_GLESFuncs.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
|
||||
// Debug-only diagnostics: which GLES depth texture did this blit write?
|
||||
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
|
||||
if (mask & GL_DEPTH_BUFFER_BIT) {
|
||||
static int diagCount = 0;
|
||||
if ((diagCount++ % 600) < 4) {
|
||||
GLint readFbo = 0, drawFbo = 0, readDepth = 0, drawDepth = 0;
|
||||
g_GLESFuncs.glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &readFbo);
|
||||
g_GLESFuncs.glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &drawFbo);
|
||||
g_GLESFuncs.glGetFramebufferAttachmentParameteriv(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
|
||||
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &readDepth);
|
||||
g_GLESFuncs.glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
|
||||
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &drawDepth);
|
||||
MGLOG_D("DBLIT readFbo=%d(depth=%d) -> drawFbo=%d(depth=%d) rect=(%d,%d,%d,%d)->(%d,%d,%d,%d)",
|
||||
readFbo, readDepth, drawFbo, drawDepth, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1,
|
||||
dstY1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
|
||||
@@ -2491,7 +2491,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
drawBufferClean = true;
|
||||
}
|
||||
|
||||
if (!drawBufferClean) {
|
||||
// glDrawBuffers writes the state of the FBO bound to GL_DRAW_FRAMEBUFFER.
|
||||
// When this object is only bound as the READ target the call would land on
|
||||
// whatever framebuffer is draw-bound AND falsely stamp this object's memo,
|
||||
// so the later draw-target sync skips as "clean" while the real state is
|
||||
// stale (Minecraft 26.x OIT: the scratch clear-FBO kept draw buffers NONE
|
||||
// from its blit-destination configuration, silently dropping every
|
||||
// offscreen color clear).
|
||||
if (!drawBufferClean && asTarget == FramebufferTarget::Draw) {
|
||||
memcpy(m_frontendDrawBuffers, stateDrawBuffers.data(),
|
||||
FramebufferObject::MAX_DRAW_BUFFERS * sizeof(FramebufferAttachmentType));
|
||||
std::fill(m_backendDrawBuffers, m_backendDrawBuffers + FramebufferObject::MAX_DRAW_BUFFERS, GL_NONE);
|
||||
@@ -2516,6 +2523,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
nEffectiveBuffers = i + 1;
|
||||
}
|
||||
g_GLESFuncs.glDrawBuffers(nEffectiveBuffers, m_backendDrawBuffers);
|
||||
MGLOG_D("DBAPPLY beFbo=%u target=%d n=%d db0=0x%x feDb0=%d", m_backendFBOId, (int)asTarget,
|
||||
nEffectiveBuffers, m_backendDrawBuffers[0], (int)stateDrawBuffers[0]);
|
||||
}
|
||||
|
||||
if (asTarget == FramebufferTarget::Draw) {
|
||||
@@ -2538,9 +2547,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
PrgramImpl::g_unormFallbackClampOutputMask = unormClampOutputMask;
|
||||
}
|
||||
|
||||
// 2. Remap read buffer
|
||||
// 2. Remap read buffer. glReadBuffer writes the READ-bound FBO's state, so
|
||||
// only apply (and stamp the memo) when this object is bound as READ.
|
||||
auto frontendReadBuf = stateFBOObject->GetReadBuffer();
|
||||
if (frontendReadBuf != m_frontendReadBuffer) {
|
||||
if (frontendReadBuf != m_frontendReadBuffer && asTarget == FramebufferTarget::Read) {
|
||||
m_frontendReadBuffer = frontendReadBuf;
|
||||
|
||||
GLenum glBackendReadBuffer = GetBackendAttachmentType(frontendReadBuf);
|
||||
@@ -2647,6 +2657,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
StateBackendObjectRegistry<MG_State::GLState::FramebufferObject, BackendFramebufferObject>
|
||||
g_backendFramebufferObjects;
|
||||
Array<Uint16, SizeT(FramebufferTarget::FramebufferTargetCount)> g_fboBindVersions = {0};
|
||||
// Tracks the bound FBO's object version (bumped on any attachment/drawbuffer change)
|
||||
// per target: re-attaching textures or changing draw buffers on an already-bound FBO
|
||||
// must re-sync it even when the binding-slot version has not moved.
|
||||
Array<Uint16, SizeT(FramebufferTarget::FramebufferTargetCount)> g_fboSyncedObjectVersions = {0};
|
||||
Array<MG_State::GLState::FramebufferObject*, SizeT(FramebufferTarget::FramebufferTargetCount)>
|
||||
g_fboSyncedObjects = {};
|
||||
} // namespace FramebufferImpl
|
||||
|
||||
namespace PrgramImpl {
|
||||
@@ -2935,6 +2951,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
m_uniformBlockBackendIndices[static_cast<SizeT>(i)] = static_cast<Int>(backendBlkIdx);
|
||||
g_GLESFuncs.glUniformBlockBinding(m_backendProgramId, backendBlkIdx, lastUBOBinding);
|
||||
MGLOG_D("CACHE prog=%u beProg=%u blk[%d]='%s' beIdx=%u -> bePoint=%u",
|
||||
stateProgramObject->GetExternalIndex(), m_backendProgramId, i, name.c_str(), backendBlkIdx,
|
||||
lastUBOBinding);
|
||||
}
|
||||
|
||||
m_samplerUniformBindings.clear();
|
||||
|
||||
@@ -408,6 +408,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
extern StateBackendObjectRegistry<MG_State::GLState::FramebufferObject, BackendFramebufferObject>
|
||||
g_backendFramebufferObjects;
|
||||
extern Array<Uint16, SizeT(FramebufferTarget::FramebufferTargetCount)> g_fboBindVersions;
|
||||
// Tracks the bound FBO's object version (bumped on any attachment/drawbuffer change)
|
||||
// per target: re-attaching textures or changing draw buffers on an already-bound FBO
|
||||
// must re-sync it even when the binding-slot version has not moved.
|
||||
extern Array<Uint16, SizeT(FramebufferTarget::FramebufferTargetCount)> g_fboSyncedObjectVersions;
|
||||
extern Array<MG_State::GLState::FramebufferObject*, SizeT(FramebufferTarget::FramebufferTargetCount)>
|
||||
g_fboSyncedObjects;
|
||||
} // namespace FramebufferImpl
|
||||
|
||||
// Image uniforms take their unit from the layout(binding=N) qualifier baked into
|
||||
|
||||
@@ -1177,7 +1177,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw);
|
||||
auto& fbo = bindingSlot.GetBoundObject();
|
||||
const bool isDefaultFBO = (fbo == FramebufferImpl::pDefaultFramebufferInfo->defaultFBO);
|
||||
static GLenum bufs[] = {buf};
|
||||
const GLenum bufs[] = {buf};
|
||||
DrawBuffersForFramebuffer_State(fbo, isDefaultFBO, 1, bufs, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1406,6 +1406,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
|
||||
const auto& index = programObject->GetUniformBlockIndex(uniformBlockName);
|
||||
MGLOG_D("GBI prog=%u name='%s' -> %d", program, uniformBlockName ? uniformBlockName : "(null)", (Int)index);
|
||||
return index;
|
||||
}
|
||||
|
||||
@@ -1429,6 +1430,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
std::to_string(program) + "."));
|
||||
return;
|
||||
}
|
||||
MGLOG_D("UBB prog=%u idx=%u binding=%u", program, uniformBlockIndex, uniformBlockBinding);
|
||||
programObject->SetUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user