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