199eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth
299eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth/*
399eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth * Copyright 2016 Google Inc.
499eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth *
599eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth * Use of this source code is governed by a BSD-style license that can be
699eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth * found in the LICENSE file.
799eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth */
899eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth
9d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon#include "../GLWindowContext.h"
10d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon#include "WindowContextFactory_unix.h"
1199eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth
1299eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth#include <GL/gl.h>
1399eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth
14d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomonusing sk_app::window_context_factory::XlibWindowInfo;
15d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomonusing sk_app::DisplayParams;
16d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomonusing sk_app::GLWindowContext;
1799eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth
18d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomonnamespace {
1999eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth
20d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomonclass GLWindowContext_xlib : public GLWindowContext {
21d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomonpublic:
22d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon    GLWindowContext_xlib(const XlibWindowInfo&, const DisplayParams&);
23d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon    ~GLWindowContext_xlib() override;
2499eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth
25d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon    void onSwapBuffers() override;
2699eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth
27d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon    void onDestroyContext() override;
2899eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth
29d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomonprotected:
30d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon    void onInitializeContext() override;
3199eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth
32d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomonprivate:
33d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon    GLWindowContext_xlib(void*, const DisplayParams&);
3499eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth
35d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon    Display*     fDisplay;
36d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon    XWindow      fWindow;
37837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon    GLXFBConfig* fFBConfig;
38d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon    XVisualInfo* fVisualInfo;
39d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon    GLXContext   fGLContext;
40fbdc080d3cae3695544ffbc05c6ff6f5b4514c02Jim Van Verth
41fbdc080d3cae3695544ffbc05c6ff6f5b4514c02Jim Van Verth    typedef GLWindowContext INHERITED;
42d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon};
4399eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth
44d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomonGLWindowContext_xlib::GLWindowContext_xlib(const XlibWindowInfo& winInfo, const DisplayParams& params)
45fbdc080d3cae3695544ffbc05c6ff6f5b4514c02Jim Van Verth        : INHERITED(params)
46d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon        , fDisplay(winInfo.fDisplay)
47d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon        , fWindow(winInfo.fWindow)
48837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon        , fFBConfig(winInfo.fFBConfig)
49d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon        , fVisualInfo(winInfo.fVisualInfo)
50d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon        , fGLContext() {
51443ec1b794ec5ec8a155a9cdc641e95a95914533Christopher Dalton    fWidth = winInfo.fWidth;
52443ec1b794ec5ec8a155a9cdc641e95a95914533Christopher Dalton    fHeight = winInfo.fHeight;
53d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon    this->initializeContext();
54d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon}
5599eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth
56837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomonusing CreateContextAttribsFn = GLXContext(Display*, GLXFBConfig, GLXContext, Bool, const int*);
57837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon
58d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomonvoid GLWindowContext_xlib::onInitializeContext() {
59d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon    SkASSERT(fDisplay);
60837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon    SkASSERT(!fGLContext);
61837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon    // We attempt to use glXCreateContextAttribsARB as RenderDoc requires that the context be
62837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon    // created with this rather than glXCreateContext.
63837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon    CreateContextAttribsFn* createContextAttribs = (CreateContextAttribsFn*)glXGetProcAddressARB(
64837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon            (const GLubyte*)"glXCreateContextAttribsARB");
65837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon    if (createContextAttribs && fFBConfig) {
66837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon        // Specifying 3.2 allows an arbitrarily high context version (so long as no 3.2 features
67837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon        // have been removed).
68837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon        for (int minor = 2; minor >= 0 && !fGLContext; --minor) {
69837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon            // Ganesh prefers a compatibility profile for possible NVPR support. However, RenderDoc
70837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon            // requires a core profile. Edit this code to use RenderDoc.
71837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon            for (int profile : {GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
72837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon                                GLX_CONTEXT_CORE_PROFILE_BIT_ARB}) {
73837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon                int attribs[] = {
74837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon                        GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, minor,
75837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon                        GLX_CONTEXT_PROFILE_MASK_ARB, profile,
76837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon                        0
77837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon                };
78837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon                fGLContext = createContextAttribs(fDisplay, *fFBConfig, nullptr, True, attribs);
79837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon                if (fGLContext) {
80837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon                    break;
81837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon                }
82837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon            }
83837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon        }
84837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon    }
85837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon    if (!fGLContext) {
86837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon        fGLContext = glXCreateContext(fDisplay, fVisualInfo, nullptr, GL_TRUE);
87837fcb68ff5bddbd30f6994fa859a1d98745ccadBrian Salomon    }
8899eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth    if (!fGLContext) {
8999eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth        return;
9099eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth    }
9199eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth
9299eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth    if (glXMakeCurrent(fDisplay, fWindow, fGLContext)) {
9399eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth        glClearStencil(0);
9499eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth        glClearColor(0, 0, 0, 0);
9599eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth        glStencilMask(0xffffffff);
9699eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth        glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
9799eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth
9899eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth        glXGetConfig(fDisplay, fVisualInfo, GLX_STENCIL_SIZE, &fStencilBits);
9999eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth        glXGetConfig(fDisplay, fVisualInfo, GLX_SAMPLES_ARB, &fSampleCount);
10099eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth
10199eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth        XWindow root;
10299eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth        int x, y;
10399eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth        unsigned int border_width, depth;
10499eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth        XGetGeometry(fDisplay, fWindow, &root, &x, &y,
105d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon                     (unsigned int*)&fWidth, (unsigned int*)&fHeight, &border_width, &depth);
10699eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth        glViewport(0, 0, fWidth, fHeight);
10799eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth    }
10899eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth}
10999eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth
110d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomonGLWindowContext_xlib::~GLWindowContext_xlib() {
111d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon    this->destroyContext();
112d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon}
113d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon
114d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomonvoid GLWindowContext_xlib::onDestroyContext() {
11599eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth    if (!fDisplay || !fGLContext) {
11699eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth        return;
11799eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth    }
11899eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth    glXMakeCurrent(fDisplay, None, nullptr);
11999eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth    glXDestroyContext(fDisplay, fGLContext);
12099eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth    fGLContext = nullptr;
12199eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth}
12299eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth
123d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomonvoid GLWindowContext_xlib::onSwapBuffers() {
12499eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth    if (fDisplay && fGLContext) {
12599eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth        glXSwapBuffers(fDisplay, fWindow);
12699eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth    }
12799eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth}
12899eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth
129d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon}  // anonymous namespace
130d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon
131d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomonnamespace sk_app {
132d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon
133d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomonnamespace window_context_factory {
134d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon
135d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomonWindowContext* NewGLForXlib(const XlibWindowInfo& winInfo, const DisplayParams& params) {
136d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon    WindowContext* ctx = new GLWindowContext_xlib(winInfo, params);
137d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon    if (!ctx->isValid()) {
138d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon        delete ctx;
139d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon        return nullptr;
140d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon    }
141d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon    return ctx;
142d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon}
143d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon
144d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon}  // namespace window_context_factory
14599eb6e2d5abab2cb74e3d413fc99d5cbbfac8765jvanverth
146d1bdd1fcbd308afb9903f39d231742f5c951cf07bsalomon}  // namespace sk_app
147