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