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 "../GLWindowContext.h"
10 #include "WindowContextFactory_unix.h"
11 
12 #include <GL/gl.h>
13 
14 using sk_app::window_context_factory::XlibWindowInfo;
15 using sk_app::DisplayParams;
16 using sk_app::GLWindowContext;
17 
18 namespace {
19 
20 class GLWindowContext_xlib : public GLWindowContext {
21 public:
22     GLWindowContext_xlib(const XlibWindowInfo&, const DisplayParams&);
23     ~GLWindowContext_xlib() override;
24 
25     void onSwapBuffers() override;
26 
27     void onDestroyContext() override;
28 
29 protected:
30     void onInitializeContext() override;
31 
32 private:
33     GLWindowContext_xlib(void*, const DisplayParams&);
34 
35     Display*     fDisplay;
36     XWindow      fWindow;
37     GLXFBConfig* fFBConfig;
38     XVisualInfo* fVisualInfo;
39     GLXContext   fGLContext;
40 };
41 
GLWindowContext_xlib(const XlibWindowInfo & winInfo,const DisplayParams & params)42 GLWindowContext_xlib::GLWindowContext_xlib(const XlibWindowInfo& winInfo, const DisplayParams& params)
43         : GLWindowContext(params)
44         , fDisplay(winInfo.fDisplay)
45         , fWindow(winInfo.fWindow)
46         , fFBConfig(winInfo.fFBConfig)
47         , fVisualInfo(winInfo.fVisualInfo)
48         , fGLContext() {
49     fWidth = winInfo.fWidth;
50     fHeight = winInfo.fHeight;
51     this->initializeContext();
52 }
53 
54 using CreateContextAttribsFn = GLXContext(Display*, GLXFBConfig, GLXContext, Bool, const int*);
55 
onInitializeContext()56 void GLWindowContext_xlib::onInitializeContext() {
57     SkASSERT(fDisplay);
58     SkASSERT(!fGLContext);
59     // We attempt to use glXCreateContextAttribsARB as RenderDoc requires that the context be
60     // created with this rather than glXCreateContext.
61     CreateContextAttribsFn* createContextAttribs = (CreateContextAttribsFn*)glXGetProcAddressARB(
62             (const GLubyte*)"glXCreateContextAttribsARB");
63     if (createContextAttribs && fFBConfig) {
64         // Specifying 3.2 allows an arbitrarily high context version (so long as no 3.2 features
65         // have been removed).
66         for (int minor = 2; minor >= 0 && !fGLContext; --minor) {
67             // Ganesh prefers a compatibility profile for possible NVPR support. However, RenderDoc
68             // requires a core profile. Edit this code to use RenderDoc.
69             for (int profile : {GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
70                                 GLX_CONTEXT_CORE_PROFILE_BIT_ARB}) {
71                 int attribs[] = {
72                         GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, minor,
73                         GLX_CONTEXT_PROFILE_MASK_ARB, profile,
74                         0
75                 };
76                 fGLContext = createContextAttribs(fDisplay, *fFBConfig, nullptr, True, attribs);
77                 if (fGLContext) {
78                     break;
79                 }
80             }
81         }
82     }
83     if (!fGLContext) {
84         fGLContext = glXCreateContext(fDisplay, fVisualInfo, nullptr, GL_TRUE);
85     }
86     if (!fGLContext) {
87         return;
88     }
89 
90     if (glXMakeCurrent(fDisplay, fWindow, fGLContext)) {
91         glClearStencil(0);
92         glClearColor(0, 0, 0, 0);
93         glStencilMask(0xffffffff);
94         glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
95 
96         glXGetConfig(fDisplay, fVisualInfo, GLX_STENCIL_SIZE, &fStencilBits);
97         glXGetConfig(fDisplay, fVisualInfo, GLX_SAMPLES_ARB, &fSampleCount);
98 
99         XWindow root;
100         int x, y;
101         unsigned int border_width, depth;
102         XGetGeometry(fDisplay, fWindow, &root, &x, &y,
103                      (unsigned int*)&fWidth, (unsigned int*)&fHeight, &border_width, &depth);
104         glViewport(0, 0, fWidth, fHeight);
105     }
106 }
107 
~GLWindowContext_xlib()108 GLWindowContext_xlib::~GLWindowContext_xlib() {
109     this->destroyContext();
110 }
111 
onDestroyContext()112 void GLWindowContext_xlib::onDestroyContext() {
113     if (!fDisplay || !fGLContext) {
114         return;
115     }
116     glXMakeCurrent(fDisplay, None, nullptr);
117     glXDestroyContext(fDisplay, fGLContext);
118     fGLContext = nullptr;
119 }
120 
onSwapBuffers()121 void GLWindowContext_xlib::onSwapBuffers() {
122     if (fDisplay && fGLContext) {
123         glXSwapBuffers(fDisplay, fWindow);
124     }
125 }
126 
127 }  // anonymous namespace
128 
129 namespace sk_app {
130 
131 namespace window_context_factory {
132 
NewGLForXlib(const XlibWindowInfo & winInfo,const DisplayParams & params)133 WindowContext* NewGLForXlib(const XlibWindowInfo& winInfo, const DisplayParams& params) {
134     WindowContext* ctx = new GLWindowContext_xlib(winInfo, params);
135     if (!ctx->isValid()) {
136         delete ctx;
137         return nullptr;
138     }
139     return ctx;
140 }
141 
142 }  // namespace window_context_factory
143 
144 }  // namespace sk_app
145