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 "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 std::unique_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) \
51 fun = reinterpret_cast<type>( \
52 glXGetProcAddress(reinterpret_cast<const GLubyte*>(#fun)));
53 LIST_PROC_FUNCTIONS(F)
54 #undef F
55 _glXSwapIntervalMESA =
56 reinterpret_cast<PFNGLXSWAPINTERVALMESAPROC>(glXGetProcAddress(
57 reinterpret_cast<const GLubyte*>("glXSwapIntervalMESA")));
58
59 return true;
60 }
61
Cleanup()62 void GLXInterface::Cleanup() {
63 glXMakeCurrent(g_xlib_display, 0, NULL);
64 DeleteContext(context_);
65 }
66
GetXVisual()67 XVisualInfo* GLXInterface::GetXVisual() {
68 if (!fb_config_) {
69 int screen = DefaultScreen(g_xlib_display);
70 int attrib[] = {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 int nelements;
79 GLXFBConfig* fb_configs =
80 glXChooseFBConfig(g_xlib_display, screen, attrib, &nelements);
81 CHECK(nelements >= 1);
82 fb_config_ = fb_configs[0];
83 XFree(fb_configs);
84 }
85
86 return glXGetVisualFromFBConfig(g_xlib_display, fb_config_);
87 }
88
MakeCurrent(const GLContext & context)89 bool GLXInterface::MakeCurrent(const GLContext& context) {
90 return glXMakeCurrent(g_xlib_display, g_xlib_window, context);
91 }
92
CreateContext()93 const GLContext GLXInterface::CreateContext() {
94 CHECK(g_xlib_display);
95 CHECK(fb_config_);
96 return glXCreateNewContext(g_xlib_display, fb_config_, GLX_RGBA_TYPE, 0,
97 True);
98 }
99
DeleteContext(const GLContext & context)100 void GLXInterface::DeleteContext(const GLContext& context) {
101 glXDestroyContext(g_xlib_display, context);
102 }
103
SwapBuffers()104 void GLXInterface::SwapBuffers() {
105 glXSwapBuffers(g_xlib_display, g_xlib_window);
106 }
107
SwapInterval(int interval)108 bool GLXInterface::SwapInterval(int interval) {
109 // Strictly, glXSwapIntervalSGI only allows interval > 0, whereas
110 // glXSwapIntervalMESA allow 0 with the same semantics as eglSwapInterval.
111 if (_glXSwapIntervalMESA) {
112 return _glXSwapIntervalMESA(interval) == 0;
113 } else {
114 return glXSwapIntervalSGI(interval) == 0;
115 }
116 }
117
CheckError()118 void GLXInterface::CheckError() {
119 CHECK_EQ(glGetError(), static_cast<GLenum>(GL_NO_ERROR));
120 };
121