1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <GL/gl.h>
6 #include <string.h>
7
8 #include <memory>
9
10 #include "base/logging.h"
11
12 #include "glx_stuff.h"
13 #include "main.h"
14 #include "xlib_window.h"
15
16 namespace gl {
17 #define F(fun, type) type fun = NULL;
18 LIST_PROC_FUNCTIONS(F)
19 #undef F
20 };
21
22 #ifndef GLX_MESA_swap_control
23 typedef GLint (* PFNGLXSWAPINTERVALMESAPROC) (unsigned interval);
24 typedef GLint (* PFNGLXGETSWAPINTERVALMESAPROC) (void);
25 #endif
26 PFNGLXSWAPINTERVALMESAPROC _glXSwapIntervalMESA = NULL;
27
28 std::unique_ptr<GLInterface> g_main_gl_interface;
29
Create()30 GLInterface* GLInterface::Create() {
31 return new GLXInterface;
32 }
33
Init()34 bool GLXInterface::Init() {
35 if (!XlibInit())
36 return false;
37
38 context_ = CreateContext();
39 if (!context_)
40 return false;
41
42 if (!glXMakeCurrent(g_xlib_display, g_xlib_window, context_)) {
43 glXDestroyContext(g_xlib_display, context_);
44 return false;
45 }
46
47 const GLubyte *str = glGetString(GL_EXTENSIONS);
48 if (!str || !strstr(reinterpret_cast<const char *>(str),
49 "GL_ARB_vertex_buffer_object"))
50 return false;
51
52 #define F(fun, type) fun = reinterpret_cast<type>( \
53 glXGetProcAddress(reinterpret_cast<const GLubyte *>(#fun)));
54 LIST_PROC_FUNCTIONS(F)
55 #undef F
56 _glXSwapIntervalMESA = reinterpret_cast<PFNGLXSWAPINTERVALMESAPROC>(
57 glXGetProcAddress(reinterpret_cast<const GLubyte *>(
58 "glXSwapIntervalMESA")));
59
60 return true;
61 }
62
Cleanup()63 void GLXInterface::Cleanup() {
64 glXMakeCurrent(g_xlib_display, 0, NULL);
65 DeleteContext(context_);
66 }
67
GetXVisual()68 XVisualInfo* GLXInterface::GetXVisual() {
69 if (!fb_config_) {
70 int screen = DefaultScreen(g_xlib_display);
71 int attrib[] = {
72 GLX_DOUBLEBUFFER, True,
73 GLX_RED_SIZE, 1,
74 GLX_GREEN_SIZE, 1,
75 GLX_BLUE_SIZE, 1,
76 GLX_DEPTH_SIZE, 1,
77 GLX_STENCIL_SIZE, 1,
78 GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
79 None
80 };
81 int nelements;
82 GLXFBConfig *fb_configs = glXChooseFBConfig(g_xlib_display, screen,
83 attrib, &nelements);
84 CHECK(nelements >= 1);
85 fb_config_ = fb_configs[0];
86 XFree(fb_configs);
87 }
88
89 return glXGetVisualFromFBConfig(g_xlib_display, fb_config_);
90 }
91
MakeCurrent(const GLContext & context)92 bool GLXInterface::MakeCurrent(const GLContext& context) {
93 return glXMakeCurrent(g_xlib_display, g_xlib_window, context);
94 }
95
CreateContext()96 const GLContext GLXInterface::CreateContext() {
97 CHECK(g_xlib_display);
98 CHECK(fb_config_);
99 return glXCreateNewContext(g_xlib_display, fb_config_, GLX_RGBA_TYPE, 0,
100 True);
101 }
102
DeleteContext(const GLContext & context)103 void GLXInterface::DeleteContext(const GLContext& context) {
104 glXDestroyContext(g_xlib_display, context);
105 }
106
SwapBuffers()107 void GLXInterface::SwapBuffers() {
108 glXSwapBuffers(g_xlib_display, g_xlib_window);
109 }
110
SwapInterval(int interval)111 bool GLXInterface::SwapInterval(int interval) {
112 // Strictly, glXSwapIntervalSGI only allows interval > 0, whereas
113 // glXSwapIntervalMESA allow 0 with the same semantics as eglSwapInterval.
114 if (_glXSwapIntervalMESA) {
115 return _glXSwapIntervalMESA(interval) == 0;
116 } else {
117 return glXSwapIntervalSGI(interval) == 0;
118 }
119 }
120
CheckError()121 void GLXInterface::CheckError() {
122 CHECK_EQ(glGetError(), static_cast<GLenum>(GL_NO_ERROR));
123 };
124