Bug 1635451 - Allow GLX to work in headless content processes. r=jgilbert

This follows what we're already doing for EGL: a refcounted object
which can own the X connection, where we hold a weak reference from
the library object so that multiple contexts opportunistically share
the display but we close the connection when the last context is
freed/GCed.

In a process where GTK is initialized, we borrow its display instead of
opening a new one, which preserves the existing behavior.

Differential Revision: https://phabricator.services.mozilla.com/D112195
This commit is contained in:
Jed Davis 2021-07-06 07:42:42 +00:00
Родитель a8d8e90b70
Коммит dc3ae62544
9 изменённых файлов: 276 добавлений и 110 удалений

Просмотреть файл

@ -20,8 +20,9 @@ class GLContextGLX : public GLContext {
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextGLX, override)
static already_AddRefed<GLContextGLX> CreateGLContext(
const GLContextDesc&, Display* display, GLXDrawable drawable,
GLXFBConfig cfg, bool deleteDrawable, gfxXlibSurface* pixmap);
const GLContextDesc&, std::shared_ptr<gfx::XlibDisplay> display,
GLXDrawable drawable, GLXFBConfig cfg, bool deleteDrawable,
gfxXlibSurface* pixmap);
static bool FindVisual(Display* display, int screen, bool useWebRender,
bool useAlpha, int* const out_visualId);
@ -67,12 +68,12 @@ class GLContextGLX : public GLContext {
private:
friend class GLContextProviderGLX;
GLContextGLX(const GLContextDesc&, Display* aDisplay, GLXDrawable aDrawable,
GLXContext aContext, bool aDeleteDrawable, bool aDoubleBuffered,
gfxXlibSurface* aPixmap);
GLContextGLX(const GLContextDesc&, std::shared_ptr<gfx::XlibDisplay> aDisplay,
GLXDrawable aDrawable, GLXContext aContext, bool aDeleteDrawable,
bool aDoubleBuffered, gfxXlibSurface* aPixmap);
const GLXContext mContext;
Display* const mDisplay;
const std::shared_ptr<gfx::XlibDisplay> mDisplay;
const GLXDrawable mDrawable;
const bool mDeleteDrawable;
const bool mDoubleBuffered;

Просмотреть файл

@ -19,6 +19,7 @@
#include "mozilla/layers/CompositorOptions.h"
#include "mozilla/Range.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/Sprintf.h"
#include "mozilla/StaticPrefs_gfx.h"
#include "mozilla/StaticPrefs_layout.h"
#include "mozilla/widget/CompositorWidget.h"
@ -59,7 +60,7 @@ static inline bool HasExtension(const char* aExtensions,
reinterpret_cast<const GLubyte*>(aExtensions), aRequiredExtension);
}
bool GLXLibrary::EnsureInitialized() {
bool GLXLibrary::EnsureInitialized(Display* aDisplay) {
if (mInitialized) {
return true;
}
@ -70,6 +71,11 @@ bool GLXLibrary::EnsureInitialized() {
}
mTriedInitializing = true;
MOZ_ASSERT(aDisplay);
if (!aDisplay) {
return false;
}
// Force enabling s3 texture compression. (Bug 774134)
PR_SetEnv("force_s3tc_enable=true");
@ -148,12 +154,11 @@ bool GLXLibrary::EnsureInitialized() {
}
const SymbolLoader pfnLoader(mSymbols.fGetProcAddress);
Display* display = DefaultXDisplay();
int screen = DefaultScreen(display);
int screen = DefaultScreen(aDisplay);
{
int major, minor;
if (!fQueryVersion(display, &major, &minor) || major != 1 || minor < 3) {
if (!fQueryVersion(aDisplay, &major, &minor) || major != 1 || minor < 3) {
NS_ERROR("GLX version older than 1.3. (released in 1998)");
return false;
}
@ -181,10 +186,10 @@ bool GLXLibrary::EnsureInitialized() {
return false;
};
const char* clientVendor = fGetClientString(display, LOCAL_GLX_VENDOR);
const char* clientVendor = fGetClientString(aDisplay, LOCAL_GLX_VENDOR);
const char* serverVendor =
fQueryServerString(display, screen, LOCAL_GLX_VENDOR);
const char* extensionsStr = fQueryExtensionsString(display, screen);
fQueryServerString(aDisplay, screen, LOCAL_GLX_VENDOR);
const char* extensionsStr = fQueryExtensionsString(aDisplay, screen);
if (HasExtension(extensionsStr, "GLX_EXT_texture_from_pixmap") &&
fnLoadSymbols(symbols_texturefrompixmap)) {
@ -240,19 +245,20 @@ bool GLXLibrary::EnsureInitialized() {
}
bool GLXLibrary::SupportsTextureFromPixmap(gfxASurface* aSurface) {
if (!EnsureInitialized()) {
if (aSurface->GetType() != gfxSurfaceType::Xlib) {
return false;
}
if (aSurface->GetType() != gfxSurfaceType::Xlib || !mUseTextureFromPixmap) {
gfxXlibSurface* xs = static_cast<gfxXlibSurface*>(aSurface);
if (!EnsureInitialized(xs->XDisplay())) {
return false;
}
return true;
return mUseTextureFromPixmap;
}
bool GLXLibrary::SupportsVideoSync() {
if (!EnsureInitialized()) {
bool GLXLibrary::SupportsVideoSync(Display* aDisplay) {
if (!EnsureInitialized(aDisplay)) {
return false;
}
@ -450,8 +456,9 @@ static int GLXErrorHandler(Display* display, XErrorEvent* ev) {
}
GLXLibrary::WrapperScope::WrapperScope(const GLXLibrary& glx,
const char* const funcName)
: mGlx(glx), mFuncName(funcName) {
const char* const funcName,
Display* aDisplay)
: mGlx(glx), mFuncName(funcName), mDisplay(aDisplay) {
if (mGlx.mDebug) {
sOldErrorHandler = XSetErrorHandler(GLXErrorHandler);
}
@ -459,11 +466,17 @@ GLXLibrary::WrapperScope::WrapperScope(const GLXLibrary& glx,
GLXLibrary::WrapperScope::~WrapperScope() {
if (mGlx.mDebug) {
FinishX(DefaultXDisplay());
if (mDisplay) {
FinishX(mDisplay);
}
if (sErrorEvent.mError.error_code) {
char buffer[100] = {};
XGetErrorText(DefaultXDisplay(), sErrorEvent.mError.error_code, buffer,
if (mDisplay) {
XGetErrorText(mDisplay, sErrorEvent.mError.error_code, buffer,
sizeof(buffer));
} else {
SprintfLiteral(buffer, "%d", sErrorEvent.mError.error_code);
}
printf_stderr("X ERROR after %s: %s (%i) - Request: %i.%i, Serial: %lu",
mFuncName, buffer, sErrorEvent.mError.error_code,
sErrorEvent.mError.request_code,
@ -474,13 +487,45 @@ GLXLibrary::WrapperScope::~WrapperScope() {
}
}
// Returns the GTK display if available; otherwise, if a display was
// previously opened by this method and is still open, returns a
// reference to it; otherwise, opens a new connection. (The non-GTK
// cases are similar to what we do for EGL.)
std::shared_ptr<XlibDisplay> GLXLibrary::GetDisplay() {
std::shared_ptr<XlibDisplay> display;
#ifdef MOZ_WIDGET_GTK
static const bool kHaveGtk = !!gdk_display_get_default();
if (kHaveGtk) {
display = XlibDisplay::Borrow(DefaultXDisplay());
}
#endif
if (display) {
return display;
}
auto ownDisplay = mOwnDisplay.Lock();
display = ownDisplay->lock();
if (display) {
return display;
}
display = XlibDisplay::Open(nullptr);
if (NS_WARN_IF(!display)) {
return nullptr;
}
*ownDisplay = display;
return display;
}
already_AddRefed<GLContextGLX> GLContextGLX::CreateGLContext(
const GLContextDesc& desc, Display* display, GLXDrawable drawable,
GLXFBConfig cfg, bool deleteDrawable, gfxXlibSurface* pixmap) {
const GLContextDesc& desc, std::shared_ptr<XlibDisplay> display,
GLXDrawable drawable, GLXFBConfig cfg, bool deleteDrawable,
gfxXlibSurface* pixmap) {
GLXLibrary& glx = sGLXLibrary;
int isDoubleBuffered = 0;
int err = glx.fGetFBConfigAttrib(display, cfg, LOCAL_GLX_DOUBLEBUFFER,
int err = glx.fGetFBConfigAttrib(*display, cfg, LOCAL_GLX_DOUBLEBUFFER,
&isDoubleBuffered);
if (LOCAL_GLX_BAD_ATTRIBUTE != err) {
if (ShouldSpew()) {
@ -507,15 +552,15 @@ already_AddRefed<GLContextGLX> GLContextGLX::CreateGLContext(
// we should not try to use such contexts. (Errors may come from the
// distant server, or something)
const auto glxContext = glx.fCreateContextAttribs(
display, cfg, nullptr, X11True, terminated.data());
*display, cfg, nullptr, X11True, terminated.data());
if (!glxContext) return nullptr;
const RefPtr<GLContextGLX> ret =
new GLContextGLX(desc, display, drawable, glxContext, deleteDrawable,
isDoubleBuffered, pixmap);
if (handler.SyncAndGetError(display)) return nullptr;
if (handler.SyncAndGetError(*display)) return nullptr;
if (!ret->Init()) return nullptr;
if (handler.SyncAndGetError(display)) return nullptr;
if (handler.SyncAndGetError(*display)) return nullptr;
return ret;
};
@ -602,15 +647,15 @@ GLContextGLX::~GLContextGLX() {
#ifdef DEBUG
bool success =
#endif
mGLX->fMakeCurrent(mDisplay, X11None, nullptr);
mGLX->fMakeCurrent(*mDisplay, X11None, nullptr);
MOZ_ASSERT(success,
"glXMakeCurrent failed to release GL context before we call "
"glXDestroyContext!");
mGLX->fDestroyContext(mDisplay, mContext);
mGLX->fDestroyContext(*mDisplay, mContext);
if (mDeleteDrawable) {
mGLX->fDestroyPixmap(mDisplay, mDrawable);
mGLX->fDestroyPixmap(*mDisplay, mDrawable);
}
}
@ -632,10 +677,10 @@ bool GLContextGLX::MakeCurrentImpl() const {
if (mGLX->IsMesa()) {
// Read into the event queue to ensure that Mesa receives a
// DRI2InvalidateBuffers event before drawing. See bug 1280653.
Unused << XPending(mDisplay);
Unused << XPending(*mDisplay);
}
const bool succeeded = mGLX->fMakeCurrent(mDisplay, mDrawable, mContext);
const bool succeeded = mGLX->fMakeCurrent(*mDisplay, mDrawable, mContext);
NS_ASSERTION(succeeded, "Failed to make GL context current!");
if (!IsOffscreen() && mGLX->SupportsSwapControl()) {
@ -643,7 +688,7 @@ bool GLContextGLX::MakeCurrentImpl() const {
// VBlank when calling glXSwapBuffers. We want to run unthrottled
// in ASAP mode. See bug 1280744.
const bool isASAP = (StaticPrefs::layout_frame_rate() == 0);
mGLX->fSwapInterval(mDisplay, mDrawable, isASAP ? 0 : 1);
mGLX->fSwapInterval(*mDisplay, mDrawable, isASAP ? 0 : 1);
}
return succeeded;
}
@ -661,7 +706,7 @@ bool GLContextGLX::IsDoubleBuffered() const { return mDoubleBuffered; }
bool GLContextGLX::SwapBuffers() {
if (!mDoubleBuffered) return false;
mGLX->fSwapBuffers(mDisplay, mDrawable);
mGLX->fSwapBuffers(*mDisplay, mDrawable);
return true;
}
@ -671,7 +716,7 @@ GLint GLContextGLX::GetBufferAge() const {
}
GLuint result = 0;
mGLX->fQueryDrawable(mDisplay, mDrawable, LOCAL_GLX_BACK_BUFFER_AGE_EXT,
mGLX->fQueryDrawable(*mDisplay, mDrawable, LOCAL_GLX_BACK_BUFFER_AGE_EXT,
&result);
if (result > INT32_MAX) {
// If the result can't fit, just assume the buffer cannot be reused.
@ -681,34 +726,34 @@ GLint GLContextGLX::GetBufferAge() const {
}
void GLContextGLX::GetWSIInfo(nsCString* const out) const {
Display* display = DefaultXDisplay();
int screen = DefaultScreen(display);
int screen = DefaultScreen(mDisplay->get());
int majorVersion, minorVersion;
sGLXLibrary.fQueryVersion(display, &majorVersion, &minorVersion);
sGLXLibrary.fQueryVersion(*mDisplay, &majorVersion, &minorVersion);
out->Append(nsPrintfCString("GLX %u.%u", majorVersion, minorVersion));
out->AppendLiteral("\nGLX_VENDOR(client): ");
out->Append(sGLXLibrary.fGetClientString(display, LOCAL_GLX_VENDOR));
out->Append(sGLXLibrary.fGetClientString(*mDisplay, LOCAL_GLX_VENDOR));
out->AppendLiteral("\nGLX_VENDOR(server): ");
out->Append(
sGLXLibrary.fQueryServerString(display, screen, LOCAL_GLX_VENDOR));
sGLXLibrary.fQueryServerString(*mDisplay, screen, LOCAL_GLX_VENDOR));
out->AppendLiteral("\nExtensions: ");
out->Append(sGLXLibrary.fQueryExtensionsString(display, screen));
out->Append(sGLXLibrary.fQueryExtensionsString(*mDisplay, screen));
}
bool GLContextGLX::OverrideDrawable(GLXDrawable drawable) {
return mGLX->fMakeCurrent(mDisplay, drawable, mContext);
return mGLX->fMakeCurrent(*mDisplay, drawable, mContext);
}
bool GLContextGLX::RestoreDrawable() {
return mGLX->fMakeCurrent(mDisplay, mDrawable, mContext);
return mGLX->fMakeCurrent(*mDisplay, mDrawable, mContext);
}
GLContextGLX::GLContextGLX(const GLContextDesc& desc, Display* aDisplay,
GLContextGLX::GLContextGLX(const GLContextDesc& desc,
std::shared_ptr<XlibDisplay> aDisplay,
GLXDrawable aDrawable, GLXContext aContext,
bool aDeleteDrawable, bool aDoubleBuffered,
gfxXlibSurface* aPixmap)
@ -741,7 +786,7 @@ static bool AreCompatibleVisuals(Visual* one, Visual* two) {
already_AddRefed<GLContext> CreateForWidget(Display* aXDisplay, Window aXWindow,
bool aHardwareWebRender,
bool aForceAccelerated) {
if (!sGLXLibrary.EnsureInitialized()) {
if (!sGLXLibrary.EnsureInitialized(aXDisplay)) {
return nullptr;
}
@ -774,7 +819,8 @@ already_AddRefed<GLContext> CreateForWidget(Display* aXDisplay, Window aXWindow,
} else {
flags = CreateContextFlags::REQUIRE_COMPAT_PROFILE;
}
return GLContextGLX::CreateGLContext({{flags}, false}, aXDisplay, aXWindow,
return GLContextGLX::CreateGLContext({{flags}, false},
XlibDisplay::Borrow(aXDisplay), aXWindow,
config, false, nullptr);
}
@ -856,7 +902,7 @@ static bool ChooseConfig(GLXLibrary* glx, Display* display, int screen,
bool GLContextGLX::FindVisual(Display* display, int screen, bool useWebRender,
bool useAlpha, int* const out_visualId) {
if (!sGLXLibrary.EnsureInitialized()) {
if (!sGLXLibrary.EnsureInitialized(display)) {
return false;
}
@ -1005,31 +1051,32 @@ static already_AddRefed<GLContextGLX> CreateOffscreenPixmapContext(
const GLContextCreateDesc& desc, const IntSize& size,
nsACString* const out_failureId) {
GLXLibrary* glx = &sGLXLibrary;
if (!glx->EnsureInitialized()) return nullptr;
auto display = glx->GetDisplay();
Display* display = DefaultXDisplay();
int screen = DefaultScreen(display);
if (!display || !glx->EnsureInitialized(*display)) return nullptr;
int screen = DefaultScreen(display->get());
ScopedXFree<GLXFBConfig> scopedConfigArr;
GLXFBConfig config;
int visid;
if (!ChooseConfig(glx, display, screen, &scopedConfigArr, &config, &visid)) {
if (!ChooseConfig(glx, *display, screen, &scopedConfigArr, &config, &visid)) {
NS_WARNING("Failed to find a compatible config.");
return nullptr;
}
Visual* visual;
int depth;
FindVisualAndDepth(display, visid, &visual, &depth);
FindVisualAndDepth(*display, visid, &visual, &depth);
OffMainThreadScopedXErrorHandler xErrorHandler;
bool error = false;
gfx::IntSize dummySize(16, 16);
RefPtr<gfxXlibSurface> surface = gfxXlibSurface::Create(
DefaultScreenOfDisplay(display), visual, dummySize);
display, DefaultScreenOfDisplay(display->get()), visual, dummySize);
if (surface->CairoStatus() != 0) {
mozilla::Unused << xErrorHandler.SyncAndGetError(display);
mozilla::Unused << xErrorHandler.SyncAndGetError(*display);
return nullptr;
}
@ -1037,12 +1084,12 @@ static already_AddRefed<GLContextGLX> CreateOffscreenPixmapContext(
// its pre-GLX-1.3 extension equivalent (though given the ABI, we
// might not need to).
const auto drawable = surface->XDrawable();
const auto pixmap = glx->fCreatePixmap(display, config, drawable, nullptr);
const auto pixmap = glx->fCreatePixmap(*display, config, drawable, nullptr);
if (pixmap == 0) {
error = true;
}
bool serverError = xErrorHandler.SyncAndGetError(display);
bool serverError = xErrorHandler.SyncAndGetError(*display);
if (error || serverError) return nullptr;
auto fullDesc = GLContextDesc{desc};

Просмотреть файл

@ -8,6 +8,8 @@
#include "GLContextTypes.h"
#include "mozilla/Assertions.h"
#include "mozilla/DataMutex.h"
#include "mozilla/gfx/XlibDisplay.h"
#include "prlink.h"
typedef realGLboolean GLboolean;
@ -33,172 +35,174 @@ class GLContextGLX;
class GLXLibrary final {
public:
bool EnsureInitialized();
bool EnsureInitialized(Display* aDisplay);
private:
class WrapperScope final {
const GLXLibrary& mGlx;
const char* const mFuncName;
Display* const mDisplay;
public:
WrapperScope(const GLXLibrary& glx, const char* const funcName);
WrapperScope(const GLXLibrary& glx, const char* const funcName,
Display* aDisplay);
~WrapperScope();
};
public:
#ifdef DEBUG
# define DECL_WRAPPER_SCOPE const WrapperScope wrapperScope(*this, __func__);
# define DECL_WRAPPER_SCOPE(display) \
const WrapperScope wrapperScope(*this, __func__, display);
#else
# define DECL_WRAPPER_SCOPE
# define DECL_WRAPPER_SCOPE(display)
#endif
void fDestroyContext(Display* display, GLXContext context) const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(display)
return mSymbols.fDestroyContext(display, context);
}
Bool fMakeCurrent(Display* display, GLXDrawable drawable,
GLXContext context) const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(display)
return mSymbols.fMakeCurrent(display, drawable, context);
}
XVisualInfo* fGetConfig(Display* display, XVisualInfo* info, int attrib,
int* value) const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(display)
return mSymbols.fGetConfig(display, info, attrib, value);
}
GLXContext fGetCurrentContext() const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(nullptr)
return mSymbols.fGetCurrentContext();
}
GLXFBConfig* fChooseFBConfig(Display* display, int screen,
const int* attrib_list, int* nelements) const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(display)
return mSymbols.fChooseFBConfig(display, screen, attrib_list, nelements);
}
XVisualInfo* fChooseVisual(Display* display, int screen,
int* attrib_list) const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(display)
return mSymbols.fChooseVisual(display, screen, attrib_list);
}
GLXFBConfig* fGetFBConfigs(Display* display, int screen,
int* nelements) const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(display)
return mSymbols.fGetFBConfigs(display, screen, nelements);
}
GLXContext fCreateNewContext(Display* display, GLXFBConfig config,
int render_type, GLXContext share_list,
Bool direct) const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(display)
return mSymbols.fCreateNewContext(display, config, render_type, share_list,
direct);
}
int fGetFBConfigAttrib(Display* display, GLXFBConfig config, int attribute,
int* value) const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(display)
return mSymbols.fGetFBConfigAttrib(display, config, attribute, value);
}
void fSwapBuffers(Display* display, GLXDrawable drawable) const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(display)
return mSymbols.fSwapBuffers(display, drawable);
}
const char* fQueryExtensionsString(Display* display, int screen) const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(display)
return mSymbols.fQueryExtensionsString(display, screen);
}
const char* fGetClientString(Display* display, int screen) const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(display)
return mSymbols.fGetClientString(display, screen);
}
const char* fQueryServerString(Display* display, int screen, int name) const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(display)
return mSymbols.fQueryServerString(display, screen, name);
}
GLXPixmap fCreatePixmap(Display* display, GLXFBConfig config, Pixmap pixmap,
const int* attrib_list) const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(display)
return mSymbols.fCreatePixmap(display, config, pixmap, attrib_list);
}
GLXPixmap fCreateGLXPixmapWithConfig(Display* display, GLXFBConfig config,
Pixmap pixmap) const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(display)
return mSymbols.fCreateGLXPixmapWithConfig(display, config, pixmap);
}
void fDestroyPixmap(Display* display, GLXPixmap pixmap) const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(display)
return mSymbols.fDestroyPixmap(display, pixmap);
}
Bool fQueryVersion(Display* display, int* major, int* minor) const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(display)
return mSymbols.fQueryVersion(display, major, minor);
}
void fBindTexImage(Display* display, GLXDrawable drawable, int buffer,
const int* attrib_list) const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(display)
return mSymbols.fBindTexImageEXT(display, drawable, buffer, attrib_list);
}
void fReleaseTexImage(Display* display, GLXDrawable drawable,
int buffer) const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(display)
return mSymbols.fReleaseTexImageEXT(display, drawable, buffer);
}
void fWaitGL() const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(nullptr)
return mSymbols.fWaitGL();
}
void fWaitX() const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(nullptr)
return mSymbols.fWaitX();
}
GLXContext fCreateContextAttribs(Display* display, GLXFBConfig config,
GLXContext share_list, Bool direct,
const int* attrib_list) const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(display)
return mSymbols.fCreateContextAttribsARB(display, config, share_list,
direct, attrib_list);
}
int fGetVideoSync(unsigned int* count) const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(nullptr)
return mSymbols.fGetVideoSyncSGI(count);
}
int fWaitVideoSync(int divisor, int remainder, unsigned int* count) const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(nullptr)
return mSymbols.fWaitVideoSyncSGI(divisor, remainder, count);
}
void fSwapInterval(Display* dpy, GLXDrawable drawable, int interval) const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(dpy)
return mSymbols.fSwapIntervalEXT(dpy, drawable, interval);
}
int fQueryDrawable(Display* dpy, GLXDrawable drawable, int attribute,
unsigned int* value) const {
DECL_WRAPPER_SCOPE
DECL_WRAPPER_SCOPE(dpy)
return mSymbols.fQueryDrawable(dpy, drawable, attribute, value);
}
#undef DECL_WRAPPER_SCOPE
////
@ -216,7 +220,7 @@ class GLXLibrary final {
bool HasVideoMemoryPurge() { return mHasVideoMemoryPurge; }
bool HasCreateContextAttribs() { return mHasCreateContextAttribs; }
bool SupportsTextureFromPixmap(gfxASurface* aSurface);
bool SupportsVideoSync();
bool SupportsVideoSync(Display* aDisplay);
bool SupportsSwapControl() const { return bool(mSymbols.fSwapIntervalEXT); }
bool SupportsBufferAge() const {
MOZ_ASSERT(mInitialized);
@ -227,6 +231,8 @@ class GLXLibrary final {
auto GetGetProcAddress() const { return mSymbols.fGetProcAddress; }
std::shared_ptr<gfx::XlibDisplay> GetDisplay();
private:
struct {
void(GLAPIENTRY* fDestroyContext)(Display*, GLXContext);
@ -276,6 +282,8 @@ class GLXLibrary final {
bool mIsNVIDIA = false;
bool mClientIsMesa = false;
PRLibrary* mOGLLibrary = nullptr;
StaticDataMutex<std::weak_ptr<gfx::XlibDisplay>> mOwnDisplay{
"GLXLibrary::mOwnDisplay"};
};
// a global GLXLibrary instance

Просмотреть файл

@ -0,0 +1,40 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "XlibDisplay.h"
#include "mozilla/Assertions.h"
namespace mozilla::gfx {
XlibDisplay::XlibDisplay(Display* aDisplay, bool aOwned)
: mDisplay(aDisplay), mOwned(aOwned) {
MOZ_ASSERT(mDisplay);
}
XlibDisplay::~XlibDisplay() {
if (mOwned) {
XCloseDisplay(mDisplay);
}
}
/* static */
std::shared_ptr<XlibDisplay> XlibDisplay::Borrow(Display* aDisplay) {
if (!aDisplay) {
return nullptr;
}
return std::shared_ptr<XlibDisplay>(new XlibDisplay(aDisplay, false));
}
/* static */
std::shared_ptr<XlibDisplay> XlibDisplay::Open(const char* aDisplayName) {
Display* disp = XOpenDisplay(aDisplayName);
if (!disp) {
return nullptr;
}
return std::shared_ptr<XlibDisplay>(new XlibDisplay(disp, true));
}
} // namespace mozilla::gfx

41
gfx/thebes/XlibDisplay.h Normal file
Просмотреть файл

@ -0,0 +1,41 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GFX_XLIBDISPLAY_H
#define GFX_XLIBDISPLAY_H
#include <X11/Xlib.h>
#include "X11UndefineNone.h"
#include <memory>
namespace mozilla::gfx {
// Represents an X11 display connection which may be either borrowed
// (e.g., from GTK) or owned; in the latter case it will be closed
// with this object becomes unreferenced. See also the `EglDisplay`
// class.
class XlibDisplay final {
public:
~XlibDisplay();
// Explicit `->get()` may be needed with some `Xlib.h` macros that
// expand to C-style pointer casts.
Display* get() const { return mDisplay; }
operator Display*() const { return mDisplay; }
static std::shared_ptr<XlibDisplay> Borrow(Display* aDisplay);
static std::shared_ptr<XlibDisplay> Open(const char* aDisplayName);
private:
Display* const mDisplay;
bool const mOwned;
XlibDisplay(Display*, bool);
};
} // namespace mozilla::gfx
#endif // GFX_XLIBDISPLAY_H

Просмотреть файл

@ -30,6 +30,7 @@
#include "mozilla/FontPropertyTypes.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/gfx/XlibDisplay.h"
#include "mozilla/Monitor.h"
#include "mozilla/Preferences.h"
#include "mozilla/StaticPrefs_gfx.h"
@ -686,8 +687,9 @@ class GtkVsyncSource final : public VsyncSource {
return;
}
mGLContext = gl::GLContextGLX::CreateGLContext({}, mXDisplay, root,
config, false, nullptr);
mGLContext = gl::GLContextGLX::CreateGLContext(
{}, gfx::XlibDisplay::Borrow(mXDisplay), root, config, false,
nullptr);
if (!mGLContext) {
lock.NotifyAll();
@ -831,7 +833,7 @@ already_AddRefed<gfx::VsyncSource> gfxPlatformGtk::CreateHardwareVsyncSource() {
}
# endif
// Only use GLX vsync when the OpenGL compositor / WebRedner is being used.
// Only use GLX vsync when the OpenGL compositor / WebRender is being used.
// The extra cost of initializing a GLX context while blocking the main
// thread is not worth it when using basic composition.
//
@ -847,7 +849,7 @@ already_AddRefed<gfx::VsyncSource> gfxPlatformGtk::CreateHardwareVsyncSource() {
// Nvidia doesn't support GLX at the same time as EGL but Mesa does.
if (!gfxVars::UseEGL() || (adapterDriverVendor.Find("mesa") != -1)) {
useGlxVsync = gl::sGLXLibrary.SupportsVideoSync();
useGlxVsync = gl::sGLXLibrary.SupportsVideoSync(DefaultXDisplay());
}
if (useGlxVsync) {
RefPtr<VsyncSource> vsyncSource = new GtkVsyncSource();

Просмотреть файл

@ -25,7 +25,7 @@ using namespace mozilla::gfx;
gfxXlibSurface::gfxXlibSurface(Display* dpy, Drawable drawable, Visual* visual)
: mPixmapTaken(false),
mDisplay(dpy),
mDisplay(XlibDisplay::Borrow(dpy)),
mDrawable(drawable),
mGLXPixmap(X11None) {
const gfx::IntSize size = DoSizeQuery();
@ -36,6 +36,11 @@ gfxXlibSurface::gfxXlibSurface(Display* dpy, Drawable drawable, Visual* visual)
gfxXlibSurface::gfxXlibSurface(Display* dpy, Drawable drawable, Visual* visual,
const gfx::IntSize& size)
: gfxXlibSurface(XlibDisplay::Borrow(dpy), drawable, visual, size) {}
gfxXlibSurface::gfxXlibSurface(const std::shared_ptr<XlibDisplay>& dpy,
Drawable drawable, Visual* visual,
const gfx::IntSize& size)
: mPixmapTaken(false),
mDisplay(dpy),
mDrawable(drawable),
@ -43,8 +48,8 @@ gfxXlibSurface::gfxXlibSurface(Display* dpy, Drawable drawable, Visual* visual,
NS_ASSERTION(Factory::CheckSurfaceSize(size, XLIB_IMAGE_SIDE_SIZE_LIMIT),
"Bad size");
cairo_surface_t* surf =
cairo_xlib_surface_create(dpy, drawable, visual, size.width, size.height);
cairo_surface_t* surf = cairo_xlib_surface_create(*dpy, drawable, visual,
size.width, size.height);
Init(surf);
}
@ -52,14 +57,14 @@ gfxXlibSurface::gfxXlibSurface(Screen* screen, Drawable drawable,
XRenderPictFormat* format,
const gfx::IntSize& size)
: mPixmapTaken(false),
mDisplay(DisplayOfScreen(screen)),
mDisplay(XlibDisplay::Borrow(DisplayOfScreen(screen))),
mDrawable(drawable),
mGLXPixmap(X11None) {
NS_ASSERTION(Factory::CheckSurfaceSize(size, XLIB_IMAGE_SIDE_SIZE_LIMIT),
"Bad Size");
cairo_surface_t* surf = cairo_xlib_surface_create_with_xrender_format(
mDisplay, drawable, screen, format, size.width, size.height);
*mDisplay, drawable, screen, format, size.width, size.height);
Init(surf);
}
@ -69,7 +74,7 @@ gfxXlibSurface::gfxXlibSurface(cairo_surface_t* csurf)
"Not expecting an error surface");
mDrawable = cairo_xlib_surface_get_drawable(csurf);
mDisplay = cairo_xlib_surface_get_display(csurf);
mDisplay = XlibDisplay::Borrow(cairo_xlib_surface_get_display(csurf));
Init(csurf, true);
}
@ -78,9 +83,9 @@ gfxXlibSurface::~gfxXlibSurface() {
// gfxASurface's destructor calls RecordMemoryFreed().
if (mPixmapTaken) {
if (mGLXPixmap) {
gl::sGLXLibrary.DestroyPixmap(mDisplay, mGLXPixmap);
gl::sGLXLibrary.DestroyPixmap(*mDisplay, mGLXPixmap);
}
XFreePixmap(mDisplay, mDrawable);
XFreePixmap(*mDisplay, mDrawable);
}
}
@ -171,12 +176,22 @@ cairo_surface_t* gfxXlibSurface::CreateCairoSurface(Screen* screen,
already_AddRefed<gfxXlibSurface> gfxXlibSurface::Create(
Screen* screen, Visual* visual, const gfx::IntSize& size,
Drawable relatedDrawable) {
return Create(XlibDisplay::Borrow(DisplayOfScreen(screen)), screen, visual,
size, relatedDrawable);
};
/* static */
already_AddRefed<gfxXlibSurface> gfxXlibSurface::Create(
const std::shared_ptr<XlibDisplay>& display, Screen* screen, Visual* visual,
const gfx::IntSize& size, Drawable relatedDrawable) {
MOZ_ASSERT(*display == DisplayOfScreen(screen));
Drawable drawable = CreatePixmap(screen, size, DepthOfVisual(screen, visual),
relatedDrawable);
if (!drawable) return nullptr;
RefPtr<gfxXlibSurface> result =
new gfxXlibSurface(DisplayOfScreen(screen), drawable, visual, size);
new gfxXlibSurface(display, drawable, visual, size);
result->TakePixmap();
if (result->CairoStatus() != 0) return nullptr;
@ -218,7 +233,7 @@ already_AddRefed<gfxASurface> gfxXlibSurface::CreateSimilarSurface(
static bool force24bpp = GetForce24bppPref();
if (force24bpp && cairo_xlib_surface_get_depth(CairoSurface()) != 24) {
XRenderPictFormat* format =
XRenderFindStandardFormat(mDisplay, PictStandardRGB24);
XRenderFindStandardFormat(*mDisplay, PictStandardRGB24);
if (format) {
// Cairo only performs simple self-copies as desired if it
// knows that this is a Pixmap surface. It only knows that
@ -240,7 +255,7 @@ already_AddRefed<gfxASurface> gfxXlibSurface::CreateSimilarSurface(
void gfxXlibSurface::Finish() {
if (mPixmapTaken && mGLXPixmap) {
gl::sGLXLibrary.DestroyPixmap(mDisplay, mGLXPixmap);
gl::sGLXLibrary.DestroyPixmap(*mDisplay, mGLXPixmap);
mGLXPixmap = X11None;
}
gfxASurface::Finish();
@ -259,7 +274,7 @@ const gfx::IntSize gfxXlibSurface::DoSizeQuery() {
int x_ignore, y_ignore;
unsigned int bwidth_ignore, width, height, depth;
XGetGeometry(mDisplay, mDrawable, &root_ignore, &x_ignore, &y_ignore, &width,
XGetGeometry(*mDisplay, mDrawable, &root_ignore, &x_ignore, &y_ignore, &width,
&height, &bwidth_ignore, &depth);
return gfx::IntSize(width, height);

Просмотреть файл

@ -13,6 +13,7 @@
#include "X11UndefineNone.h"
#include "GLXLibrary.h"
#include "mozilla/gfx/XlibDisplay.h"
#include "nsSize.h"
@ -31,6 +32,9 @@ class gfxXlibSurface final : public gfxASurface {
// and known width/height.
gfxXlibSurface(Display* dpy, Drawable drawable, Visual* visual,
const mozilla::gfx::IntSize& size);
gfxXlibSurface(const std::shared_ptr<mozilla::gfx::XlibDisplay>& dpy,
Drawable drawable, Visual* visual,
const mozilla::gfx::IntSize& size);
// construct a wrapper around the specified drawable with dpy/format,
// and known width/height.
@ -46,6 +50,10 @@ class gfxXlibSurface final : public gfxASurface {
static already_AddRefed<gfxXlibSurface> Create(
::Screen* screen, Visual* visual, const mozilla::gfx::IntSize& size,
Drawable relatedDrawable = X11None);
static already_AddRefed<gfxXlibSurface> Create(
const std::shared_ptr<mozilla::gfx::XlibDisplay>& display,
::Screen* screen, Visual* visual, const mozilla::gfx::IntSize& size,
Drawable relatedDrawable = X11None);
static cairo_surface_t* CreateCairoSurface(
::Screen* screen, Visual* visual, const mozilla::gfx::IntSize& size,
Drawable relatedDrawable = X11None);
@ -61,7 +69,7 @@ class gfxXlibSurface final : public gfxASurface {
const mozilla::gfx::IntSize GetSize() const override;
Display* XDisplay() { return mDisplay; }
Display* XDisplay() { return *mDisplay; }
::Screen* XScreen();
Drawable XDrawable() { return mDrawable; }
XRenderPictFormat* XRenderFormat();
@ -98,15 +106,15 @@ class gfxXlibSurface final : public gfxASurface {
bool IsPadSlow() {
// The test here matches that for buggy_pad_reflect in
// _cairo_xlib_device_create.
return VendorRelease(mDisplay) >= 60700000 ||
VendorRelease(mDisplay) < 10699000;
return VendorRelease(mDisplay->get()) >= 60700000 ||
VendorRelease(mDisplay->get()) < 10699000;
}
protected:
// if TakePixmap() has been called on this
bool mPixmapTaken;
Display* mDisplay;
std::shared_ptr<mozilla::gfx::XlibDisplay> mDisplay;
Drawable mDrawable;
const mozilla::gfx::IntSize DoSizeQuery();

Просмотреть файл

@ -135,9 +135,13 @@ elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
"gfxXlibNativeRenderer.h",
"gfxXlibSurface.h",
]
EXPORTS.mozilla.gfx += [
"XlibDisplay.h",
]
SOURCES += [
"gfxXlibNativeRenderer.cpp",
"gfxXlibSurface.cpp",
"XlibDisplay.cpp",
]
elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows":