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 30 GLInterface* GLInterface::Create() { 31 return new GLXInterface; 32 } 33 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 63 void GLXInterface::Cleanup() { 64 glXMakeCurrent(g_xlib_display, 0, NULL); 65 DeleteContext(context_); 66 } 67 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 92 bool GLXInterface::MakeCurrent(const GLContext& context) { 93 return glXMakeCurrent(g_xlib_display, g_xlib_window, context); 94 } 95 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 103 void GLXInterface::DeleteContext(const GLContext& context) { 104 glXDestroyContext(g_xlib_display, context); 105 } 106 107 void GLXInterface::SwapBuffers() { 108 glXSwapBuffers(g_xlib_display, g_xlib_window); 109 } 110 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 121 void GLXInterface::CheckError() { 122 CHECK_EQ(glGetError(), static_cast<GLenum>(GL_NO_ERROR)); 123 }; 124