[Fix] (MG_State, MG_Impl, MG_Test): enforce strict GL 3.3 core rules only on contexts that explicitly request a core profile - texture deleted-name reservation keep and VAO-0 draws relax otherwise or under MOBILEGL_RELAXED_SEMANTICS, and GL_CONTEXT_PROFILE_MASK reports the requested profile

This commit is contained in:
2026-07-17 21:32:16 -04:00
parent 1929a7c546
commit 92cced9bcc
14 changed files with 208 additions and 12 deletions
+14
View File
@@ -764,6 +764,20 @@ namespace MobileGL {
ctx->MajorVersion > 3 || (ctx->MajorVersion == 3 && ctx->MinorVersion >= 1);
}
Bool EGLContext::IsCurrentContextOpenGLCompatibilityProfile() const {
const std::lock_guard<std::recursive_mutex> lock(m_mutex);
auto currentIt = m_threadCurrents.find(CurrentThreadKey());
if (currentIt == m_threadCurrents.end()) {
return false;
}
const auto* ctx = TryGetContext(currentIt->second.Context);
// Affirmative check: true only when the host explicitly requested the
// compatibility bit. Attrib-less contexts report false and thus read as core
// for GL_CONTEXT_PROFILE_MASK (EGL defaults 3.x contexts to the core profile).
return ctx && ctx->ClientAPI == EGL_OPENGL_API &&
(ctx->OpenGLProfileMask & EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT);
}
EGLint EGLContext::GetCurrentContextFlags() const {
const std::lock_guard<std::recursive_mutex> lock(m_mutex);
auto currentIt = m_threadCurrents.find(CurrentThreadKey());
+1
View File
@@ -59,6 +59,7 @@ namespace MobileGL {
Bool ValidateContext(EGLContextHandle context) const;
Bool ValidateContextOnDisplay(EGLDisplayHandle display, EGLContextHandle context) const;
Bool IsCurrentContextOpenGLCoreProfile() const;
Bool IsCurrentContextOpenGLCompatibilityProfile() const;
EGLint GetCurrentContextFlags() const;
// Surface
+7 -1
View File
@@ -9,6 +9,7 @@
#include "Core.h"
#include "MG_State/GLState/RenderbufferState/RenderbufferObject.h"
#include "MG_State/EGLState/Core.h"
#include <Config.h>
namespace MobileGL::MG_State {
void Init() {
@@ -17,6 +18,11 @@ namespace MobileGL::MG_State {
pEGLContext = MakeUnique<EGLState::EGLContext>();
}
Bool IsRelaxedSemanticsActive() {
return MG_Config::Features.RelaxedSemantics ||
!(pEGLContext && pEGLContext->IsCurrentContextOpenGLCoreProfile());
}
namespace GLState {
// Error
void GLContext::RecordError(ErrorCode code, UniquePtr<ErrorInfo> info) {
@@ -235,7 +241,7 @@ namespace MobileGL::MG_State {
}
void GLContext::MarkTextureObjectForDeletion(Uint index) {
m_textureState.MarkTextureObjectForDeletion(index);
m_textureState.MarkTextureObjectForDeletion(index, IsRelaxedSemanticsActive());
}
TextureUnit& GLContext::GetTextureUnitObject(Int unit) {
+7
View File
@@ -252,5 +252,12 @@ namespace MobileGL {
} // namespace GLState
extern UniquePtr<GLState::GLContext> pGLContext;
// True when relaxed GL semantics apply. Strict core rules are enforced only when the
// current EGL context explicitly requested a core profile (core bit in
// EGL_CONTEXT_OPENGL_PROFILE_MASK, or a >=3.1 version request without the compatibility
// bit) and MOBILEGL_RELAXED_SEMANTICS is off; no current context, legacy version
// requests, and the compatibility bit all relax.
Bool IsRelaxedSemanticsActive();
} // namespace MG_State
} // namespace MobileGL
@@ -96,7 +96,7 @@ namespace MobileGL::MG_State::GLState {
return textureObject;
}
void TextureState::MarkTextureObjectForDeletion(Uint index) {
void TextureState::MarkTextureObjectForDeletion(Uint index, Bool keepUnboundReservation) {
if (m_indexGenerator.IsValid(index)) {
auto it = m_textureObjects.find(index);
if (it != m_textureObjects.end()) {
@@ -123,10 +123,15 @@ namespace MobileGL::MG_State::GLState {
BumpTextureBindGeneration();
m_textureObjects.erase(index);
m_indexGenerator.Delete(index);
} else if (!keepUnboundReservation) {
// GL 3.3 core 3.8.1 makes a deleted name unused again even when GenTextures only
// reserved it and no bind ever instantiated an object (so a later bind of it must
// fail), and the reservation has to return to the free list.
m_indexGenerator.Delete(index);
}
// Compatibility: legacy Minecraft may delete a generated name before its first bind,
// then bind and populate that same name. Keep such a reservation alive; only a real
// texture object reaching deletion releases its index above.
// Relaxed semantics: legacy apps may delete a generated name before its first
// bind, then bind and populate that same name. Keep such a reservation alive there;
// a real texture object reaching deletion still releases its index above.
}
}
@@ -60,7 +60,7 @@ namespace MobileGL::MG_State::GLState {
const ImageTextureBinding& GetImageTextureBinding(Int unit) const;
Int GetActiveTextureUnit() const;
void SetActiveTextureUnit(Int unit);
void MarkTextureObjectForDeletion(Uint index);
void MarkTextureObjectForDeletion(Uint index, Bool keepUnboundReservation);
Bool ValidateName(Uint index) const;
Bool ValidateTextureObject(Uint index) const;