Bug 1650583 [Linux/EGL] Implement GLContextEGL::FindVisual(), r=jgilbert

Implement GLContextEGL::FindVisual() as a EGL counterpart of GLContextGLX::FindVisual() used
by GLX.

We need to make sure that GdkWindow uses the same visual as GL framebuffer we use for it.
That was already implemented for GLX backend (Bug 1478454).

The visual match is implemented by visual parameter at CreateConfig()/CreateConfigScreen() routines and when it's non-zero,
try to find exact match based on visual ID.

Differential Revision: https://phabricator.services.mozilla.com/D87636
This commit is contained in:
Martin Stransky 2020-09-02 19:45:44 +00:00
parent fcbc4fc378
commit 90c4b74c25
3 changed files with 79 additions and 8 deletions

View File

@ -117,6 +117,9 @@ class GLContextEGL final : public GLContext {
static EGLSurface CreateEGLSurfaceForCompositorWidget(
widget::CompositorWidget* aCompositorWidget, const EGLConfig aConfig);
static bool FindVisual(bool aUseWebRender, bool useAlpha,
int* const out_visualId);
protected:
friend class GLContextProviderEGL;
friend class GLContextEGLFactory;
@ -156,9 +159,10 @@ class GLContextEGL final : public GLContext {
};
// -
// aVisual is used in Linux only to exactly match window and framebuffer
// visuals on NVIDIA drivers (Bug 1478454).
bool CreateConfig(EglDisplay&, EGLConfig* aConfig, int32_t depth,
bool aEnableDepthBuffer, bool aUseGles);
bool aEnableDepthBuffer, bool aUseGles, int aVisual = 0);
} // namespace gl
} // namespace mozilla

View File

