// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <GL/gl.h>
#include <string.h>
#include <memory>
#include "base/logging.h"
#include "glx_stuff.h"
#include "main.h"
#include "xlib_window.h"
namespace gl {
#define F(fun, type) type fun = NULL;
LIST_PROC_FUNCTIONS(F)
#undef F
};
#ifndef GLX_MESA_swap_control
typedef GLint (* PFNGLXSWAPINTERVALMESAPROC) (unsigned interval);
typedef GLint (* PFNGLXGETSWAPINTERVALMESAPROC) (void);
#endif
PFNGLXSWAPINTERVALMESAPROC _glXSwapIntervalMESA = NULL;
std::unique_ptr<GLInterface> g_main_gl_interface;
GLInterface* GLInterface::Create() {
return new GLXInterface;
}
bool GLXInterface::Init() {
if (!XlibInit())
return false;
context_ = CreateContext();
if (!context_)
return false;
if (!glXMakeCurrent(g_xlib_display, g_xlib_window, context_)) {
glXDestroyContext(g_xlib_display, context_);
return false;
}
const GLubyte *str = glGetString(GL_EXTENSIONS);
if (!str || !strstr(reinterpret_cast<const char *>(str),
"GL_ARB_vertex_buffer_object"))
return false;
#define F(fun, type) fun = reinterpret_cast<type>( \
glXGetProcAddress(reinterpret_cast<const GLubyte *>(#fun)));
LIST_PROC_FUNCTIONS(F)
#undef F
_glXSwapIntervalMESA = reinterpret_cast<PFNGLXSWAPINTERVALMESAPROC>(
glXGetProcAddress(reinterpret_cast<const GLubyte *>(
"glXSwapIntervalMESA")));
return true;
}
void GLXInterface::Cleanup() {
glXMakeCurrent(g_xlib_display, 0, NULL);
DeleteContext(context_);
}
XVisualInfo* GLXInterface::GetXVisual() {
if (!fb_config_) {
int screen = DefaultScreen(g_xlib_display);
int attrib[] = {
GLX_DOUBLEBUFFER, True,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_DEPTH_SIZE, 1,
GLX_STENCIL_SIZE, 1,
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
None
};
int nelements;
GLXFBConfig *fb_configs = glXChooseFBConfig(g_xlib_display, screen,
attrib, &nelements);
CHECK(nelements >= 1);
fb_config_ = fb_configs[0];
XFree(fb_configs);
}
return glXGetVisualFromFBConfig(g_xlib_display, fb_config_);
}
bool GLXInterface::MakeCurrent(const GLContext& context) {
return glXMakeCurrent(g_xlib_display, g_xlib_window, context);
}
const GLContext GLXInterface::CreateContext() {
CHECK(g_xlib_display);
CHECK(fb_config_);
return glXCreateNewContext(g_xlib_display, fb_config_, GLX_RGBA_TYPE, 0,
True);
}
void GLXInterface::DeleteContext(const GLContext& context) {
glXDestroyContext(g_xlib_display, context);
}
void GLXInterface::SwapBuffers() {
glXSwapBuffers(g_xlib_display, g_xlib_window);
}
bool GLXInterface::SwapInterval(int interval) {
// Strictly, glXSwapIntervalSGI only allows interval > 0, whereas
// glXSwapIntervalMESA allow 0 with the same semantics as eglSwapInterval.
if (_glXSwapIntervalMESA) {
return _glXSwapIntervalMESA(interval) == 0;
} else {
return glXSwapIntervalSGI(interval) == 0;
}
}
void GLXInterface::CheckError() {
CHECK_EQ(glGetError(), static_cast<GLenum>(GL_NO_ERROR));
};