diff --git a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp index 01783abd..6c517949 100644 --- a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp @@ -738,6 +738,9 @@ namespace MobileGL::MG_Backend::DirectGLES { static Bool g_hasSyncedRenderState = false; static RenderStateParameters g_syncedRenderStateParameters; static IntVec4 g_syncedBackendViewport = IntVec4(-1, -1, -1, -1); + // GLES starts with sRGB framebuffer encoding on, so the first sync always has to push the + // frontend's (desktop-GL default) disabled state down. + static Bool g_syncedSrgbFramebufferWrites = true; void SyncRenderState() { #ifdef TRACY_ENABLE ZoneScopedC(TRACY_ZONECOLOR_BACKEND); @@ -784,6 +787,19 @@ namespace MobileGL::MG_Backend::DirectGLES { #undef SYNC_CAPABILITY + { // sRGB framebuffer writes. GLES core always encodes a write into an sRGB attachment, + // while GL_FRAMEBUFFER_SRGB is disabled by default in desktop GL and the frontend + // never turns it on, so the driver has to be told to write raw. Without this a render + // into an sRGB colour buffer comes back encoded once too often (the shader's own + // decode on the next fetch then leaves the value one conversion short). + const Bool srgbWrites = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::FramebufferSrgb); + if (g_GLESCapabilities.SupportsSrgbWriteControl && srgbWrites != g_syncedSrgbFramebufferWrites) { + srgbWrites ? g_GLESFuncs.glEnable(GL_FRAMEBUFFER_SRGB) + : g_GLESFuncs.glDisable(GL_FRAMEBUFFER_SRGB); + g_syncedSrgbFramebufferWrites = srgbWrites; + } + } + { // Primitive restart. GLES core has only GL_PRIMITIVE_RESTART_FIXED_INDEX (fixed all-ones // value); both the fixed cap and the (fixed-valued) arbitrary GL_PRIMITIVE_RESTART map to // it. An arbitrary non-fixed restart index is rejected at draw time (see DrawElements). diff --git a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp index 9b98c942..ac006e8e 100644 --- a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp +++ b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp @@ -824,6 +824,9 @@ namespace MobileGL::MG_Util::BackendLoader { if (std::strcmp(extension, "GL_EXT_texture_norm16") == 0) { caps.SupportsNorm16Texture = true; } + if (std::strcmp(extension, "GL_EXT_sRGB_write_control") == 0) { + caps.SupportsSrgbWriteControl = true; + } if (std::strcmp(extension, "GL_EXT_texture_filter_anisotropic") == 0) { caps.SupportsTextureFilterAnisotropy = true; } diff --git a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.h b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.h index fa544e40..f9196485 100644 --- a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.h +++ b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.h @@ -1031,6 +1031,10 @@ namespace MobileGL { String GLESShadingLanguageVersionString; Bool SupportsPersistentMapping = false; Bool SupportsNorm16Texture = false; + // GL_EXT_sRGB_write_control is present, so GL_FRAMEBUFFER_SRGB can be turned off. + // GLES has no such switch in core: writes into an sRGB attachment are ALWAYS encoded, + // while desktop GL leaves GL_FRAMEBUFFER_SRGB disabled by default and writes raw. + Bool SupportsSrgbWriteControl = false; // GL_EXT_texture_filter_anisotropic is present, so sampler/texture // anisotropy may be forwarded without raising GL_INVALID_ENUM in GLES. Bool SupportsTextureFilterAnisotropy = false;