@ -92,6 +92,15 @@ inline bool IsWaylandDisplay() {
#endif
}
inline bool IsX11Display() {
#ifdef MOZ_WIDGET_GTK
return gdk_display_get_default() &&
GDK_IS_X11_DISPLAY(gdk_display_get_default());
#else
return false;
#endif
}
struct wl_egl_window;
using namespace mozilla::gfx;
@ -130,7 +139,7 @@ void DeleteWaylandGLSurface(EGLSurface surface) {
static bool CreateConfigScreen(EglDisplay&, EGLConfig* const aConfig,
const bool aEnableDepthBuffer,
const bool aUseGles);
const bool aUseGles, int aVisual = 0);
// append three zeros at the end of attribs list to work around
// EGL implementation bugs that iterate until they find 0, instead of
@ -256,6 +265,22 @@ already_AddRefed<GLContext> GLContextEGLFactory::CreateImpl(
return nullptr;
}
int visualID = 0;
if (IsX11Display()) {
#ifdef MOZ_WIDGET_GTK
GdkDisplay* gdkDisplay = gdk_display_get_default();
auto display = gdkDisplay ? GDK_DISPLAY_XDISPLAY(gdkDisplay) : nullptr;
if (display) {
XWindowAttributes windowAttrs;
if (!XGetWindowAttributes(display, (Window)aWindow, &windowAttrs)) {
NS_WARNING("[EGL] XGetWindowAttributes() failed");
return nullptr;
}
visualID = XVisualIDFromVisual(windowAttrs.visual);
}
#endif
}
bool doubleBuffered = true;
EGLConfig config;
@ -270,14 +295,16 @@ already_AddRefed<GLContext> GLContextEGLFactory::CreateImpl(
}
} else {
if (aDepth) {
if (!CreateConfig(*egl, &config, aDepth, aWebRender, aUseGles)) {
if (!CreateConfig(*egl, &config, aDepth, aWebRender, aUseGles,
visualID)) {
gfxCriticalNote
<< "Failed to create EGLConfig for WebRender with depth!";
return nullptr;
}
} else {
if (!CreateConfigScreen(*egl, &config,
/* aEnableDepthBuffer */ aWebRender, aUseGles)) {
/* aEnableDepthBuffer */ aWebRender, aUseGles,
visualID)) {
gfxCriticalNote << "Failed to create EGLConfig!";
return nullptr;
}
@ -287,6 +314,9 @@ already_AddRefed<GLContext> GLContextEGLFactory::CreateImpl(
EGLSurface surface = EGL_NO_SURFACE;
if (aWindow) {
surface = mozilla::gl::CreateSurfaceFromNativeWindow(*egl, aWindow, config);
if (!surface) {
return nullptr;
}
}
CreateContextFlags flags = CreateContextFlags::NONE;
@ -835,7 +865,7 @@ static const EGLint kEGLConfigAttribsRGBA32[] = {
LOCAL_EGL_ALPHA_SIZE, 8};
bool CreateConfig(EglDisplay& egl, EGLConfig* aConfig, int32_t depth,
bool aEnableDepthBuffer, bool aUseGles) {
bool aEnableDepthBuffer, bool aUseGles, int aVisual) {
EGLConfig configs[64];
std::vector<EGLint> attribs;
EGLint ncfg = ArrayLength(configs);
@ -890,6 +920,15 @@ bool CreateConfig(EglDisplay& egl, EGLConfig* aConfig, int32_t depth,
continue;
}
}
#if defined(MOZ_WIDGET_GTK)
if (aVisual) {
int vis;
if (!egl.fGetConfigAttrib(config, LOCAL_EGL_NATIVE_VISUAL_ID, &vis) ||
aVisual != vis) {
continue;
}
}
#endif
*aConfig = config;
return true;
}
@ -902,11 +941,13 @@ bool CreateConfig(EglDisplay& egl, EGLConfig* aConfig, int32_t depth,
//
// NB: It's entirely legal for the returned EGLConfig to be valid yet
// have the value null.
// aVisual is used in Linux only.
static bool CreateConfigScreen(EglDisplay& egl, EGLConfig* const aConfig,
const bool aEnableDepthBuffer,
const bool aUseGles) {
const bool aUseGles, int aVisual) {
int32_t depth = gfxVars::ScreenDepth();
if (CreateConfig(egl, aConfig, depth, aEnableDepthBuffer, aUseGles)) {
if (CreateConfig(egl, aConfig, depth, aEnableDepthBuffer, aUseGles,
aVisual)) {
return true;
}
#ifdef MOZ_WIDGET_ANDROID
@ -1045,6 +1086,30 @@ static EGLConfig ChooseConfig(EglDisplay& egl, const GLContextCreateDesc& desc,
return config;
}
/* static */
bool GLContextEGL::FindVisual(bool aUseWebRender, bool useAlpha,
int* const out_visualId) {
nsCString discardFailureId;
const auto egl = DefaultEglDisplay(&discardFailureId);
if (!egl) {
gfxCriticalNote
<< "GLContextEGL::FindVisual(): Failed to load EGL library!";
return false;
}
EGLConfig config;
const int bpp = useAlpha ? 32 : 24;
if (!CreateConfig(*egl, &config, bpp, aUseWebRender, /* aUseGles */ false)) {
gfxCriticalNote
<< "GLContextEGL::FindVisual(): Failed to create EGLConfig!";
return false;
}
if (egl->fGetConfigAttrib(config, LOCAL_EGL_NATIVE_VISUAL_ID, out_visualId)) {
return true;
}
return false;
}
/*static*/
RefPtr<GLContextEGL> GLContextEGL::CreateEGLPBufferOffscreenContextImpl(
const std::shared_ptr<EglDisplay> egl, const GLContextCreateDesc& desc,

View File

@ -150,6 +150,8 @@ class GLLibraryEGL final {
bool IsANGLE() const { return mIsANGLE; }
static bool FindVisual(Display* display, int screen, bool useWebRender,
bool useAlpha, int* const out_visualId);
// -
// PFN wrappers