普通文本  |  124行  |  3.18 KB

// 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));
};