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