summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordominich@chromium.org <dominich@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-27 18:26:57 +0000
committerdominich@chromium.org <dominich@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-27 18:26:57 +0000
commitcd1f2455551054586a441fff03f15a92e31114e9 (patch)
tree03b86c075f636374ebd5f0f2a113006e6d1b17c8
parentdac716a0ab0c600bfef13d2738ce749bdc13b03a (diff)
downloadchromium_src-cd1f2455551054586a441fff03f15a92e31114e9.zip
chromium_src-cd1f2455551054586a441fff03f15a92e31114e9.tar.gz
chromium_src-cd1f2455551054586a441fff03f15a92e31114e9.tar.bz2
Change X11 error handler override to allow easy X11 error checking.
BUG=None TEST=None Review URL: http://codereview.chromium.org/7889040 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@102978 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--gpu/DEPS2
-rw-r--r--gpu/command_buffer/common/gl_mock.h6
-rw-r--r--gpu/command_buffer/service/buffer_manager_unittest.cc8
-rw-r--r--gpu/command_buffer/service/framebuffer_manager_unittest.cc11
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc11
-rw-r--r--gpu/command_buffer/service/id_manager_unittest.cc10
-rw-r--r--gpu/command_buffer/service/program_manager_unittest.cc7
-rw-r--r--gpu/command_buffer/service/renderbuffer_manager_unittest.cc9
-rw-r--r--gpu/command_buffer/service/shader_manager_unittest.cc8
-rw-r--r--gpu/command_buffer/service/texture_manager_unittest.cc8
-rw-r--r--gpu/command_buffer/service/vertex_attrib_manager_unittest.cc8
-rw-r--r--ui/base/x/x11_util.cc115
-rw-r--r--ui/base/x/x11_util_internal.h5
-rw-r--r--ui/gfx/gl/gl_bindings.h6
-rw-r--r--ui/gfx/gl/gl_context_glx.cc6
15 files changed, 146 insertions, 74 deletions
diff --git a/gpu/DEPS b/gpu/DEPS
index b357d81..5c266a4 100644
--- a/gpu/DEPS
+++ b/gpu/DEPS
@@ -8,6 +8,8 @@ include_rules = [
"+../GLES2",
"+../service",
+ # For ui::CheckFailOnReportedX11Error
+ "+ui/base",
# For gfx::PluginWindowHandle
"+ui/gfx",
]
diff --git a/gpu/command_buffer/common/gl_mock.h b/gpu/command_buffer/common/gl_mock.h
index 4c5c114..29fb000 100644
--- a/gpu/command_buffer/common/gl_mock.h
+++ b/gpu/command_buffer/common/gl_mock.h
@@ -9,6 +9,11 @@
#define GPU_COMMAND_BUFFER_COMMON_GL_MOCK_H_
#pragma once
+// Include gtest.h out of order because <X11/X.h> #define's Bool & None, which
+// gtest uses as struct names (inside a namespace). This means that
+// #include'ing gtest after anything that pulls in X.h fails to compile.
+// This is http://code.google.com/p/googletest/issues/detail?id=371
+#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "ui/gfx/gl/gl_interface.h"
@@ -450,4 +455,3 @@ class MockGLInterface : public GLInterface {
} // namespace gfx
#endif // GPU_COMMAND_BUFFER_COMMON_GL_MOCK_H_
-
diff --git a/gpu/command_buffer/service/buffer_manager_unittest.cc b/gpu/command_buffer/service/buffer_manager_unittest.cc
index 1e4258b..8cd095dc 100644
--- a/gpu/command_buffer/service/buffer_manager_unittest.cc
+++ b/gpu/command_buffer/service/buffer_manager_unittest.cc
@@ -2,9 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// Include gtest.h out of order because <X11/X.h> #define's Bool & None, which
+// gtest uses as struct names (inside a namespace). This means that
+// #include'ing gtest after anything that pulls in X.h fails to compile.
+// This is http://code.google.com/p/googletest/issues/detail?id=371
+#include "testing/gtest/include/gtest/gtest.h"
#include "gpu/command_buffer/service/buffer_manager.h"
#include "gpu/command_buffer/common/gl_mock.h"
-#include "testing/gtest/include/gtest/gtest.h"
namespace gpu {
namespace gles2 {
@@ -223,5 +227,3 @@ TEST_F(BufferManagerTest, GetMaxValueForRangeUint32) {
} // namespace gles2
} // namespace gpu
-
-
diff --git a/gpu/command_buffer/service/framebuffer_manager_unittest.cc b/gpu/command_buffer/service/framebuffer_manager_unittest.cc
index 77c6622..7bd4872 100644
--- a/gpu/command_buffer/service/framebuffer_manager_unittest.cc
+++ b/gpu/command_buffer/service/framebuffer_manager_unittest.cc
@@ -2,12 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// Include gtest.h out of order because <X11/X.h> #define's Bool & None, which
+// gtest uses as struct names (inside a namespace). This means that
+// #include'ing gtest after anything that pulls in X.h fails to compile.
+// This is http://code.google.com/p/googletest/issues/detail?id=371
+#include "testing/gtest/include/gtest/gtest.h"
+#include "gpu/command_buffer/common/gl_mock.h"
#include "gpu/command_buffer/service/framebuffer_manager.h"
#include "gpu/command_buffer/service/feature_info.h"
-#include "gpu/command_buffer/common/gl_mock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
namespace gpu {
namespace gles2 {
@@ -364,5 +367,3 @@ TEST_F(FramebufferInfoTest, AttachTexture) {
} // namespace gles2
} // namespace gpu
-
-
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index d6c513e..82b16de 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -15,6 +15,7 @@
#include "base/atomicops.h"
#include "base/at_exit.h"
#include "base/callback.h"
+#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "build/build_config.h"
@@ -40,6 +41,13 @@
#include "ui/gfx/gl/gl_implementation.h"
#include "ui/gfx/gl/gl_surface.h"
+#if defined(USE_X11)
+#include "ui/base/x/x11_util_internal.h"
+#define CHECK_X_ERROR() ui::CheckForReportedX11Error()
+#else // USE_X11
+#define CHECK_X_ERROR() void(0)
+#endif // USE_X11
+
#if !defined(GL_DEPTH24_STENCIL8)
#define GL_DEPTH24_STENCIL8 0x88F0
#endif
@@ -1732,6 +1740,8 @@ bool GLES2DecoderImpl::Initialize(
// Take ownership of the GLContext.
context_ = context;
+ CHECK_X_ERROR();
+
if (!MakeCurrent()) {
LOG(ERROR) << "GLES2DecoderImpl::Initialize failed because "
<< "MakeCurrent failed.";
@@ -1746,6 +1756,7 @@ bool GLES2DecoderImpl::Initialize(
return false;
}
+ CHECK_X_ERROR();
CHECK_GL_ERROR();
disallowed_features_ = disallowed_features;
diff --git a/gpu/command_buffer/service/id_manager_unittest.cc b/gpu/command_buffer/service/id_manager_unittest.cc
index 015a442..7f7e676 100644
--- a/gpu/command_buffer/service/id_manager_unittest.cc
+++ b/gpu/command_buffer/service/id_manager_unittest.cc
@@ -1,9 +1,13 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium 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 "gpu/command_buffer/service/id_manager.h"
+// Include gtest.h out of order because <X11/X.h> #define's Bool & None, which
+// gtest uses as struct names (inside a namespace). This means that
+// #include'ing gtest after anything that pulls in X.h fails to compile.
+// This is http://code.google.com/p/googletest/issues/detail?id=371
#include "testing/gtest/include/gtest/gtest.h"
+#include "gpu/command_buffer/service/id_manager.h"
namespace gpu {
namespace gles2 {
@@ -72,5 +76,3 @@ TEST_F(IdManagerTest, Basic) {
} // namespace gles2
} // namespace gpu
-
-
diff --git a/gpu/command_buffer/service/program_manager_unittest.cc b/gpu/command_buffer/service/program_manager_unittest.cc
index c58cda1..b5f7cc3 100644
--- a/gpu/command_buffer/service/program_manager_unittest.cc
+++ b/gpu/command_buffer/service/program_manager_unittest.cc
@@ -2,6 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// Include gtest.h out of order because <X11/X.h> #define's Bool & None, which
+// gtest uses as struct names (inside a namespace). This means that
+// #include'ing gtest after anything that pulls in X.h fails to compile.
+// This is http://code.google.com/p/googletest/issues/detail?id=371
+#include "testing/gtest/include/gtest/gtest.h"
#include "gpu/command_buffer/service/program_manager.h"
#include <algorithm>
@@ -900,5 +905,3 @@ TEST_F(ProgramManagerWithShaderTest, ProgramInfoGetProgramInfo) {
} // namespace gles2
} // namespace gpu
-
-
diff --git a/gpu/command_buffer/service/renderbuffer_manager_unittest.cc b/gpu/command_buffer/service/renderbuffer_manager_unittest.cc
index c68b599..c12e451 100644
--- a/gpu/command_buffer/service/renderbuffer_manager_unittest.cc
+++ b/gpu/command_buffer/service/renderbuffer_manager_unittest.cc
@@ -1,7 +1,12 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium 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 gtest.h out of order because <X11/X.h> #define's Bool & None, which
+// gtest uses as struct names (inside a namespace). This means that
+// #include'ing gtest after anything that pulls in X.h fails to compile.
+// This is http://code.google.com/p/googletest/issues/detail?id=371
+#include "testing/gtest/include/gtest/gtest.h"
#include "gpu/command_buffer/service/renderbuffer_manager.h"
#include "gpu/command_buffer/common/gl_mock.h"
@@ -117,5 +122,3 @@ TEST_F(RenderbufferManagerTest, RenderbufferInfo) {
} // namespace gles2
} // namespace gpu
-
-
diff --git a/gpu/command_buffer/service/shader_manager_unittest.cc b/gpu/command_buffer/service/shader_manager_unittest.cc
index 23590b78..2aed8d9 100644
--- a/gpu/command_buffer/service/shader_manager_unittest.cc
+++ b/gpu/command_buffer/service/shader_manager_unittest.cc
@@ -2,12 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// Include gtest.h out of order because <X11/X.h> #define's Bool & None, which
+// gtest uses as struct names (inside a namespace). This means that
+// #include'ing gtest after anything that pulls in X.h fails to compile.
+// This is http://code.google.com/p/googletest/issues/detail?id=371
+#include "testing/gtest/include/gtest/gtest.h"
#include "gpu/command_buffer/service/shader_manager.h"
#include "base/memory/scoped_ptr.h"
#include "gpu/command_buffer/common/gl_mock.h"
#include "gpu/command_buffer/service/mocks.h"
-#include "testing/gtest/include/gtest/gtest.h"
using ::testing::Return;
using ::testing::ReturnRef;
@@ -242,5 +246,3 @@ TEST_F(ShaderManagerTest, ShaderInfoUseCount) {
} // namespace gles2
} // namespace gpu
-
-
diff --git a/gpu/command_buffer/service/texture_manager_unittest.cc b/gpu/command_buffer/service/texture_manager_unittest.cc
index cf33e72..fe0392b 100644
--- a/gpu/command_buffer/service/texture_manager_unittest.cc
+++ b/gpu/command_buffer/service/texture_manager_unittest.cc
@@ -2,13 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// Include gtest.h out of order because <X11/X.h> #define's Bool & None, which
+// gtest uses as struct names (inside a namespace). This means that
+// #include'ing gtest after anything that pulls in X.h fails to compile.
+// This is http://code.google.com/p/googletest/issues/detail?id=371
+#include "testing/gtest/include/gtest/gtest.h"
#include "gpu/command_buffer/service/texture_manager.h"
#include "base/memory/scoped_ptr.h"
#include "gpu/command_buffer/common/gl_mock.h"
#include "gpu/command_buffer/service/feature_info.h"
#include "gpu/command_buffer/service/test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
using ::testing::Pointee;
using ::testing::_;
@@ -727,5 +731,3 @@ TEST_F(TextureInfoTest, EGLImageExternal) {
} // namespace gles2
} // namespace gpu
-
-
diff --git a/gpu/command_buffer/service/vertex_attrib_manager_unittest.cc b/gpu/command_buffer/service/vertex_attrib_manager_unittest.cc
index 49c1883..fb5e26c 100644
--- a/gpu/command_buffer/service/vertex_attrib_manager_unittest.cc
+++ b/gpu/command_buffer/service/vertex_attrib_manager_unittest.cc
@@ -2,13 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// Include gtest.h out of order because <X11/X.h> #define's Bool & None, which
+// gtest uses as struct names (inside a namespace). This means that
+// #include'ing gtest after anything that pulls in X.h fails to compile.
+// This is http://code.google.com/p/googletest/issues/detail?id=371
+#include "testing/gtest/include/gtest/gtest.h"
#include "gpu/command_buffer/service/vertex_attrib_manager.h"
#include "base/memory/scoped_ptr.h"
#include "gpu/command_buffer/common/gl_mock.h"
#include "gpu/command_buffer/service/feature_info.h"
#include "gpu/command_buffer/service/test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
using ::testing::Pointee;
using ::testing::_;
@@ -176,5 +180,3 @@ TEST_F(VertexAttribManagerTest, CanAccess) {
} // namespace gles2
} // namespace gpu
-
-
diff --git a/ui/base/x/x11_util.cc b/ui/base/x/x11_util.cc
index 39c2cff..0dd6e9c 100644
--- a/ui/base/x/x11_util.cc
+++ b/ui/base/x/x11_util.cc
@@ -65,6 +65,8 @@ CachedPictFormats* get_cached_pict_formats() {
const size_t kMaxCacheSize = 5;
int DefaultX11ErrorHandler(Display* d, XErrorEvent* e) {
+ DCHECK(!MessageLoop::current() ||
+ MessageLoop::current()->type() == MessageLoop::TYPE_UI);
MessageLoop::current()->PostTask(
FROM_HERE, NewRunnableFunction(LogErrorEventDescription, d, *e));
return 0;
@@ -76,6 +78,14 @@ int DefaultX11IOErrorHandler(Display* d) {
_exit(1);
}
+XErrorHandler current_error_handler = DefaultX11ErrorHandler;
+XErrorEvent last_error_event = {0, NULL, 0, 0, 0, 0, 0 };
+
+int BaseX11ErrorHandler(Display* d, XErrorEvent* e) {
+ last_error_event = *e;
+ return current_error_handler(d, e);
+}
+
Atom GetAtom(const char* name) {
#if defined(TOOLKIT_USES_GTK)
return gdk_x11_get_xatom_by_name_for_display(
@@ -105,6 +115,49 @@ bool GetProperty(XID window, const std::string& property_name, long max_length,
property);
}
+std::string BuildX11ErrorString(const XErrorEvent& error_event) {
+ char error_str[256];
+ char request_str[256];
+
+ XGetErrorText(error_event.display, error_event.error_code, error_str,
+ sizeof(error_str));
+
+ strncpy(request_str, "Unknown", sizeof(request_str));
+ if (error_event.request_code < 128) {
+ std::string num = base::UintToString(error_event.request_code);
+ XGetErrorDatabaseText(error_event.display, "XRequest", num.c_str(),
+ "Unknown", request_str, sizeof(request_str));
+ } else {
+ int num_ext;
+ char** ext_list = XListExtensions(error_event.display, &num_ext);
+
+ for (int i = 0; i < num_ext; i++) {
+ int ext_code, first_event, first_error;
+ XQueryExtension(error_event.display, ext_list[i], &ext_code, &first_event,
+ &first_error);
+ if (error_event.request_code == ext_code) {
+ std::string msg = StringPrintf(
+ "%s.%d", ext_list[i], error_event.minor_code);
+ XGetErrorDatabaseText(error_event.display, "XRequest", msg.c_str(),
+ "Unknown", request_str, sizeof(request_str));
+ break;
+ }
+ }
+ XFreeExtensionList(ext_list);
+ }
+
+ std::ostringstream error_ss;
+ error_ss << "X Error detected: "
+ << "serial " << error_event.serial << ", "
+ << "error_code " << static_cast<int>(error_event.error_code)
+ << " (" << error_str << "), "
+ << "request_code " << static_cast<int>(error_event.request_code)
+ << ", "
+ << "minor_code " << static_cast<int>(error_event.minor_code)
+ << " (" << request_str << ")";
+ return error_ss.str();
+}
+
} // namespace
bool XDisplayExists() {
@@ -695,6 +748,7 @@ bool ChangeWindowDesktop(XID window, XID destination) {
}
void SetDefaultX11ErrorHandlers() {
+ XSetErrorHandler(BaseX11ErrorHandler);
SetX11ErrorHandlers(NULL, NULL);
}
@@ -730,6 +784,15 @@ bool IsX11WindowFullScreen(XID window) {
#endif
}
+void CheckForReportedX11Error() {
+ DCHECK(!MessageLoop::current() ||
+ MessageLoop::current()->type() == MessageLoop::TYPE_UI);
+ if (!last_error_event.display)
+ return;
+ XSync(last_error_event.display, False);
+ LOG(FATAL) << BuildX11ErrorString(last_error_event);
+}
+
// ----------------------------------------------------------------------------
// These functions are declared in x11_util_internal.h because they require
// XLib.h to be included, and it conflicts with many other headers.
@@ -808,51 +871,21 @@ XRenderPictFormat* GetRenderVisualFormat(Display* dpy, Visual* visual) {
void SetX11ErrorHandlers(XErrorHandler error_handler,
XIOErrorHandler io_error_handler) {
- XSetErrorHandler(error_handler ? error_handler : DefaultX11ErrorHandler);
- XSetIOErrorHandler(
- io_error_handler ? io_error_handler : DefaultX11IOErrorHandler);
+ DCHECK(!MessageLoop::current() ||
+ MessageLoop::current()->type() == MessageLoop::TYPE_UI);
+ current_error_handler = error_handler ?
+ error_handler : DefaultX11ErrorHandler;
+ XSetIOErrorHandler(io_error_handler ?
+ io_error_handler : DefaultX11IOErrorHandler);
}
void LogErrorEventDescription(Display* dpy,
const XErrorEvent& error_event) {
- char error_str[256];
- char request_str[256];
-
- XGetErrorText(dpy, error_event.error_code, error_str, sizeof(error_str));
-
- strncpy(request_str, "Unknown", sizeof(request_str));
- if (error_event.request_code < 128) {
- std::string num = base::UintToString(error_event.request_code);
- XGetErrorDatabaseText(
- dpy, "XRequest", num.c_str(), "Unknown", request_str,
- sizeof(request_str));
- } else {
- int num_ext;
- char** ext_list = XListExtensions(dpy, &num_ext);
-
- for (int i = 0; i < num_ext; i++) {
- int ext_code, first_event, first_error;
- XQueryExtension(dpy, ext_list[i], &ext_code, &first_event, &first_error);
- if (error_event.request_code == ext_code) {
- std::string msg = StringPrintf(
- "%s.%d", ext_list[i], error_event.minor_code);
- XGetErrorDatabaseText(
- dpy, "XRequest", msg.c_str(), "Unknown", request_str,
- sizeof(request_str));
- break;
- }
- }
- XFreeExtensionList(ext_list);
- }
-
- LOG(ERROR)
- << "X Error detected: "
- << "serial " << error_event.serial << ", "
- << "error_code " << static_cast<int>(error_event.error_code)
- << " (" << error_str << "), "
- << "request_code " << static_cast<int>(error_event.request_code) << ", "
- << "minor_code " << static_cast<int>(error_event.minor_code)
- << " (" << request_str << ")";
+ DCHECK(!MessageLoop::current() ||
+ MessageLoop::current()->type() == MessageLoop::TYPE_UI);
+ DCHECK_EQ(dpy, error_event.display)
+ << "Attempt to log error for mismatching X11 display.";
+ LOG(ERROR) << BuildX11ErrorString(error_event);
}
// ----------------------------------------------------------------------------
diff --git a/ui/base/x/x11_util_internal.h b/ui/base/x/x11_util_internal.h
index 70eb088..c84063f 100644
--- a/ui/base/x/x11_util_internal.h
+++ b/ui/base/x/x11_util_internal.h
@@ -50,6 +50,11 @@ UI_EXPORT void SetX11ErrorHandlers(XErrorHandler error_handler,
UI_EXPORT void LogErrorEventDescription(Display* dpy,
const XErrorEvent& error_event);
+// LOG(FATAL) if an X11 errors has been reported. Uses XSync to ensure that all
+// requests have been received and processed by the X server and uses the X
+// display contained in the reported XErrorEvent.
+UI_EXPORT void CheckForReportedX11Error();
+
} // namespace ui
#endif // UI_BASE_X_X11_UTIL_INTERNAL_H_
diff --git a/ui/gfx/gl/gl_bindings.h b/ui/gfx/gl/gl_bindings.h
index 8951225..af14f84 100644
--- a/ui/gfx/gl/gl_bindings.h
+++ b/ui/gfx/gl/gl_bindings.h
@@ -26,12 +26,6 @@
#elif defined(USE_X11)
#include <GL/glx.h>
#include <GL/glxext.h>
-
-// Undefine some macros defined by X headers. This is why this file should only
-// be included in .cc files.
-#undef Bool
-#undef None
-#undef Status
#endif
#if defined(OS_WIN)
diff --git a/ui/gfx/gl/gl_context_glx.cc b/ui/gfx/gl/gl_context_glx.cc
index a23f1a9..e0ea25e 100644
--- a/ui/gfx/gl/gl_context_glx.cc
+++ b/ui/gfx/gl/gl_context_glx.cc
@@ -11,6 +11,7 @@ extern "C" {
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "third_party/mesa/MesaLib/include/GL/osmesa.h"
+#include "ui/base/x/x11_util_internal.h"
#include "ui/gfx/gl/gl_bindings.h"
#include "ui/gfx/gl/gl_implementation.h"
#include "ui/gfx/gl/gl_surface_glx.h"
@@ -88,6 +89,8 @@ bool GLContextGLX::Initialize(GLSurface* compatible_surface) {
}
}
+ ui::CheckForReportedX11Error();
+
if (!context_) {
// The means by which the context is created depends on whether
// the drawable type works reliably with GLX 1.3. If it does not
@@ -113,6 +116,8 @@ bool GLContextGLX::Initialize(GLSurface* compatible_surface) {
return false;
}
+ ui::CheckForReportedX11Error();
+
XVisualInfo visual_info_template;
visual_info_template.visualid = XVisualIDFromVisual(attributes.visual);
@@ -136,6 +141,7 @@ bool GLContextGLX::Initialize(GLSurface* compatible_surface) {
True);
}
}
+ ui::CheckForReportedX11Error();
if (!context_) {
LOG(ERROR) << "Couldn't create GL context.";