summaryrefslogtreecommitdiffstats
path: root/o3d/command_buffer/service/gapi_gl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'o3d/command_buffer/service/gapi_gl.cc')
-rw-r--r--o3d/command_buffer/service/gapi_gl.cc417
1 files changed, 417 insertions, 0 deletions
diff --git a/o3d/command_buffer/service/gapi_gl.cc b/o3d/command_buffer/service/gapi_gl.cc
new file mode 100644
index 0000000..5bc587d
--- /dev/null
+++ b/o3d/command_buffer/service/gapi_gl.cc
@@ -0,0 +1,417 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file implements the GAPIGL class.
+
+#include <build/build_config.h>
+#include "command_buffer/service/gapi_gl.h"
+
+#ifdef OS_LINUX
+#include "command_buffer/service/linux/x_utils.h"
+#endif // OS_LINUX
+
+namespace command_buffer {
+namespace o3d {
+
+GAPIGL::GAPIGL()
+ : cg_context_(NULL),
+#ifdef OS_LINUX
+ window_(NULL),
+#endif
+#ifdef OS_WIN
+ hwnd_(NULL),
+ device_context_(NULL),
+ gl_context_(NULL),
+#endif
+ anti_aliased_(false),
+ current_vertex_struct_(kInvalidResource),
+ validate_streams_(true),
+ max_vertices_(0),
+ current_effect_id_(kInvalidResource),
+ validate_effect_(true),
+ current_effect_(NULL) {
+}
+
+GAPIGL::~GAPIGL() {
+}
+
+bool GAPIGL::Initialize() {
+ if (!InitPlatformSpecific())
+ return false;
+ if (!InitCommon())
+ return false;
+ CHECK_GL_ERROR();
+ return true;
+}
+
+#if defined(OS_WIN)
+static const PIXELFORMATDESCRIPTOR kPixelFormatDescriptor = {
+ sizeof(kPixelFormatDescriptor), // Size of structure.
+ 1, // Default version.
+ PFD_DRAW_TO_WINDOW | // Window drawing support.
+ PFD_SUPPORT_OPENGL | // OpenGL support.
+ PFD_DOUBLEBUFFER, // Double buffering support (not stereo).
+ PFD_TYPE_RGBA, // RGBA color mode (not indexed).
+ 24, // 24 bit color mode.
+ 0, 0, 0, 0, 0, 0, // Don't set RGB bits & shifts.
+ 8, 0, // 8 bit alpha
+ 0, // No accumulation buffer.
+ 0, 0, 0, 0, // Ignore accumulation bits.
+ 24, // 24 bit z-buffer size.
+ 8, // 8-bit stencil buffer.
+ 0, // No aux buffer.
+ PFD_MAIN_PLANE, // Main drawing plane (not overlay).
+ 0, // Reserved.
+ 0, 0, 0, // Layer masks ignored.
+};
+
+LRESULT CALLBACK IntermediateWindowProc(HWND window,
+ UINT message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ return ::DefWindowProc(window, message, w_param, l_param);
+}
+
+// Helper routine that returns the highest quality pixel format supported on
+// the current platform. Returns true upon success.
+static bool GetWindowsPixelFormat(HWND window,
+ bool anti_aliased,
+ int* pixel_format) {
+ // We must initialize a GL context before we can determine the multi-sampling
+ // supported on the current hardware, so we create an intermediate window
+ // and context here.
+ HINSTANCE module_handle;
+ if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT |
+ GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+ reinterpret_cast<wchar_t*>(IntermediateWindowProc),
+ &module_handle)) {
+ return false;
+ }
+
+ WNDCLASS intermediate_class;
+ intermediate_class.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
+ intermediate_class.lpfnWndProc = IntermediateWindowProc;
+ intermediate_class.cbClsExtra = 0;
+ intermediate_class.cbWndExtra = 0;
+ intermediate_class.hInstance = module_handle;
+ intermediate_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ intermediate_class.hCursor = LoadCursor(NULL, IDC_ARROW);
+ intermediate_class.hbrBackground = NULL;
+ intermediate_class.lpszMenuName = NULL;
+ intermediate_class.lpszClassName = L"Intermediate GL Window";
+
+ ATOM class_registration = ::RegisterClass(&intermediate_class);
+ if (!class_registration) {
+ return false;
+ }
+
+ HWND intermediate_window = ::CreateWindow(
+ reinterpret_cast<wchar_t*>(class_registration),
+ L"",
+ WS_OVERLAPPEDWINDOW,
+ 0, 0,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+
+ if (!intermediate_window) {
+ ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration),
+ module_handle);
+ return false;
+ }
+
+ HDC intermediate_dc = ::GetDC(intermediate_window);
+ int format_index = ::ChoosePixelFormat(intermediate_dc,
+ &kPixelFormatDescriptor);
+ if (format_index == 0) {
+ DLOG(ERROR) << "Unable to get the pixel format for GL context.";
+ ::ReleaseDC(intermediate_window, intermediate_dc);
+ ::DestroyWindow(intermediate_window);
+ ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration),
+ module_handle);
+ return false;
+ }
+ if (!::SetPixelFormat(intermediate_dc, format_index,
+ &kPixelFormatDescriptor)) {
+ DLOG(ERROR) << "Unable to set the pixel format for GL context.";
+ ::ReleaseDC(intermediate_window, intermediate_dc);
+ ::DestroyWindow(intermediate_window);
+ ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration),
+ module_handle);
+ return false;
+ }
+
+ // Store the pixel format without multisampling.
+ *pixel_format = format_index;
+ HGLRC gl_context = ::wglCreateContext(intermediate_dc);
+ if (::wglMakeCurrent(intermediate_dc, gl_context)) {
+ // GL context was successfully created and applied to the window's DC.
+ // Startup GLEW, the GL extensions wrangler.
+ GLenum glew_error = ::glewInit();
+ if (glew_error == GLEW_OK) {
+ DLOG(INFO) << "Initialized GLEW " << ::glewGetString(GLEW_VERSION);
+ } else {
+ DLOG(ERROR) << "Unable to initialise GLEW : "
+ << ::glewGetErrorString(glew_error);
+ ::wglMakeCurrent(intermediate_dc, NULL);
+ ::wglDeleteContext(gl_context);
+ ::ReleaseDC(intermediate_window, intermediate_dc);
+ ::DestroyWindow(intermediate_window);
+ ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration),
+ module_handle);
+ return false;
+ }
+
+ // If the multi-sample extensions are present, query the api to determine
+ // the pixel format.
+ if (anti_aliased && WGLEW_ARB_pixel_format && WGLEW_ARB_multisample) {
+ int pixel_attributes[] = {
+ WGL_SAMPLES_ARB, 4,
+ WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
+ WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
+ WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
+ WGL_COLOR_BITS_ARB, 24,
+ WGL_ALPHA_BITS_ARB, 8,
+ WGL_DEPTH_BITS_ARB, 24,
+ WGL_STENCIL_BITS_ARB, 8,
+ WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
+ WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
+ 0, 0};
+
+ float pixel_attributes_f[] = {0, 0};
+ int msaa_pixel_format;
+ unsigned int num_formats;
+
+ // Query for the highest sampling rate supported, starting at 4x.
+ static const int kSampleCount[] = {4, 2};
+ static const int kNumSamples = 2;
+ for (int sample = 0; sample < kNumSamples; ++sample) {
+ pixel_attributes[1] = kSampleCount[sample];
+ if (GL_TRUE == ::wglChoosePixelFormatARB(intermediate_dc,
+ pixel_attributes,
+ pixel_attributes_f,
+ 1,
+ &msaa_pixel_format,
+ &num_formats)) {
+ *pixel_format = msaa_pixel_format;
+ break;
+ }
+ }
+ }
+ }
+
+ ::wglMakeCurrent(intermediate_dc, NULL);
+ ::wglDeleteContext(gl_context);
+ ::ReleaseDC(intermediate_window, intermediate_dc);
+ ::DestroyWindow(intermediate_window);
+ ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration),
+ module_handle);
+ return true;
+}
+#endif
+
+bool GAPIGL::InitPlatformSpecific() {
+#if defined(OS_WIN)
+ device_context_ = ::GetDC(hwnd_);
+
+ int pixel_format;
+
+ if (!GetWindowsPixelFormat(hwnd_,
+ anti_aliased(),
+ &pixel_format)) {
+ DLOG(ERROR) << "Unable to determine optimal pixel format for GL context.";
+ return false;
+ }
+
+ if (!::SetPixelFormat(device_context_, pixel_format,
+ &kPixelFormatDescriptor)) {
+ DLOG(ERROR) << "Unable to set the pixel format for GL context.";
+ return false;
+ }
+
+ gl_context_ = ::wglCreateContext(device_context_);
+ if (!gl_context_) {
+ DLOG(ERROR) << "Failed to create GL context.";
+ return false;
+ }
+
+ if (!::wglMakeCurrent(device_context_, gl_context_)) {
+ DLOG(ERROR) << "Unable to make gl context current.";
+ return false;
+ }
+#elif defined(OS_LINUX)
+ DCHECK(window_);
+ if (!window_->Initialize())
+ return false;
+ if (!window_->MakeCurrent())
+ return false;
+#endif
+
+ return true;
+}
+
+bool GAPIGL::InitCommon() {
+ if (!InitGlew())
+ return false;
+ InitCG();
+
+ // Initialize global GL settings.
+ // Tell GL that texture buffers can be single-byte aligned.
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
+ glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
+ // Get the initial viewport (set to the window size) to set up the helper
+ // constant.
+ GLint viewport[4];
+ glGetIntegerv(GL_VIEWPORT, viewport);
+ SetViewport(viewport[0], viewport[1], viewport[2], viewport[3], 0.f, 1.f);
+ CHECK_GL_ERROR();
+
+ ::glGenFramebuffersEXT(1, &render_surface_framebuffer_);
+ CHECK_GL_ERROR();
+ return true;
+}
+
+void GAPIGL::InitCG() {
+ cg_context_ = cgCreateContext();
+ // Set up all Cg State Assignments for OpenGL.
+ cgGLRegisterStates(cg_context_);
+ cgGLSetDebugMode(CG_FALSE);
+ // Enable the profiles we use.
+ cgGLEnableProfile(CG_PROFILE_ARBVP1);
+ cgGLEnableProfile(CG_PROFILE_ARBFP1);
+}
+
+bool GAPIGL::InitGlew() {
+ DLOG(INFO) << "Initializing GL and GLEW for GAPI.";
+
+ GLenum glew_error = glewInit();
+ if (glew_error != GLEW_OK) {
+ DLOG(ERROR) << "Unable to initialise GLEW : "
+ << ::glewGetErrorString(glew_error);
+ return false;
+ }
+
+ // Check to see that we can use the OpenGL vertex attribute APIs
+ // TODO(petersont): Return false if this check fails, but because some
+ // Intel hardware does not support OpenGL 2.0, yet does support all of the
+ // extensions we require, we only log an error. A future CL should change
+ // this check to ensure that all of the extension strings we require are
+ // present.
+ if (!GLEW_VERSION_2_0) {
+ DLOG(ERROR) << "GL drivers do not have OpenGL 2.0 functionality.";
+ }
+
+ bool extensions_found = true;
+ if (!GLEW_ARB_vertex_buffer_object) {
+ // NOTE: Linux NVidia drivers claim to support OpenGL 2.0 when using
+ // indirect rendering (e.g. remote X), but it is actually lying. The
+ // ARB_vertex_buffer_object functions silently no-op (!) when using
+ // indirect rendering, leading to crashes. Fortunately, in that case, the
+ // driver claims to not support ARB_vertex_buffer_object, so fail in that
+ // case.
+ DLOG(ERROR) << "GL drivers do not support vertex buffer objects.";
+ extensions_found = false;
+ }
+ if (!GLEW_EXT_framebuffer_object) {
+ DLOG(ERROR) << "GL drivers do not support framebuffer objects.";
+ extensions_found = false;
+ }
+ // Check for necessary extensions
+ if (!GLEW_VERSION_2_0 && !GLEW_EXT_stencil_two_side) {
+ DLOG(ERROR) << "Two sided stencil extension missing.";
+ extensions_found = false;
+ }
+ if (!GLEW_VERSION_1_4 && !GLEW_EXT_blend_func_separate) {
+ DLOG(ERROR) <<"Separate blend func extension missing.";
+ extensions_found = false;
+ }
+ if (!GLEW_VERSION_2_0 && !GLEW_EXT_blend_equation_separate) {
+ DLOG(ERROR) << "Separate blend function extension missing.";
+ extensions_found = false;
+ }
+ if (!extensions_found)
+ return false;
+
+ return true;
+}
+
+void GAPIGL::Destroy() {
+ vertex_buffers_.DestroyAllResources();
+ index_buffers_.DestroyAllResources();
+ vertex_structs_.DestroyAllResources();
+ effects_.DestroyAllResources();
+ effect_params_.DestroyAllResources();
+ // textures_.DestroyAllResources();
+ // samplers_.DestroyAllResources();
+ cgDestroyContext(cg_context_);
+ cg_context_ = NULL;
+#ifdef OS_LINUX
+ DCHECK(window_);
+ window_->Destroy();
+#endif
+}
+
+void GAPIGL::BeginFrame() {
+}
+
+void GAPIGL::EndFrame() {
+#ifdef OS_WIN
+ ::SwapBuffers(device_context_);
+#endif
+
+#ifdef OS_LINUX
+ DCHECK(window_);
+ window_->SwapBuffers();
+#endif
+
+ CHECK_GL_ERROR();
+}
+
+void GAPIGL::Clear(unsigned int buffers,
+ const RGBA &color,
+ float depth,
+ unsigned int stencil) {
+ glClearColor(color.red, color.green, color.blue, color.alpha);
+ glClearDepth(depth);
+ glClearStencil(stencil);
+ glClear((buffers & kColor ? GL_COLOR_BUFFER_BIT : 0) |
+ (buffers & kDepth ? GL_DEPTH_BUFFER_BIT : 0) |
+ (buffers & kStencil ? GL_STENCIL_BUFFER_BIT : 0));
+ CHECK_GL_ERROR();
+}
+
+} // namespace o3d
+} // namespace command_buffer