1*c8dee2aaSAndroid Build Coastguard Worker
2*c8dee2aaSAndroid Build Coastguard Worker /*
3*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2016 Google Inc.
4*c8dee2aaSAndroid Build Coastguard Worker *
5*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
6*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
7*c8dee2aaSAndroid Build Coastguard Worker */
8*c8dee2aaSAndroid Build Coastguard Worker #include "tools/window/unix/GaneshGLWindowContext_unix.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/gl/glx/GrGLMakeGLXInterface.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/gl/GrGLInterface.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "tools/window/GLWindowContext.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "tools/window/unix/XlibWindowInfo.h"
14*c8dee2aaSAndroid Build Coastguard Worker
15*c8dee2aaSAndroid Build Coastguard Worker #include <GL/gl.h>
16*c8dee2aaSAndroid Build Coastguard Worker #include <GL/glx.h>
17*c8dee2aaSAndroid Build Coastguard Worker #include <X11/Xlib.h>
18*c8dee2aaSAndroid Build Coastguard Worker
19*c8dee2aaSAndroid Build Coastguard Worker using skwindow::DisplayParams;
20*c8dee2aaSAndroid Build Coastguard Worker using skwindow::XlibWindowInfo;
21*c8dee2aaSAndroid Build Coastguard Worker using skwindow::internal::GLWindowContext;
22*c8dee2aaSAndroid Build Coastguard Worker
23*c8dee2aaSAndroid Build Coastguard Worker namespace {
24*c8dee2aaSAndroid Build Coastguard Worker
25*c8dee2aaSAndroid Build Coastguard Worker static bool gCtxErrorOccurred = false;
ctxErrorHandler(Display * dpy,XErrorEvent * ev)26*c8dee2aaSAndroid Build Coastguard Worker static int ctxErrorHandler(Display* dpy, XErrorEvent* ev) {
27*c8dee2aaSAndroid Build Coastguard Worker gCtxErrorOccurred = true;
28*c8dee2aaSAndroid Build Coastguard Worker return 0;
29*c8dee2aaSAndroid Build Coastguard Worker }
30*c8dee2aaSAndroid Build Coastguard Worker
31*c8dee2aaSAndroid Build Coastguard Worker class GLWindowContext_xlib : public GLWindowContext {
32*c8dee2aaSAndroid Build Coastguard Worker public:
33*c8dee2aaSAndroid Build Coastguard Worker GLWindowContext_xlib(const XlibWindowInfo&, std::unique_ptr<const DisplayParams>);
34*c8dee2aaSAndroid Build Coastguard Worker ~GLWindowContext_xlib() override;
35*c8dee2aaSAndroid Build Coastguard Worker
36*c8dee2aaSAndroid Build Coastguard Worker void onDestroyContext() override;
37*c8dee2aaSAndroid Build Coastguard Worker
38*c8dee2aaSAndroid Build Coastguard Worker protected:
39*c8dee2aaSAndroid Build Coastguard Worker sk_sp<const GrGLInterface> onInitializeContext() override;
40*c8dee2aaSAndroid Build Coastguard Worker void onSwapBuffers() override;
41*c8dee2aaSAndroid Build Coastguard Worker
42*c8dee2aaSAndroid Build Coastguard Worker private:
43*c8dee2aaSAndroid Build Coastguard Worker GLWindowContext_xlib(void*, std::unique_ptr<const DisplayParams>);
44*c8dee2aaSAndroid Build Coastguard Worker
45*c8dee2aaSAndroid Build Coastguard Worker Display* fDisplay;
46*c8dee2aaSAndroid Build Coastguard Worker XWindow fWindow;
47*c8dee2aaSAndroid Build Coastguard Worker GLXFBConfig* fFBConfig;
48*c8dee2aaSAndroid Build Coastguard Worker XVisualInfo* fVisualInfo;
49*c8dee2aaSAndroid Build Coastguard Worker GLXContext fGLContext;
50*c8dee2aaSAndroid Build Coastguard Worker };
51*c8dee2aaSAndroid Build Coastguard Worker
GLWindowContext_xlib(const XlibWindowInfo & winInfo,std::unique_ptr<const DisplayParams> params)52*c8dee2aaSAndroid Build Coastguard Worker GLWindowContext_xlib::GLWindowContext_xlib(const XlibWindowInfo& winInfo,
53*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<const DisplayParams> params)
54*c8dee2aaSAndroid Build Coastguard Worker : GLWindowContext(std::move(params))
55*c8dee2aaSAndroid Build Coastguard Worker , fDisplay(winInfo.fDisplay)
56*c8dee2aaSAndroid Build Coastguard Worker , fWindow(winInfo.fWindow)
57*c8dee2aaSAndroid Build Coastguard Worker , fFBConfig(winInfo.fFBConfig)
58*c8dee2aaSAndroid Build Coastguard Worker , fVisualInfo(winInfo.fVisualInfo)
59*c8dee2aaSAndroid Build Coastguard Worker , fGLContext() {
60*c8dee2aaSAndroid Build Coastguard Worker fWidth = winInfo.fWidth;
61*c8dee2aaSAndroid Build Coastguard Worker fHeight = winInfo.fHeight;
62*c8dee2aaSAndroid Build Coastguard Worker this->initializeContext();
63*c8dee2aaSAndroid Build Coastguard Worker }
64*c8dee2aaSAndroid Build Coastguard Worker
65*c8dee2aaSAndroid Build Coastguard Worker using CreateContextAttribsFn = GLXContext(Display*, GLXFBConfig, GLXContext, Bool, const int*);
66*c8dee2aaSAndroid Build Coastguard Worker
make_interface()67*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<const GrGLInterface> make_interface() { return GrGLInterfaces::MakeGLX(); }
68*c8dee2aaSAndroid Build Coastguard Worker
onInitializeContext()69*c8dee2aaSAndroid Build Coastguard Worker sk_sp<const GrGLInterface> GLWindowContext_xlib::onInitializeContext() {
70*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fDisplay);
71*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fGLContext);
72*c8dee2aaSAndroid Build Coastguard Worker sk_sp<const GrGLInterface> interface;
73*c8dee2aaSAndroid Build Coastguard Worker bool current = false;
74*c8dee2aaSAndroid Build Coastguard Worker
75*c8dee2aaSAndroid Build Coastguard Worker // We attempt to use glXCreateContextAttribsARB as RenderDoc requires that the context be
76*c8dee2aaSAndroid Build Coastguard Worker // created with this rather than glXCreateContext.
77*c8dee2aaSAndroid Build Coastguard Worker CreateContextAttribsFn* createContextAttribs = (CreateContextAttribsFn*)glXGetProcAddressARB(
78*c8dee2aaSAndroid Build Coastguard Worker (const GLubyte*)"glXCreateContextAttribsARB");
79*c8dee2aaSAndroid Build Coastguard Worker if (createContextAttribs && fFBConfig) {
80*c8dee2aaSAndroid Build Coastguard Worker // Install Xlib error handler that will set gCtxErrorOccurred
81*c8dee2aaSAndroid Build Coastguard Worker int (*oldHandler)(Display*, XErrorEvent*) = XSetErrorHandler(&ctxErrorHandler);
82*c8dee2aaSAndroid Build Coastguard Worker
83*c8dee2aaSAndroid Build Coastguard Worker // Specifying 3.2 allows an arbitrarily high context version (so long as no 3.2 features
84*c8dee2aaSAndroid Build Coastguard Worker // have been removed).
85*c8dee2aaSAndroid Build Coastguard Worker for (int minor = 2; minor >= 0 && !fGLContext; --minor) {
86*c8dee2aaSAndroid Build Coastguard Worker // Ganesh prefers a core profile which incidentally allows RenderDoc to work correctly.
87*c8dee2aaSAndroid Build Coastguard Worker for (int profile :
88*c8dee2aaSAndroid Build Coastguard Worker {GLX_CONTEXT_CORE_PROFILE_BIT_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB}) {
89*c8dee2aaSAndroid Build Coastguard Worker gCtxErrorOccurred = false;
90*c8dee2aaSAndroid Build Coastguard Worker int attribs[] = {GLX_CONTEXT_MAJOR_VERSION_ARB,
91*c8dee2aaSAndroid Build Coastguard Worker 3,
92*c8dee2aaSAndroid Build Coastguard Worker GLX_CONTEXT_MINOR_VERSION_ARB,
93*c8dee2aaSAndroid Build Coastguard Worker minor,
94*c8dee2aaSAndroid Build Coastguard Worker GLX_CONTEXT_PROFILE_MASK_ARB,
95*c8dee2aaSAndroid Build Coastguard Worker profile,
96*c8dee2aaSAndroid Build Coastguard Worker 0};
97*c8dee2aaSAndroid Build Coastguard Worker fGLContext = createContextAttribs(fDisplay, *fFBConfig, nullptr, True, attribs);
98*c8dee2aaSAndroid Build Coastguard Worker
99*c8dee2aaSAndroid Build Coastguard Worker // Sync to ensure any errors generated are processed.
100*c8dee2aaSAndroid Build Coastguard Worker XSync(fDisplay, False);
101*c8dee2aaSAndroid Build Coastguard Worker if (gCtxErrorOccurred) {
102*c8dee2aaSAndroid Build Coastguard Worker continue;
103*c8dee2aaSAndroid Build Coastguard Worker }
104*c8dee2aaSAndroid Build Coastguard Worker
105*c8dee2aaSAndroid Build Coastguard Worker if (fGLContext && profile == GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB &&
106*c8dee2aaSAndroid Build Coastguard Worker glXMakeCurrent(fDisplay, fWindow, fGLContext)) {
107*c8dee2aaSAndroid Build Coastguard Worker current = true;
108*c8dee2aaSAndroid Build Coastguard Worker // Look to see if RenderDoc is attached. If so, re-create the context with a
109*c8dee2aaSAndroid Build Coastguard Worker // core profile.
110*c8dee2aaSAndroid Build Coastguard Worker interface = make_interface();
111*c8dee2aaSAndroid Build Coastguard Worker if (interface && interface->fExtensions.has("GL_EXT_debug_tool")) {
112*c8dee2aaSAndroid Build Coastguard Worker interface.reset();
113*c8dee2aaSAndroid Build Coastguard Worker glXMakeCurrent(fDisplay, None, nullptr);
114*c8dee2aaSAndroid Build Coastguard Worker glXDestroyContext(fDisplay, fGLContext);
115*c8dee2aaSAndroid Build Coastguard Worker current = false;
116*c8dee2aaSAndroid Build Coastguard Worker fGLContext = nullptr;
117*c8dee2aaSAndroid Build Coastguard Worker }
118*c8dee2aaSAndroid Build Coastguard Worker }
119*c8dee2aaSAndroid Build Coastguard Worker if (fGLContext) {
120*c8dee2aaSAndroid Build Coastguard Worker break;
121*c8dee2aaSAndroid Build Coastguard Worker }
122*c8dee2aaSAndroid Build Coastguard Worker }
123*c8dee2aaSAndroid Build Coastguard Worker }
124*c8dee2aaSAndroid Build Coastguard Worker // Restore the original error handler
125*c8dee2aaSAndroid Build Coastguard Worker XSetErrorHandler(oldHandler);
126*c8dee2aaSAndroid Build Coastguard Worker }
127*c8dee2aaSAndroid Build Coastguard Worker if (!fGLContext) {
128*c8dee2aaSAndroid Build Coastguard Worker fGLContext = glXCreateContext(fDisplay, fVisualInfo, nullptr, GL_TRUE);
129*c8dee2aaSAndroid Build Coastguard Worker }
130*c8dee2aaSAndroid Build Coastguard Worker if (!fGLContext) {
131*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
132*c8dee2aaSAndroid Build Coastguard Worker }
133*c8dee2aaSAndroid Build Coastguard Worker
134*c8dee2aaSAndroid Build Coastguard Worker if (!current && !glXMakeCurrent(fDisplay, fWindow, fGLContext)) {
135*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
136*c8dee2aaSAndroid Build Coastguard Worker }
137*c8dee2aaSAndroid Build Coastguard Worker
138*c8dee2aaSAndroid Build Coastguard Worker const char* glxExtensions = glXQueryExtensionsString(fDisplay, DefaultScreen(fDisplay));
139*c8dee2aaSAndroid Build Coastguard Worker if (glxExtensions) {
140*c8dee2aaSAndroid Build Coastguard Worker if (strstr(glxExtensions, "GLX_EXT_swap_control")) {
141*c8dee2aaSAndroid Build Coastguard Worker PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT =
142*c8dee2aaSAndroid Build Coastguard Worker (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddressARB(
143*c8dee2aaSAndroid Build Coastguard Worker (const GLubyte*)"glXSwapIntervalEXT");
144*c8dee2aaSAndroid Build Coastguard Worker glXSwapIntervalEXT(fDisplay, fWindow, fDisplayParams->disableVsync() ? 0 : 1);
145*c8dee2aaSAndroid Build Coastguard Worker }
146*c8dee2aaSAndroid Build Coastguard Worker }
147*c8dee2aaSAndroid Build Coastguard Worker
148*c8dee2aaSAndroid Build Coastguard Worker glClearStencil(0);
149*c8dee2aaSAndroid Build Coastguard Worker glClearColor(0, 0, 0, 0);
150*c8dee2aaSAndroid Build Coastguard Worker glStencilMask(0xffffffff);
151*c8dee2aaSAndroid Build Coastguard Worker glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
152*c8dee2aaSAndroid Build Coastguard Worker
153*c8dee2aaSAndroid Build Coastguard Worker glXGetConfig(fDisplay, fVisualInfo, GLX_STENCIL_SIZE, &fStencilBits);
154*c8dee2aaSAndroid Build Coastguard Worker glXGetConfig(fDisplay, fVisualInfo, GLX_SAMPLES_ARB, &fSampleCount);
155*c8dee2aaSAndroid Build Coastguard Worker fSampleCount = std::max(fSampleCount, 1);
156*c8dee2aaSAndroid Build Coastguard Worker
157*c8dee2aaSAndroid Build Coastguard Worker XWindow root;
158*c8dee2aaSAndroid Build Coastguard Worker int x, y;
159*c8dee2aaSAndroid Build Coastguard Worker unsigned int border_width, depth;
160*c8dee2aaSAndroid Build Coastguard Worker XGetGeometry(fDisplay,
161*c8dee2aaSAndroid Build Coastguard Worker fWindow,
162*c8dee2aaSAndroid Build Coastguard Worker &root,
163*c8dee2aaSAndroid Build Coastguard Worker &x,
164*c8dee2aaSAndroid Build Coastguard Worker &y,
165*c8dee2aaSAndroid Build Coastguard Worker (unsigned int*)&fWidth,
166*c8dee2aaSAndroid Build Coastguard Worker (unsigned int*)&fHeight,
167*c8dee2aaSAndroid Build Coastguard Worker &border_width,
168*c8dee2aaSAndroid Build Coastguard Worker &depth);
169*c8dee2aaSAndroid Build Coastguard Worker glViewport(0, 0, fWidth, fHeight);
170*c8dee2aaSAndroid Build Coastguard Worker
171*c8dee2aaSAndroid Build Coastguard Worker return interface ? interface : make_interface();
172*c8dee2aaSAndroid Build Coastguard Worker }
173*c8dee2aaSAndroid Build Coastguard Worker
~GLWindowContext_xlib()174*c8dee2aaSAndroid Build Coastguard Worker GLWindowContext_xlib::~GLWindowContext_xlib() { this->destroyContext(); }
175*c8dee2aaSAndroid Build Coastguard Worker
onDestroyContext()176*c8dee2aaSAndroid Build Coastguard Worker void GLWindowContext_xlib::onDestroyContext() {
177*c8dee2aaSAndroid Build Coastguard Worker if (!fDisplay || !fGLContext) {
178*c8dee2aaSAndroid Build Coastguard Worker return;
179*c8dee2aaSAndroid Build Coastguard Worker }
180*c8dee2aaSAndroid Build Coastguard Worker glXMakeCurrent(fDisplay, None, nullptr);
181*c8dee2aaSAndroid Build Coastguard Worker glXDestroyContext(fDisplay, fGLContext);
182*c8dee2aaSAndroid Build Coastguard Worker fGLContext = nullptr;
183*c8dee2aaSAndroid Build Coastguard Worker }
184*c8dee2aaSAndroid Build Coastguard Worker
onSwapBuffers()185*c8dee2aaSAndroid Build Coastguard Worker void GLWindowContext_xlib::onSwapBuffers() {
186*c8dee2aaSAndroid Build Coastguard Worker if (fDisplay && fGLContext) {
187*c8dee2aaSAndroid Build Coastguard Worker glXSwapBuffers(fDisplay, fWindow);
188*c8dee2aaSAndroid Build Coastguard Worker }
189*c8dee2aaSAndroid Build Coastguard Worker }
190*c8dee2aaSAndroid Build Coastguard Worker
191*c8dee2aaSAndroid Build Coastguard Worker } // anonymous namespace
192*c8dee2aaSAndroid Build Coastguard Worker
193*c8dee2aaSAndroid Build Coastguard Worker namespace skwindow {
194*c8dee2aaSAndroid Build Coastguard Worker
MakeGaneshGLForXlib(const XlibWindowInfo & winInfo,std::unique_ptr<const DisplayParams> params)195*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<WindowContext> MakeGaneshGLForXlib(const XlibWindowInfo& winInfo,
196*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<const DisplayParams> params) {
197*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<WindowContext> ctx(new GLWindowContext_xlib(winInfo, std::move(params)));
198*c8dee2aaSAndroid Build Coastguard Worker if (!ctx->isValid()) {
199*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
200*c8dee2aaSAndroid Build Coastguard Worker }
201*c8dee2aaSAndroid Build Coastguard Worker return ctx;
202*c8dee2aaSAndroid Build Coastguard Worker }
203*c8dee2aaSAndroid Build Coastguard Worker
204*c8dee2aaSAndroid Build Coastguard Worker } // namespace skwindow
205