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 28 GLInterface* GLInterface::Create() { 29 return new GLXInterface; 30 } 31 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 62 void GLXInterface::Cleanup() { 63 glXMakeCurrent(g_xlib_display, 0, NULL); 64 DeleteContext(context_); 65 } 66 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 89 bool GLXInterface::MakeCurrent(const GLContext& context) { 90 return glXMakeCurrent(g_xlib_display, g_xlib_window, context); 91 } 92 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 100 void GLXInterface::DeleteContext(const GLContext& context) { 101 glXDestroyContext(g_xlib_display, context); 102 } 103 104 void GLXInterface::SwapBuffers() { 105 glXSwapBuffers(g_xlib_display, g_xlib_window); 106 } 107 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 118 void GLXInterface::CheckError() { 119 CHECK_EQ(glGetError(), static_cast<GLenum>(GL_NO_ERROR)); 120 }; 121