Skip to content

android: 8bit render target fallback when rgb10a2 window configs are non-conformant (#374) - #385

Open
abdelaziz-mahdy wants to merge 2 commits into
wang-bin:masterfrom
abdelaziz-mahdy:fix/egl-caveat-8bit-fallback
Open

android: 8bit render target fallback when rgb10a2 window configs are non-conformant (#374)#385
abdelaziz-mahdy wants to merge 2 commits into
wang-bin:masterfrom
abdelaziz-mahdy:fix/egl-caveat-8bit-fallback

Conversation

@abdelaziz-mahdy

Copy link
Copy Markdown
Contributor

implements the detection from your #374 suggestion: probe once with eglChooseConfig (EGL_CONFIG_CAVEAT = EGL_NONE + 10/10/10/2 + window bit), and if the driver has no conformant 10bit window config, request GLRenderAPI.depth = 8 via setRenderAPI before updateNativeSurface. no context/surface created, cached after first call. no behavior change on drivers with conformant 10bit configs

tested on the #374 device (TCL google tv, PowerVR BXE, realtek RTD2875P, android 12) with the EGL_SDR_DEPTH env workaround removed:

conformant rgb10a2 window EGLConfigs: 0
select a 8bits EGLConfig

zero IsTextureConsistent errors, clean playback. ideally the caveat filter lives in libmdk's own eglChooseConfig (then this plugin-side fallback becomes redundant), but this fixes it for fvp users today

(developed with an AI assistant (Fable), tested and verified on device)

…indow EGLConfig exists

Some drivers (PowerVR BXE on Realtek TVs, wang-bin#374) expose RGBA_1010102 window
configs but mark them all EGL_NON_CONFORMANT_CONFIG; rendering into one from
a shared context corrupts the output. Probe once with eglChooseConfig
(EGL_CONFIG_CAVEAT=EGL_NONE) and request depth=8 via setRenderAPI when the
driver has no conformant 10bit window config. No behavior change on
conformant drivers.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a fallback mechanism to request an 8-bit render target on Android devices where the EGL driver lacks conformant 10-bit window configurations (which can cause output corruption on certain drivers like PowerVR BXE). This is achieved by linking against EGL, querying the available EGL configurations, and setting the GLRenderAPI depth to 8 if no conformant 10-bit configuration is found. The reviewer suggested calling eglTerminate after the EGL configuration probe to prevent potential resource leaks.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread android/fvp_plugin.cpp Outdated
Comment on lines +51 to +67
if (!eglInitialize(dpy, &major, &minor)) // ref counted, no eglTerminate
return false;
const EGLint attrs[] = {
EGL_CONFIG_CAVEAT, EGL_NONE, // exclude slow/non-conformant configs
EGL_BUFFER_SIZE, 32,
EGL_RED_SIZE, 10,
EGL_GREEN_SIZE, 10,
EGL_BLUE_SIZE, 10,
EGL_ALPHA_SIZE, 2,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT | 0x40/*EGL_OPENGL_ES3_BIT*/,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_NONE
};
EGLint count = 0;
const EGLBoolean ok = eglChooseConfig(dpy, attrs, nullptr, 0, &count);
clog << "conformant rgb10a2 window EGLConfigs: " << count << endl;
return ok && count <= 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Although EGL initialization is reference-counted, failing to call eglTerminate after a successful eglInitialize can lead to resource leaks or prevent clean cleanup of EGL resources (especially if this is the only initialization of the display at this point). Since this is a one-time probe, it is best practice to call eglTerminate(dpy) to decrement the reference count back to its original state once the query is complete.

        if (!eglInitialize(dpy, &major, &minor))
            return false;
        const EGLint attrs[] = {
            EGL_CONFIG_CAVEAT, EGL_NONE, // exclude slow/non-conformant configs
            EGL_BUFFER_SIZE, 32,
            EGL_RED_SIZE, 10,
            EGL_GREEN_SIZE, 10,
            EGL_BLUE_SIZE, 10,
            EGL_ALPHA_SIZE, 2,
            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT | 0x40/*EGL_OPENGL_ES3_BIT*/,
            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
            EGL_NONE
        };
        EGLint count = 0;
        const EGLBoolean ok = eglChooseConfig(dpy, attrs, nullptr, 0, &count);
        clog << "conformant rgb10a2 window EGLConfigs: " << count << endl;
        eglTerminate(dpy);
        return ok && count <= 0;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not calling eglTerminate here is intentional: this is the process-global default display shared with the flutter engine and mdk's own renderer in the same process, and per the EGL spec eglTerminate destroys ALL resources associated with the display — android's libEGL refcounts initialize/terminate, but on a spec-conformant implementation that call could tear down live contexts owned by other components. the display staying initialized for the process lifetime is the expected state, nothing is leaked. expanded the code comment in 1a44848 to document this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant