xref: /aosp_15_r20/external/skia/tools/window/unix/GaneshGLWindowContext_unix.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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