Bug 1700799 - For GLContextGLX creation, add fallback if robustness fails. r=lsalzman

Also trim out unused code/vars.
Also give better WebGL context creation errors.

Differential Revision: https://phabricator.services.mozilla.com/D109679
This commit is contained in:
Jeff Gilbert 2021-03-27 08:26:35 +00:00
parent 17afcf1656
commit 615878e7ce
5 changed files with 259 additions and 244 deletions

View File

@ -532,8 +532,9 @@ RefPtr<WebGLContext> WebGLContext::Create(HostWebGLContext& host,
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID, cur.key);
}
text.AppendLiteral("\n* ");
text.Append(cur.info);
const auto str = nsPrintfCString("\n* %s (%s)", cur.info.BeginReading(),
cur.key.BeginReading());
text.Append(str);
}
failureId = "FEATURE_FAILURE_REASON"_ns;
return Err(text.BeginReading());

View File

@ -19,9 +19,10 @@ namespace gl {
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);
static RefPtr<GLContextGLX> CreateGLContext(const GLContextDesc&,
Display* display,
GLXDrawable drawable,
GLXFBConfig cfg);
static bool FindVisual(Display* display, int screen, bool useWebRender,
bool useAlpha, int* const out_visualId);
@ -68,19 +69,16 @@ class GLContextGLX : public GLContext {
friend class GLContextProviderGLX;
GLContextGLX(const GLContextDesc&, Display* aDisplay, GLXDrawable aDrawable,
GLXContext aContext, bool aDeleteDrawable, bool aDoubleBuffered,
gfxXlibSurface* aPixmap);
GLXContext aContext, bool aDoubleBuffered);
GLXContext mContext;
Display* mDisplay;
GLXDrawable mDrawable;
bool mDeleteDrawable;
bool mDoubleBuffered;
const GLXContext mContext;
Display* const mDisplay;
const GLXDrawable mDrawable;
const bool mDoubleBuffered;
GLXLibrary* mGLX;
GLXLibrary* const mGLX;
RefPtr<gfxXlibSurface> mPixmap;
bool mOwnsContext = true;
GLXPbuffer mPbuffer = 0;
};
} // namespace gl

View File

