1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc.
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
7300178b1c83e7a9b8d3bee7aeb09e0d4fb096d6bbsalomon
8273c0f5e87397c40d22bb7e3ee078bb46a3f6860bsalomon#include "gl/GLTestContext.h"
9300178b1c83e7a9b8d3bee7aeb09e0d4fb096d6bbsalomon#include "SkOnce.h"
1016bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com
119e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen#include <X11/Xlib.h>
129e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen#include <GL/glx.h>
1316bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com#include <GL/glu.h>
1416bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com
15fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova#include <vector>
16fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova#include <utility>
17fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova
189e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunennamespace {
1910805961ce424868e8315e00f6dbeeaa62d466acbsalomon
209e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen/* Note: Skia requires glx 1.3 or newer */
2110805961ce424868e8315e00f6dbeeaa62d466acbsalomon
229e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen/* This struct is taken from a mesa demo.  Please update as required */
23fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarovastatic const std::vector<std::pair<int, int>> gl_versions = {
249e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen   {1, 0},
259e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen   {1, 1},
269e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen   {1, 2},
279e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen   {1, 3},
289e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen   {1, 4},
299e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen   {1, 5},
309e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen   {2, 0},
319e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen   {2, 1},
329e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen   {3, 0},
339e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen   {3, 1},
349e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen   {3, 2},
359e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen   {3, 3},
369e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen   {4, 0},
379e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen   {4, 1},
389e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen   {4, 2},
399e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen   {4, 3},
409e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen   {4, 4},
419e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen};
42fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova
43fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarovastatic const std::vector<std::pair<int, int>> gles_versions = {
44fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova    {2, 0},
45fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova    {3, 0},
46fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova};
4716bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com
4816bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.comstatic bool ctxErrorOccurred = false;
4916bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.comstatic int ctxErrorHandler(Display *dpy, XErrorEvent *ev) {
5016bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    ctxErrorOccurred = true;
5116bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    return 0;
5216bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com}
5316bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com
54273c0f5e87397c40d22bb7e3ee078bb46a3f6860bsalomonclass GLXGLTestContext : public sk_gpu_test::GLTestContext {
559e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunenpublic:
56273c0f5e87397c40d22bb7e3ee078bb46a3f6860bsalomon    GLXGLTestContext(GrGLStandard forcedGpuAPI, GLXGLTestContext* shareList);
57273c0f5e87397c40d22bb7e3ee078bb46a3f6860bsalomon    ~GLXGLTestContext() override;
589e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen
599e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunenprivate:
6030bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen    void destroyGLContext();
61fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova    static GLXContext CreateBestContext(bool isES, Display* display, GLXFBConfig bestFbc,
62fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova                                        GLXContext glxSharedContext);
6330bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen
64d416a5b10ff9e6d4f55a1f5b0419722132d68ff3cdalton    void onPlatformMakeCurrent() const override;
65d416a5b10ff9e6d4f55a1f5b0419722132d68ff3cdalton    void onPlatformSwapBuffers() const override;
66d416a5b10ff9e6d4f55a1f5b0419722132d68ff3cdalton    GrGLFuncPtr onPlatformGetProcAddress(const char*) const override;
67d416a5b10ff9e6d4f55a1f5b0419722132d68ff3cdalton
689e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen    GLXContext fContext;
699e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen    Display* fDisplay;
709e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen    Pixmap fPixmap;
719e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen    GLXPixmap fGlxPixmap;
729e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen};
739e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen
74300178b1c83e7a9b8d3bee7aeb09e0d4fb096d6bbsalomonstatic Display* get_display() {
75300178b1c83e7a9b8d3bee7aeb09e0d4fb096d6bbsalomon    class AutoDisplay {
76300178b1c83e7a9b8d3bee7aeb09e0d4fb096d6bbsalomon    public:
77fc6c37b981daeece7474ce61070c707c37eefa62Mike Klein        AutoDisplay() { fDisplay = XOpenDisplay(nullptr); }
78300178b1c83e7a9b8d3bee7aeb09e0d4fb096d6bbsalomon        ~AutoDisplay() {
79300178b1c83e7a9b8d3bee7aeb09e0d4fb096d6bbsalomon            if (fDisplay) {
80300178b1c83e7a9b8d3bee7aeb09e0d4fb096d6bbsalomon                XCloseDisplay(fDisplay);
81300178b1c83e7a9b8d3bee7aeb09e0d4fb096d6bbsalomon            }
82300178b1c83e7a9b8d3bee7aeb09e0d4fb096d6bbsalomon        }
83300178b1c83e7a9b8d3bee7aeb09e0d4fb096d6bbsalomon        Display* display() const { return fDisplay; }
84300178b1c83e7a9b8d3bee7aeb09e0d4fb096d6bbsalomon    private:
85300178b1c83e7a9b8d3bee7aeb09e0d4fb096d6bbsalomon        Display* fDisplay;
86300178b1c83e7a9b8d3bee7aeb09e0d4fb096d6bbsalomon    };
87300178b1c83e7a9b8d3bee7aeb09e0d4fb096d6bbsalomon    static std::unique_ptr<AutoDisplay> ad;
88300178b1c83e7a9b8d3bee7aeb09e0d4fb096d6bbsalomon    static SkOnce once;
89300178b1c83e7a9b8d3bee7aeb09e0d4fb096d6bbsalomon    once([] { ad.reset(new AutoDisplay{}); });
90300178b1c83e7a9b8d3bee7aeb09e0d4fb096d6bbsalomon    return ad->display();
91300178b1c83e7a9b8d3bee7aeb09e0d4fb096d6bbsalomon}
92300178b1c83e7a9b8d3bee7aeb09e0d4fb096d6bbsalomon
93273c0f5e87397c40d22bb7e3ee078bb46a3f6860bsalomonGLXGLTestContext::GLXGLTestContext(GrGLStandard forcedGpuAPI, GLXGLTestContext* shareContext)
9496fcdcc219d2a0d3579719b84b28bede76efba64halcanary    : fContext(nullptr)
9596fcdcc219d2a0d3579719b84b28bede76efba64halcanary    , fDisplay(nullptr)
96373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com    , fPixmap(0)
97373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com    , fGlxPixmap(0) {
98300178b1c83e7a9b8d3bee7aeb09e0d4fb096d6bbsalomon    fDisplay = get_display();
9916bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com
100b59d1bc7a8596f346d57a9cfcd461dddc6d75edbjoshualitt    GLXContext glxShareContext = shareContext ? shareContext->fContext : nullptr;
101b59d1bc7a8596f346d57a9cfcd461dddc6d75edbjoshualitt
102373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com    if (!fDisplay) {
10316bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com        SkDebugf("Failed to open X display.\n");
104373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com        this->destroyGLContext();
10530bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        return;
10616bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    }
10716bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com
10816bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    // Get a matching FB config
10916bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    static int visual_attribs[] = {
11016bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com        GLX_X_RENDERABLE    , True,
11116bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com        GLX_DRAWABLE_TYPE   , GLX_PIXMAP_BIT,
11216bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com        None
11316bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    };
11416bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com
115c863ab07c207aac5aae8b1593a2767a946682bcajoshualitt    int glx_major, glx_minor;
116c863ab07c207aac5aae8b1593a2767a946682bcajoshualitt
117c863ab07c207aac5aae8b1593a2767a946682bcajoshualitt    // FBConfigs were added in GLX version 1.3.
118c863ab07c207aac5aae8b1593a2767a946682bcajoshualitt    if (!glXQueryVersion(fDisplay, &glx_major, &glx_minor) ||
119c863ab07c207aac5aae8b1593a2767a946682bcajoshualitt            ((glx_major == 1) && (glx_minor < 3)) || (glx_major < 1)) {
120c863ab07c207aac5aae8b1593a2767a946682bcajoshualitt        SkDebugf("GLX version 1.3 or higher required.\n");
121c863ab07c207aac5aae8b1593a2767a946682bcajoshualitt        this->destroyGLContext();
12230bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        return;
123c863ab07c207aac5aae8b1593a2767a946682bcajoshualitt    }
124c863ab07c207aac5aae8b1593a2767a946682bcajoshualitt
12516bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    //SkDebugf("Getting matching framebuffer configs.\n");
12616bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    int fbcount;
127373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com    GLXFBConfig *fbc = glXChooseFBConfig(fDisplay, DefaultScreen(fDisplay),
12816bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com                                          visual_attribs, &fbcount);
12916bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    if (!fbc) {
13016bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com        SkDebugf("Failed to retrieve a framebuffer config.\n");
131373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com        this->destroyGLContext();
13230bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        return;
13316bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    }
13416bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    //SkDebugf("Found %d matching FB configs.\n", fbcount);
13516bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com
13616bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    // Pick the FB config/visual with the most samples per pixel
13716bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    //SkDebugf("Getting XVisualInfos.\n");
138bb89cda7e799bdec58c026a447363024a4bc1a5arobertphillips@google.com    int best_fbc = -1, best_num_samp = -1;
13916bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com
14016bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    int i;
14116bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    for (i = 0; i < fbcount; ++i) {
142373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com        XVisualInfo *vi = glXGetVisualFromFBConfig(fDisplay, fbc[i]);
14316bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com        if (vi) {
14416bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com            int samp_buf, samples;
145373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com            glXGetFBConfigAttrib(fDisplay, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
146373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com            glXGetFBConfigAttrib(fDisplay, fbc[i], GLX_SAMPLES, &samples);
14716bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com
14816bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com            //SkDebugf("  Matching fbconfig %d, visual ID 0x%2x: SAMPLE_BUFFERS = %d,"
14916bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com            //       " SAMPLES = %d\n",
15016bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com            //        i, (unsigned int)vi->visualid, samp_buf, samples);
15116bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com
15219eb8435cbce1200667024079750c6494b02079fMike Klein            if (best_fbc < 0 || (samp_buf && samples > best_num_samp)) {
15319eb8435cbce1200667024079750c6494b02079fMike Klein                best_fbc = i;
15419eb8435cbce1200667024079750c6494b02079fMike Klein                best_num_samp = samples;
15519eb8435cbce1200667024079750c6494b02079fMike Klein            }
156fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com        }
15716bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com        XFree(vi);
15816bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    }
15916bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com
16016bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    GLXFBConfig bestFbc = fbc[best_fbc];
16116bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com
16216bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    // Be sure to free the FBConfig list allocated by glXChooseFBConfig()
16316bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    XFree(fbc);
16416bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com
16516bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    // Get a visual
166373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com    XVisualInfo *vi = glXGetVisualFromFBConfig(fDisplay, bestFbc);
16716bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    //SkDebugf("Chosen visual ID = 0x%x\n", (unsigned int)vi->visualid);
16816bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com
169373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com    fPixmap = XCreatePixmap(fDisplay, RootWindow(fDisplay, vi->screen), 10, 10, vi->depth);
17016bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com
171373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com    if (!fPixmap) {
17216bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com        SkDebugf("Failed to create pixmap.\n");
173373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com        this->destroyGLContext();
17430bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        return;
17516bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    }
17616bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com
177373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com    fGlxPixmap = glXCreateGLXPixmap(fDisplay, vi, fPixmap);
17816bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com
17916bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    // Done with the visual info data
18016bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    XFree(vi);
18116bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com
18216bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    // Get the default screen's GLX extension list
18316bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    const char *glxExts = glXQueryExtensionsString(
184373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com        fDisplay, DefaultScreen(fDisplay)
18516bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    );
18616bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    // Check for the GLX_ARB_create_context extension string and the function.
18716bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    // If either is not present, use GLX 1.3 context creation method.
18880549fcdd50269d7e069d6db02b395fca128056ckkinnunen    if (!gluCheckExtension(reinterpret_cast<const GLubyte*>("GLX_ARB_create_context"),
18980549fcdd50269d7e069d6db02b395fca128056ckkinnunen                           reinterpret_cast<const GLubyte*>(glxExts))) {
19080549fcdd50269d7e069d6db02b395fca128056ckkinnunen        if (kGLES_GrGLStandard != forcedGpuAPI) {
19180549fcdd50269d7e069d6db02b395fca128056ckkinnunen            fContext = glXCreateNewContext(fDisplay, bestFbc, GLX_RGBA_TYPE, 0, True);
19280549fcdd50269d7e069d6db02b395fca128056ckkinnunen        }
193c863ab07c207aac5aae8b1593a2767a946682bcajoshualitt    } else {
19480549fcdd50269d7e069d6db02b395fca128056ckkinnunen        if (kGLES_GrGLStandard == forcedGpuAPI) {
19580549fcdd50269d7e069d6db02b395fca128056ckkinnunen            if (gluCheckExtension(
19680549fcdd50269d7e069d6db02b395fca128056ckkinnunen                    reinterpret_cast<const GLubyte*>("GLX_EXT_create_context_es2_profile"),
19780549fcdd50269d7e069d6db02b395fca128056ckkinnunen                    reinterpret_cast<const GLubyte*>(glxExts))) {
198fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova                fContext = CreateBestContext(true, fDisplay, bestFbc, glxShareContext);
19980549fcdd50269d7e069d6db02b395fca128056ckkinnunen            }
20016bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com        } else {
201fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova            fContext = CreateBestContext(false, fDisplay, bestFbc, glxShareContext);
20216bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com        }
20316bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    }
204fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova    if (!fContext) {
20516bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com        SkDebugf("Failed to create an OpenGL context.\n");
206373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com        this->destroyGLContext();
20730bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        return;
20816bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    }
20916bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com
21016bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    // Verify that context is a direct context
211373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com    if (!glXIsDirect(fDisplay, fContext)) {
21216bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com        //SkDebugf("Indirect GLX rendering context obtained.\n");
21316bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    } else {
21416bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com        //SkDebugf("Direct GLX rendering context obtained.\n");
21516bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    }
21616bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com
21716bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    //SkDebugf("Making context current.\n");
218373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com    if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) {
21916bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com      SkDebugf("Could not set the context.\n");
220373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com        this->destroyGLContext();
22130bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        return;
22216bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    }
22316bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com
2241b612a89fba2275e3effe12bdc9b6cdc2f4d9eeeHal Canary    sk_sp<const GrGLInterface> gl(GrGLCreateNativeInterface());
22596fcdcc219d2a0d3579719b84b28bede76efba64halcanary    if (nullptr == gl.get()) {
226373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com        SkDebugf("Failed to create gl interface");
227373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com        this->destroyGLContext();
22830bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        return;
22930bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen    }
23030bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen
231d416a5b10ff9e6d4f55a1f5b0419722132d68ff3cdalton    if (!gl->validate()) {
23230bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        SkDebugf("Failed to validate gl interface");
23330bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        this->destroyGLContext();
23430bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        return;
23530bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen    }
236d416a5b10ff9e6d4f55a1f5b0419722132d68ff3cdalton
23718300a3aa7cb6eb55d21bb0450dffa58b6fc062cmtklein    this->init(gl.release());
23830bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen}
23930bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen
24030bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen
241273c0f5e87397c40d22bb7e3ee078bb46a3f6860bsalomonGLXGLTestContext::~GLXGLTestContext() {
242d416a5b10ff9e6d4f55a1f5b0419722132d68ff3cdalton    this->teardown();
24330bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen    this->destroyGLContext();
24430bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen}
24530bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen
246273c0f5e87397c40d22bb7e3ee078bb46a3f6860bsalomonvoid GLXGLTestContext::destroyGLContext() {
24730bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen    if (fDisplay) {
24830bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        glXMakeCurrent(fDisplay, 0, 0);
24930bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen
25030bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        if (fContext) {
25130bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen            glXDestroyContext(fDisplay, fContext);
25296fcdcc219d2a0d3579719b84b28bede76efba64halcanary            fContext = nullptr;
25330bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        }
25430bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen
25530bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        if (fGlxPixmap) {
25630bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen            glXDestroyGLXPixmap(fDisplay, fGlxPixmap);
25730bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen            fGlxPixmap = 0;
25830bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        }
25930bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen
26030bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        if (fPixmap) {
26130bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen            XFreePixmap(fDisplay, fPixmap);
26230bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen            fPixmap = 0;
26330bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        }
26430bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen
26596fcdcc219d2a0d3579719b84b28bede76efba64halcanary        fDisplay = nullptr;
266373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com    }
267373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com}
268373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com
269fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova/* Create a context with the highest possible version.
270fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova *
271fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova * Disable Xlib errors for the duration of this function (by default they abort
272fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova * the program) and try to get a context starting from the highest version
273fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova * number - there is no way to just directly ask what the highest supported
274fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova * version is.
275fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova *
276fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova * Returns the correct context or NULL on failure.
277fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova */
278fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarovaGLXContext GLXGLTestContext::CreateBestContext(bool isES, Display* display, GLXFBConfig bestFbc,
279fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova                                               GLXContext glxShareContext) {
280fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova    auto glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)
281fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova        glXGetProcAddressARB((GrGLubyte*)"glXCreateContextAttribsARB");
282fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova    if (!glXCreateContextAttribsARB) {
283fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova        SkDebugf("Failed to get address of glXCreateContextAttribsARB");
284fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova        return nullptr;
285fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova    }
286fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova    GLXContext context = nullptr;
287fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova    // Install Xlib error handler that will set ctxErrorOccurred.
288fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova    // WARNING: It is global for all threads.
289fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova    ctxErrorOccurred = false;
290fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova    int (*oldHandler)(Display*, XErrorEvent*) = XSetErrorHandler(&ctxErrorHandler);
291fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova
292fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova    auto versions = isES ? gles_versions : gl_versions;
293fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova    // Well, unfortunately GLX will not just give us the highest context so
294fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova    // instead we have to do this nastiness
295fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova    for (int i = versions.size() - 1; i >= 0 ; i--) {
296fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova        // WARNING: Don't try to optimize this and make this array static. The
297fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova        // glXCreateContextAttribsARB call writes to it upon failure and the
298fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova        // next call would fail too.
299fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova        std::vector<int> flags = {
300fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova            GLX_CONTEXT_MAJOR_VERSION_ARB, versions[i].first,
301fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova            GLX_CONTEXT_MINOR_VERSION_ARB, versions[i].second,
302fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova        };
303fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova        if (isES) {
304fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova            flags.push_back(GLX_CONTEXT_PROFILE_MASK_ARB);
305fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova            // the ES2 flag should work even for higher versions
306fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova            flags.push_back(GLX_CONTEXT_ES2_PROFILE_BIT_EXT);
307fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova        } else if (versions[i].first > 2) {
308fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova            flags.push_back(GLX_CONTEXT_PROFILE_MASK_ARB);
309fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova            // TODO When Nvidia implements NVPR on Core profiles, we should start
310fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova            // requesting core here - currently Nv Path rendering on Nvidia
311fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova            // requires a compatibility profile.
312fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova            flags.push_back(GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB);
313fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova        }
314fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova        flags.push_back(0);
315fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova        context = glXCreateContextAttribsARB(display, bestFbc, glxShareContext, true,
316fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova                                             &flags[0]);
317fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova        // Sync to ensure any errors generated are processed.
318fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova        XSync(display, False);
319fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova
320fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova        if (!ctxErrorOccurred && context) {
321fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova            break;
322fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova        }
323fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova        // try again
324fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova        ctxErrorOccurred = false;
325fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova    }
326fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova    // Restore the original error handler.
327fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova    XSetErrorHandler(oldHandler);
328fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova    return context;
329fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova}
330fc3ea41cebb8272c3f683f9cf585ff780b18f09bmartina.kollarova
331273c0f5e87397c40d22bb7e3ee078bb46a3f6860bsalomonvoid GLXGLTestContext::onPlatformMakeCurrent() const {
332373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com    if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) {
333373a6635b7190b4af4d265fdd4b70f102ec3a6fdbsalomon@google.com        SkDebugf("Could not set the context.\n");
33416bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com    }
33516bab87a78cfaf6a4f334e1af910c46883f460afbungeman@google.com}
336c9542ca3d00878a18a57af80037060d6374d5650djsollen@google.com
337273c0f5e87397c40d22bb7e3ee078bb46a3f6860bsalomonvoid GLXGLTestContext::onPlatformSwapBuffers() const {
338c9542ca3d00878a18a57af80037060d6374d5650djsollen@google.com    glXSwapBuffers(fDisplay, fGlxPixmap);
339c9542ca3d00878a18a57af80037060d6374d5650djsollen@google.com}
3409e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen
341273c0f5e87397c40d22bb7e3ee078bb46a3f6860bsalomonGrGLFuncPtr GLXGLTestContext::onPlatformGetProcAddress(const char* procName) const {
342d416a5b10ff9e6d4f55a1f5b0419722132d68ff3cdalton    return glXGetProcAddress(reinterpret_cast<const GLubyte*>(procName));
343d416a5b10ff9e6d4f55a1f5b0419722132d68ff3cdalton}
344d416a5b10ff9e6d4f55a1f5b0419722132d68ff3cdalton
3453724e574a744491b7cfb8187ac865a70ef3d4528bsalomon}  // anonymous namespace
3469e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen
3473724e574a744491b7cfb8187ac865a70ef3d4528bsalomonnamespace sk_gpu_test {
348273c0f5e87397c40d22bb7e3ee078bb46a3f6860bsalomonGLTestContext *CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,
349273c0f5e87397c40d22bb7e3ee078bb46a3f6860bsalomon                                           GLTestContext *shareContext) {
350273c0f5e87397c40d22bb7e3ee078bb46a3f6860bsalomon    GLXGLTestContext *glxShareContext = reinterpret_cast<GLXGLTestContext *>(shareContext);
351273c0f5e87397c40d22bb7e3ee078bb46a3f6860bsalomon    GLXGLTestContext *ctx = new GLXGLTestContext(forcedGpuAPI, glxShareContext);
35230bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen    if (!ctx->isValid()) {
353385fe4d4b62d7d1dd76116dd570df3290a2f487bhalcanary        delete ctx;
35496fcdcc219d2a0d3579719b84b28bede76efba64halcanary        return nullptr;
35530bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen    }
35630bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen    return ctx;
3579e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen}
3583724e574a744491b7cfb8187ac865a70ef3d4528bsalomon}  // namespace sk_gpu_test
359