• 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     typedef GLWindowContext INHERITED;
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 compatibility profile for possible NVPR support. However, RenderDoc
83             // requires a core profile. Edit this code to use RenderDoc.
84             for (int profile : {GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
85                                 GLX_CONTEXT_CORE_PROFILE_BIT_ARB}) {
86                 gCtxErrorOccurred = false;
87                 int attribs[] = {
88                         GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, minor,
89                         GLX_CONTEXT_PROFILE_MASK_ARB, profile,
90                         0
91                 };
92                 fGLContext = createContextAttribs(fDisplay, *fFBConfig, nullptr, True, attribs);
93 
94                 // Sync to ensure any errors generated are processed.
95                 XSync(fDisplay, False);
96                 if (gCtxErrorOccurred) { continue; }
97 
98                 if (fGLContext && profile == GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB &&
99                     glXMakeCurrent(fDisplay, fWindow, fGLContext)) {
100                     current = true;
101                     // Look to see if RenderDoc is attached. If so, re-create the context with a
102                     // core profile.
103                     interface = GrGLMakeNativeInterface();
104                     if (interface && interface->fExtensions.has("GL_EXT_debug_tool")) {
105                         interface.reset();
106                         glXMakeCurrent(fDisplay, None, nullptr);
107                         glXDestroyContext(fDisplay, fGLContext);
108                         current = false;
109                         fGLContext = nullptr;
110                     }
111                 }
112                 if (fGLContext) {
113                     break;
114                 }
115             }
116         }
117         // Restore the original error handler
118         XSetErrorHandler(oldHandler);
119     }
120     if (!fGLContext) {
121         fGLContext = glXCreateContext(fDisplay, fVisualInfo, nullptr, GL_TRUE);
122     }
123     if (!fGLContext) {
124         return nullptr;
125     }
126 
127     if (!current && !glXMakeCurrent(fDisplay, fWindow, fGLContext)) {
128         return nullptr;
129     }
130 
131     const char* glxExtensions = glXQueryExtensionsString(fDisplay, DefaultScreen(fDisplay));
132     if (glxExtensions) {
133         if (strstr(glxExtensions, "GLX_EXT_swap_control")) {
134             PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT =
135                     (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddressARB(
136                             (const GLubyte*)"glXSwapIntervalEXT");
137             glXSwapIntervalEXT(fDisplay, fWindow, fDisplayParams.fDisableVsync ? 0 : 1);
138         }
139     }
140 
141     glClearStencil(0);
142     glClearColor(0, 0, 0, 0);
143     glStencilMask(0xffffffff);
144     glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
145 
146     glXGetConfig(fDisplay, fVisualInfo, GLX_STENCIL_SIZE, &fStencilBits);
147     glXGetConfig(fDisplay, fVisualInfo, GLX_SAMPLES_ARB, &fSampleCount);
148     fSampleCount = SkTMax(fSampleCount, 1);
149 
150     XWindow root;
151     int x, y;
152     unsigned int border_width, depth;
153     XGetGeometry(fDisplay, fWindow, &root, &x, &y, (unsigned int*)&fWidth, (unsigned int*)&fHeight,
154                  &border_width, &depth);
155     glViewport(0, 0, fWidth, fHeight);
156 
157     return interface ? interface : GrGLMakeNativeInterface();
158 }
159 
~GLWindowContext_xlib()160 GLWindowContext_xlib::~GLWindowContext_xlib() {
161     this->destroyContext();
162 }
163 
onDestroyContext()164 void GLWindowContext_xlib::onDestroyContext() {
165     if (!fDisplay || !fGLContext) {
166         return;
167     }
168     glXMakeCurrent(fDisplay, None, nullptr);
169     glXDestroyContext(fDisplay, fGLContext);
170     fGLContext = nullptr;
171 }
172 
onSwapBuffers()173 void GLWindowContext_xlib::onSwapBuffers() {
174     if (fDisplay && fGLContext) {
175         glXSwapBuffers(fDisplay, fWindow);
176     }
177 }
178 
179 }  // anonymous namespace
180 
181 namespace sk_app {
182 
183 namespace window_context_factory {
184 
MakeGLForXlib(const XlibWindowInfo & winInfo,const DisplayParams & params)185 std::unique_ptr<WindowContext> MakeGLForXlib(const XlibWindowInfo& winInfo,
186                                              const DisplayParams& params) {
187     std::unique_ptr<WindowContext> ctx(new GLWindowContext_xlib(winInfo, params));
188     if (!ctx->isValid()) {
189         return nullptr;
190     }
191     return ctx;
192 }
193 
194 }  // namespace window_context_factory
195 
196 }  // namespace sk_app
197