@ -130,7 +130,9 @@ bool GLXLibrary::EnsureInitialized() {
SYMBOL(ChooseVisual),
SYMBOL(GetFBConfigAttrib),
SYMBOL(GetFBConfigs),
SYMBOL(CreatePbuffer),
SYMBOL(CreatePixmap),
SYMBOL(DestroyPbuffer),
SYMBOL(DestroyPixmap),
SYMBOL(CreateNewContext),
@ -436,11 +438,16 @@ void GLXLibrary::UpdateTexImage(Display* aDisplay, GLXPixmap aPixmap) {
BindTexImage(aDisplay, aPixmap);
}
// -
// Before/AfterGLXCall
static int (*sOldErrorHandler)(Display*, XErrorEvent*);
ScopedXErrorHandler::ErrorEvent sErrorEvent;
static XErrorEvent sErrorEvent = {};
static int GLXErrorHandler(Display* display, XErrorEvent* ev) {
if (!sErrorEvent.mError.error_code) {
sErrorEvent.mError = *ev;
if (!sErrorEvent.error_code) {
sErrorEvent = *ev;
}
return 0;
}
@ -451,128 +458,166 @@ void GLXLibrary::BeforeGLXCall() const {
}
}
void GLXLibrary::AfterGLXCall() const {
void GLXLibrary::AfterGLXCall(const char* const func) const {
if (mDebug) {
FinishX(DefaultXDisplay());
if (sErrorEvent.mError.error_code) {
char buffer[2048];
XGetErrorText(DefaultXDisplay(), sErrorEvent.mError.error_code, buffer,
sizeof(buffer));
printf_stderr("X ERROR: %s (%i) - Request: %i.%i, Serial: %lu", buffer,
sErrorEvent.mError.error_code,
sErrorEvent.mError.request_code,
sErrorEvent.mError.minor_code, sErrorEvent.mError.serial);
MOZ_ASSERT_UNREACHABLE("AfterGLXCall sErrorEvent");
if (sErrorEvent.error_code) {
char buffer[2048] = {};
XGetErrorText(sErrorEvent.display, sErrorEvent.error_code, buffer,
sizeof(buffer) - 1);
auto str = nsPrintfCString("X ERROR after %s: %s (%i)", func, buffer,
sErrorEvent.error_code);
NS_WARNING(str.BeginReading());
constexpr bool verbose = true;
if (verbose) {
str = nsPrintfCString(" (Request: %i.%i, Serial: %lu)",
sErrorEvent.request_code, sErrorEvent.minor_code,
sErrorEvent.serial);
NS_WARNING(str.BeginReading());
}
// MOZ_ASSERT_UNREACHABLE("AfterGLXCall sErrorEvent");
sErrorEvent = {};
}
XSetErrorHandler(sOldErrorHandler);
}
}
already_AddRefed<GLContextGLX> GLContextGLX::CreateGLContext(
const GLContextDesc& desc, Display* display, GLXDrawable drawable,
GLXFBConfig cfg, bool deleteDrawable, gfxXlibSurface* pixmap) {
// -
RefPtr<GLContextGLX> GLContextGLX::CreateGLContext(const GLContextDesc& desc,
Display* display,
GLXDrawable drawable,
GLXFBConfig cfg) {
GLXLibrary& glx = sGLXLibrary;
int db = 0;
int err = glx.fGetFBConfigAttrib(display, cfg, LOCAL_GLX_DOUBLEBUFFER, &db);
if (LOCAL_GLX_BAD_ATTRIBUTE != err) {
int isDoubleBuffered = 0;
{
const int err = glx.fGetFBConfigAttrib(display, cfg, LOCAL_GLX_DOUBLEBUFFER,
&isDoubleBuffered);
MOZ_ASSERT(err != LOCAL_GLX_BAD_ATTRIBUTE);
(void)err;
if (ShouldSpew()) {
printf("[GLX] FBConfig is %sdouble-buffered\n", db ? "" : "not ");
printf("[GLX] FBConfig is %sdouble-buffered\n",
isDoubleBuffered ? "" : "not ");
}
}
GLXContext context;
if (!glx.HasCreateContextAttribs()) {
NS_WARNING("Cannot create GLContextGLX without glxCreateContextAttribs");
return nullptr;
}
RefPtr<GLContextGLX> glContext;
bool error;
OffMainThreadScopedXErrorHandler xErrorHandler;
const auto CreateWithAttribs =
[&](const std::vector<int>& attribs) -> RefPtr<GLContextGLX> {
GLXContext glxContext = nullptr;
bool hadError = false;
do {
error = false;
{
auto terminated = attribs;
terminated.push_back(0);
if (glx.HasCreateContextAttribs()) {
AutoTArray<int, 13> attrib_list;
if (glx.HasRobustness()) {
const int robust_attribs[] = {
LOCAL_GLX_CONTEXT_FLAGS_ARB,
LOCAL_GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB,
LOCAL_GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
LOCAL_GLX_LOSE_CONTEXT_ON_RESET_ARB,
};
attrib_list.AppendElements(robust_attribs,
MOZ_ARRAY_LENGTH(robust_attribs));
// X Errors can happen even if this context creation returns non-null, and
// we should not try to use such contexts. (Errors may come from the
// distant server, or something)
OffMainThreadScopedXErrorHandler handler;
glxContext = glx.fCreateContextAttribs(display, cfg, nullptr, X11True,
terminated.data());
hadError = handler.SyncAndGetError(display);
}
if (glxContext && hadError) {
glx.fDestroyContext(display, glxContext);
glxContext = nullptr;
}
if (!glxContext) return nullptr;
const RefPtr<GLContextGLX> ret =
new GLContextGLX(desc, display, drawable, glxContext, isDoubleBuffered);
if (!ret->Init()) return nullptr;
return ret;
};
std::vector<int> attribs;
attribs.insert(attribs.end(), {
LOCAL_GLX_RENDER_TYPE,
LOCAL_GLX_RGBA_TYPE,
});
if (glx.HasVideoMemoryPurge()) {
attribs.insert(attribs.end(),
{
LOCAL_GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV,
LOCAL_GL_TRUE,
});
}
const bool useCore =
!(desc.flags & CreateContextFlags::REQUIRE_COMPAT_PROFILE);
if (useCore) {
attribs.insert(attribs.end(), {
LOCAL_GLX_CONTEXT_MAJOR_VERSION_ARB,
3,
LOCAL_GLX_CONTEXT_MINOR_VERSION_ARB,
2,
LOCAL_GLX_CONTEXT_PROFILE_MASK_ARB,
LOCAL_GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
});
}
if (glx.HasRobustness()) {
auto withRobustness = attribs;
withRobustness.insert(withRobustness.end(),
{
LOCAL_GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
LOCAL_GLX_LOSE_CONTEXT_ON_RESET_ARB,
});
{
auto withRBAB = withRobustness;
withRBAB.insert(withRBAB.end(),
{
LOCAL_GLX_CONTEXT_FLAGS_ARB,
LOCAL_GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB,
});
if (!glContext) {
glContext = CreateWithAttribs(withRBAB);
if (!glContext) {
NS_WARNING("Failed to create+init GLContextGLX with RBAB");
}
}
if (glx.HasVideoMemoryPurge()) {
const int memory_purge_attribs[] = {
LOCAL_GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV,
LOCAL_GL_TRUE,
};
attrib_list.AppendElements(memory_purge_attribs,
MOZ_ARRAY_LENGTH(memory_purge_attribs));
}
if (!glContext) {
glContext = CreateWithAttribs(withRobustness);
if (!glContext) {
NS_WARNING("Failed to create+init GLContextGLX with Robustness");
}
if (!(desc.flags & CreateContextFlags::REQUIRE_COMPAT_PROFILE)) {
int core_attribs[] = {
LOCAL_GLX_CONTEXT_MAJOR_VERSION_ARB,
3,
LOCAL_GLX_CONTEXT_MINOR_VERSION_ARB,
2,
LOCAL_GLX_CONTEXT_PROFILE_MASK_ARB,
LOCAL_GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
};
attrib_list.AppendElements(core_attribs,
MOZ_ARRAY_LENGTH(core_attribs));
};
attrib_list.AppendElement(0);
context = glx.fCreateContextAttribs(display, cfg, nullptr, X11True,
attrib_list.Elements());
} else {
context = glx.fCreateNewContext(display, cfg, LOCAL_GLX_RGBA_TYPE,
nullptr, X11True);
}
}
if (context) {
glContext = new GLContextGLX(desc, display, drawable, context,
deleteDrawable, db, pixmap);
if (!glContext->Init()) error = true;
} else {
error = true;
if (!glContext) {
glContext = CreateWithAttribs(attribs);
if (!glContext) {
NS_WARNING("Failed to create+init GLContextGLX with required attribs");
}
}
error |= xErrorHandler.SyncAndGetError(display);
if (error) {
NS_WARNING("Failed to create GLXContext!");
glContext = nullptr; // note: this must be done while the graceful X
// error handler is set, because glxMakeCurrent can
// give a GLXBadDrawable error
}
return glContext.forget();
} while (true);
return glContext;
}
GLContextGLX::~GLContextGLX() {
MarkDestroyed();
// Wrapped context should not destroy glxContext/Surface
if (!mOwnsContext) {
return;
}
// see bug 659842 comment 76
#ifdef DEBUG
bool success =
#endif
mGLX->fMakeCurrent(mDisplay, X11None, nullptr);
const bool success = mGLX->fMakeCurrent(mDisplay, 0, nullptr);
MOZ_ASSERT(success,
"glXMakeCurrent failed to release GL context before we call "
"glXDestroyContext!");
(void)success;
mGLX->fDestroyContext(mDisplay, mContext);
if (mDeleteDrawable) {
mGLX->fDestroyPixmap(mDisplay, mDrawable);
if (mPbuffer) {
mGLX->fDestroyPbuffer(mDisplay, mPbuffer);
}
}
@ -672,16 +717,13 @@ bool GLContextGLX::RestoreDrawable() {
GLContextGLX::GLContextGLX(const GLContextDesc& desc, Display* aDisplay,
GLXDrawable aDrawable, GLXContext aContext,
bool aDeleteDrawable, bool aDoubleBuffered,
gfxXlibSurface* aPixmap)
bool aDoubleBuffered)
: GLContext(desc, nullptr),
mContext(aContext),
mDisplay(aDisplay),
mDrawable(aDrawable),
mDeleteDrawable(aDeleteDrawable),
mDoubleBuffered(aDoubleBuffered),
mGLX(&sGLXLibrary),
mPixmap(aPixmap) {}
mGLX(&sGLXLibrary) {}
static bool AreCompatibleVisuals(Visual* one, Visual* two) {
if (one->c_class != two->c_class) {
@ -700,9 +742,9 @@ static bool AreCompatibleVisuals(Visual* one, Visual* two) {
return true;
}
already_AddRefed<GLContext> CreateForWidget(Display* aXDisplay, Window aXWindow,
bool aWebRender,
bool aForceAccelerated) {
static RefPtr<GLContext> CreateForWidget(Display* aXDisplay, Window aXWindow,
bool aWebRender,
bool aForceAccelerated) {
if (!sGLXLibrary.EnsureInitialized()) {
return nullptr;
}
@ -736,7 +778,7 @@ already_AddRefed<GLContext> CreateForWidget(Display* aXDisplay, Window aXWindow,
flags = CreateContextFlags::REQUIRE_COMPAT_PROFILE;
}
return GLContextGLX::CreateGLContext({{flags}, false}, aXDisplay, aXWindow,
config, false, nullptr);
config);
}
already_AddRefed<GLContext> GLContextProviderGLX::CreateForCompositorWidget(
@ -749,66 +791,9 @@ already_AddRefed<GLContext> GLContextProviderGLX::CreateForCompositorWidget(
GtkCompositorWidget* compWidget = aCompositorWidget->AsX11();
MOZ_ASSERT(compWidget);
return CreateForWidget(compWidget->XDisplay(), compWidget->XWindow(),
aWebRender, aForceAccelerated);
}
static bool ChooseConfig(GLXLibrary* glx, Display* display, int screen,
ScopedXFree<GLXFBConfig>* const out_scopedConfigArr,
GLXFBConfig* const out_config, int* const out_visid) {
ScopedXFree<GLXFBConfig>& scopedConfigArr = *out_scopedConfigArr;
int attribs[] = {LOCAL_GLX_DRAWABLE_TYPE,
LOCAL_GLX_PIXMAP_BIT,
LOCAL_GLX_X_RENDERABLE,
X11True,
LOCAL_GLX_RED_SIZE,
8,
LOCAL_GLX_GREEN_SIZE,
8,
LOCAL_GLX_BLUE_SIZE,
8,
LOCAL_GLX_ALPHA_SIZE,
8,
LOCAL_GLX_DEPTH_SIZE,
0,
LOCAL_GLX_STENCIL_SIZE,
0,
0};
int numConfigs = 0;
scopedConfigArr = glx->fChooseFBConfig(display, screen, attribs, &numConfigs);
if (!scopedConfigArr || !numConfigs) return false;
// Issues with glxChooseFBConfig selection and sorting:
// * ALPHA_SIZE is sorted as 'largest total RGBA bits first'. If we don't
// request
// alpha bits, we'll probably get RGBA anyways, since 32 is more than 24.
// * DEPTH_SIZE is sorted largest first, including for `0` inputs.
// * STENCIL_SIZE is smallest first, but it might return `8` even though we
// ask for
// `0`.
// For now, we don't care about these. We *will* care when we do XPixmap
// sharing.
for (int i = 0; i < numConfigs; ++i) {
GLXFBConfig curConfig = scopedConfigArr[i];
int visid;
if (glx->fGetFBConfigAttrib(display, curConfig, LOCAL_GLX_VISUAL_ID,
&visid) != Success) {
continue;
}
if (!visid) continue;
*out_config = curConfig;
*out_visid = visid;
return true;
}
return false;
auto ret = CreateForWidget(compWidget->XDisplay(), compWidget->XWindow(),
aWebRender, aForceAccelerated);
return ret.forget();
}
bool GLContextGLX::FindVisual(Display* display, int screen, bool useWebRender,
@ -896,13 +881,19 @@ bool GLContextGLX::FindFBConfigForWindow(
ScopedXFree<GLXFBConfig>& cfgs = *out_scopedConfigArr;
int numConfigs;
const int webrenderAttribs[] = {LOCAL_GLX_ALPHA_SIZE,
windowAttrs.depth == 32 ? 8 : 0,
LOCAL_GLX_DEPTH_SIZE,
24,
LOCAL_GLX_DOUBLEBUFFER,
X11True,
0};
const int webrenderAttribs[] = {
LOCAL_GLX_RENDER_TYPE,
LOCAL_GLX_RGBA_BIT,
LOCAL_GLX_DRAWABLE_TYPE,
LOCAL_GLX_WINDOW_BIT,
LOCAL_GLX_ALPHA_SIZE,
windowAttrs.depth == 32 ? 8 : 0,
LOCAL_GLX_DEPTH_SIZE,
24,
LOCAL_GLX_DOUBLEBUFFER,
X11True,
0,
};
if (aWebRender) {
cfgs = sGLXLibrary.fChooseFBConfig(display, screen, webrenderAttribs,
@ -962,61 +953,76 @@ bool GLContextGLX::FindFBConfigForWindow(
return false;
}
static already_AddRefed<GLContextGLX> CreateOffscreenPixmapContext(
const GLContextCreateDesc& desc, const IntSize& size,
nsACString* const out_failureId) {
GLXLibrary* glx = &sGLXLibrary;
if (!glx->EnsureInitialized()) return nullptr;
Display* display = DefaultXDisplay();
int screen = DefaultScreen(display);
ScopedXFree<GLXFBConfig> scopedConfigArr;
GLXFBConfig config;
int 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);
OffMainThreadScopedXErrorHandler xErrorHandler;
bool error = false;
gfx::IntSize dummySize(16, 16);
RefPtr<gfxXlibSurface> surface = gfxXlibSurface::Create(
DefaultScreenOfDisplay(display), visual, dummySize);
if (surface->CairoStatus() != 0) {
mozilla::Unused << xErrorHandler.SyncAndGetError(display);
return nullptr;
}
// Handle slightly different signature between glXCreatePixmap and
// 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);
if (pixmap == 0) {
error = true;
}
bool serverError = xErrorHandler.SyncAndGetError(display);
if (error || serverError) return nullptr;
auto fullDesc = GLContextDesc{desc};
fullDesc.isOffscreen = true;
return GLContextGLX::CreateGLContext(fullDesc, display, pixmap, config, true,
surface);
}
/*static*/
already_AddRefed<GLContext> GLContextProviderGLX::CreateHeadless(
const GLContextCreateDesc& desc, nsACString* const out_failureId) {
IntSize dummySize = IntSize(16, 16);
return CreateOffscreenPixmapContext(desc, dummySize, out_failureId);
GLXLibrary* glx = &sGLXLibrary;
if (!glx->EnsureInitialized()) return nullptr;
const auto display = DefaultXDisplay();
const auto screen = DefaultScreen(display);
// -
// Choose any fbconfig, since we won't be using it.
std::vector<int> configAttribs;
configAttribs.insert(configAttribs.end(), {
LOCAL_GLX_RENDER_TYPE,
LOCAL_GLX_RGBA_BIT,
LOCAL_GLX_DRAWABLE_TYPE,
LOCAL_GLX_PBUFFER_BIT,
});
constexpr bool WORKAROUND_X_CREATEPIXMAP_BADVALUE = true;
if (WORKAROUND_X_CREATEPIXMAP_BADVALUE) {
configAttribs.insert(configAttribs.end(), {
LOCAL_GLX_RED_SIZE,
8,
LOCAL_GLX_GREEN_SIZE,
8,
LOCAL_GLX_BLUE_SIZE,
8,
LOCAL_GLX_ALPHA_SIZE,
8,
});
}
configAttribs.push_back(0);
int numConfigs = 0;
ScopedXFree<GLXFBConfig> configArr;
configArr =
glx->fChooseFBConfig(display, screen, configAttribs.data(), &numConfigs);
if (!configArr || !numConfigs) {
*out_failureId = "FEATURE_FAILURE_GLX_HEADLESS_CONFIG"_ns;
return nullptr;
}
const auto config = configArr[0];
// -
const int pbufferAttribs[] = {
LOCAL_GLX_PBUFFER_WIDTH, 1, LOCAL_GLX_PBUFFER_HEIGHT, 1, 0,
};
// We're supposed to be able to pass null instead of attribs, but null
// crashes on llvmpipe 20.2.1.
const auto pbuffer = glx->fCreatePbuffer(display, config, pbufferAttribs);
MOZ_ASSERT(pbuffer);
if (!pbuffer) {
*out_failureId = "FEATURE_FAILURE_GLX_HEADLESS_PBUFFER"_ns;
return nullptr;
}
// -
auto fullDesc = GLContextDesc{desc};
fullDesc.isOffscreen = true;
auto ret = GLContextGLX::CreateGLContext(fullDesc, display, pbuffer, config);
if (!ret) {
*out_failureId = "FEATURE_FAILURE_GLX_HEADLESS_CONTEXT"_ns;
return nullptr;
}
ret->mPbuffer = pbuffer;
return ret.forget();
}
/*static*/

View File

@ -16,6 +16,7 @@ typedef realGLboolean GLboolean;
#include "X11/Xutil.h" // for XVisualInfo
#include "X11UndefineNone.h"
typedef struct __GLXcontextRec* GLXContext;
typedef XID GLXPbuffer;
typedef XID GLXPixmap;
typedef XID GLXDrawable;
/* GLX 1.3 and later */
@ -37,29 +38,29 @@ class GLXLibrary final {
private:
void BeforeGLXCall() const;
void AfterGLXCall() const;
void AfterGLXCall(const char*) const;
public:
#ifdef DEBUG
# define BEFORE_CALL BeforeGLXCall();
# define AFTER_CALL AfterGLXCall();
# define AFTER_CALL(S) AfterGLXCall(S);
#else
# define BEFORE_CALL
# define AFTER_CALL
# define AFTER_CALL(S)
#endif
#define WRAP(X) \
{ \
BEFORE_CALL \
const auto ret = mSymbols.X; \
AFTER_CALL \
AFTER_CALL(__func__) \
return ret; \
}
#define VOID_WRAP(X) \
{ \
BEFORE_CALL \
mSymbols.X; \
AFTER_CALL \
#define VOID_WRAP(X) \
{ \
BEFORE_CALL \
mSymbols.X; \
AFTER_CALL(__func__) \
}
void fDestroyContext(Display* display, GLXContext context) const
@ -110,6 +111,10 @@ class GLXLibrary final {
char* fQueryServerString(Display* display, int screen, int name) const
WRAP(fQueryServerString(display, screen, name))
GLXPbuffer fCreatePbuffer(Display* display, GLXFBConfig config,
const int* attrib_list) const
WRAP(fCreatePbuffer(display, config, attrib_list))
GLXPixmap fCreatePixmap(Display* display, GLXFBConfig config,
Pixmap pixmap, const int* attrib_list) const
WRAP(fCreatePixmap(display, config, pixmap, attrib_list))
@ -119,6 +124,9 @@ class GLXLibrary final {
Pixmap pixmap) const
WRAP(fCreateGLXPixmapWithConfig(display, config, pixmap))
void fDestroyPbuffer(Display* display, GLXPbuffer pbuffer) const
VOID_WRAP(fDestroyPbuffer(display, pbuffer))
void fDestroyPixmap(Display* display, GLXPixmap pixmap) const
VOID_WRAP(fDestroyPixmap(display, pixmap))
@ -207,10 +215,12 @@ class GLXLibrary final {
const char*(GLAPIENTRY* fQueryExtensionsString)(Display*, int);
const char*(GLAPIENTRY* fGetClientString)(Display*, int);
const char*(GLAPIENTRY* fQueryServerString)(Display*, int, int);
GLXPbuffer(GLAPIENTRY* fCreatePbuffer)(Display*, GLXFBConfig, const int*);
GLXPixmap(GLAPIENTRY* fCreatePixmap)(Display*, GLXFBConfig, Pixmap,
const int*);
GLXPixmap(GLAPIENTRY* fCreateGLXPixmapWithConfig)(Display*, GLXFBConfig,
Pixmap);
void(GLAPIENTRY* fDestroyPbuffer)(Display*, GLXPbuffer);
void(GLAPIENTRY* fDestroyPixmap)(Display*, GLXPixmap);
Bool(GLAPIENTRY* fQueryVersion)(Display*, int*, int*);
void(GLAPIENTRY* fWaitGL)();

View File

@ -649,8 +649,8 @@ class GtkVsyncSource final : public VsyncSource {
return;
}
mGLContext = gl::GLContextGLX::CreateGLContext({}, mXDisplay, root,
config, false, nullptr);
mGLContext =
gl::GLContextGLX::CreateGLContext({}, mXDisplay, root, config);
if (!mGLContext) {
lock.NotifyAll();