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