summaryrefslogtreecommitdiffstats
path: root/gpu
diff options
context:
space:
mode:
authorapatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-20 22:08:54 +0000
committerapatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-20 22:08:54 +0000
commit4bedba77d40df5fa5f1e00f5918123ee8711ca76 (patch)
tree0d34ff8aac44eaf1281fbcbdbe38867cb2a35f19 /gpu
parent163cf4a0682a5e32f9db5e413dab296f17027015 (diff)
downloadchromium_src-4bedba77d40df5fa5f1e00f5918123ee8711ca76.zip
chromium_src-4bedba77d40df5fa5f1e00f5918123ee8711ca76.tar.gz
chromium_src-4bedba77d40df5fa5f1e00f5918123ee8711ca76.tar.bz2
Added OSMesa based GLContext.
- Renders 3D using Mesa offscreen software renderer. - Will be used to run 3D tests on bots that do not support native OpenGL. - Extended glew library to use the osmesa shared library instead of the regular OpenGL one if it is in the search path. - Only works on Windows with this changelist, though other platforms will continue to use native OpenGL. - Added a stub GLContext implementation for use in unit tests. Review URL: http://codereview.chromium.org/1629029 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@45093 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu')
-rw-r--r--gpu/command_buffer/service/gl_context.h131
-rw-r--r--gpu/command_buffer/service/gl_context_linux.cc175
-rw-r--r--gpu/command_buffer/service/gl_context_mac.cc145
-rw-r--r--gpu/command_buffer/service/gl_context_osmesa.cc106
-rw-r--r--gpu/command_buffer/service/gl_context_osmesa.h58
-rw-r--r--gpu/command_buffer/service/gl_context_stub.cc39
-rw-r--r--gpu/command_buffer/service/gl_context_win.cc553
-rw-r--r--gpu/command_buffer/service/gl_utils.h1
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc66
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc4
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h2
-rw-r--r--gpu/command_buffer/service/gpu_processor_linux.cc25
-rw-r--r--gpu/command_buffer/service/gpu_processor_mac.cc16
-rw-r--r--gpu/command_buffer/service/gpu_processor_win.cc25
-rw-r--r--gpu/gpu.gyp25
15 files changed, 872 insertions, 499 deletions
diff --git a/gpu/command_buffer/service/gl_context.h b/gpu/command_buffer/service/gl_context.h
index 988b7d6..cd41b56 100644
--- a/gpu/command_buffer/service/gl_context.h
+++ b/gpu/command_buffer/service/gl_context.h
@@ -5,33 +5,13 @@
#ifndef GPU_COMMAND_BUFFER_SERVICE_GL_CONTEXT_H_
#define GPU_COMMAND_BUFFER_SERVICE_GL_CONTEXT_H_
-#include <build/build_config.h>
-
-#include "base/basictypes.h"
-#include "base/logging.h"
+#include "build/build_config.h"
#include "gfx/native_widget_types.h"
#include "gfx/size.h"
#include "gpu/command_buffer/common/logging.h"
-#include "gpu/command_buffer/service/gl_utils.h"
namespace gpu {
-#if defined(UNIT_TEST)
-typedef void* HDC;
-struct Display;
-typedef void* GLContextHandle;
-typedef void* PbufferHandle;
-#elif defined(OS_WIN)
-typedef HGLRC GLContextHandle;
-typedef HPBUFFERARB PbufferHandle;
-#elif defined(OS_LINUX)
-typedef GLXContext GLContextHandle;
-typedef GLXPbuffer PbufferHandle;
-#elif defined(OS_MACOSX)
-typedef CGLContextObj GLContextHandle;
-typedef CGLPBufferObj PbufferHandle;
-#endif
-
bool InitializeGLEW();
// Encapsulates an OpenGL context, hiding platform specific management.
@@ -60,110 +40,23 @@ class GLContext {
virtual gfx::Size GetSize() = 0;
// Get the underlying platform specific GL context "handle".
- virtual GLContextHandle GetHandle() = 0;
+ virtual void* GetHandle() = 0;
- protected:
- bool InitializeCommon();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(GLContext);
-};
-
-// This class is a wrapper around a GL context that renders directly to a
-// window.
-class ViewGLContext : public GLContext {
- public:
-#if defined(OS_WIN)
- explicit ViewGLContext(gfx::PluginWindowHandle window)
- : window_(window),
- device_context_(NULL),
- context_(NULL) {
- DCHECK(window);
- }
-#elif defined(OS_LINUX)
- explicit ViewGLContext(gfx::PluginWindowHandle window)
- : window_(window),
- context_(NULL) {
- DCHECK(window);
- }
-#elif defined(OS_MACOSX)
- ViewGLContext() {
- NOTIMPLEMENTED() << "ViewGLContext not supported on Mac platform.";
- }
+#if !defined(OS_MACOSX)
+ // Create a GL context that renders directly to a view.
+ static GLContext* CreateViewGLContext(gfx::PluginWindowHandle window,
+ bool multisampled);
#endif
- // Initializes the GL context.
- bool Initialize(bool multisampled);
-
- virtual void Destroy();
- virtual bool MakeCurrent();
- virtual bool IsCurrent();
- virtual bool IsOffscreen();
- virtual void SwapBuffers();
- virtual gfx::Size GetSize();
- virtual GLContextHandle GetHandle();
+ // Create a GL context used for offscreen rendering. It is initially backed by
+ // a 1x1 pbuffer. Use it to create an FBO to do useful rendering.
+ static GLContext* CreateOffscreenGLContext(void* shared_handle);
- private:
-#if defined(OS_WIN)
- gfx::PluginWindowHandle window_;
- HDC device_context_;
- GLContextHandle context_;
-#elif defined(OS_LINUX)
- gfx::PluginWindowHandle window_;
- GLContextHandle context_;
-#elif defined(OS_MACOSX)
- // This context isn't implemented on Mac OS X.
-#endif
-
- DISALLOW_COPY_AND_ASSIGN(ViewGLContext);
-};
-
-// This class is a wrapper around a GL context used for offscreen rendering.
-// It is initially backed by a 1x1 pbuffer. Use it to create an FBO to do useful
-// rendering.
-class PbufferGLContext : public GLContext {
- public:
-#if defined(OS_WIN)
- PbufferGLContext()
- : context_(NULL),
- device_context_(NULL),
- pbuffer_(NULL) {
- }
-#elif defined(OS_LINUX)
- explicit PbufferGLContext()
- : context_(NULL),
- pbuffer_(NULL) {
- }
-#elif defined(OS_MACOSX)
- PbufferGLContext()
- : context_(NULL),
- pbuffer_(NULL) {
- }
-#endif
-
- // Initializes the GL context.
- bool Initialize(GLContext* shared_context);
- bool Initialize(GLContextHandle shared_handle);
-
- virtual void Destroy();
- virtual bool MakeCurrent();
- virtual bool IsCurrent();
- virtual bool IsOffscreen();
- virtual void SwapBuffers();
- virtual gfx::Size GetSize();
- virtual GLContextHandle GetHandle();
+ protected:
+ bool InitializeCommon();
private:
- GLContextHandle context_;
-#if defined(OS_WIN)
- HDC device_context_;
- PbufferHandle pbuffer_;
-#elif defined(OS_LINUX)
- PbufferHandle pbuffer_;
-#elif defined(OS_MACOSX)
- PbufferHandle pbuffer_;
-#endif
- DISALLOW_COPY_AND_ASSIGN(PbufferGLContext);
+ DISALLOW_COPY_AND_ASSIGN(GLContext);
};
} // namespace gpu
diff --git a/gpu/command_buffer/service/gl_context_linux.cc b/gpu/command_buffer/service/gl_context_linux.cc
index acafd3b2..1c04d91 100644
--- a/gpu/command_buffer/service/gl_context_linux.cc
+++ b/gpu/command_buffer/service/gl_context_linux.cc
@@ -4,21 +4,79 @@
// This file implements the ViewGLContext and PbufferGLContext classes.
-#if !defined(UNIT_TEST)
#include <dlfcn.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
-#endif
+
+// Ensure that gl_utils.h is included before any GL headers.
+#include "gpu/command_buffer/service/gl_utils.h"
#include "app/x11_util.h"
-#include "gpu/command_buffer/service/gl_context.h"
#include "base/scoped_ptr.h"
-#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/service/gl_context.h"
+#include "gpu/command_buffer/service/gl_context_osmesa.h"
#include "gpu/command_buffer/common/logging.h"
namespace gpu {
-#if !defined(UNIT_TEST)
+typedef GLXContext GLContextHandle;
+typedef GLXPbuffer PbufferHandle;
+
+// This class is a wrapper around a GL context that renders directly to a
+// window.
+class ViewGLContext : public GLContext {
+ public:
+ explicit ViewGLContext(gfx::PluginWindowHandle window)
+ : window_(window),
+ context_(NULL) {
+ DCHECK(window);
+ }
+
+ // Initializes the GL context.
+ bool Initialize(bool multisampled);
+
+ virtual void Destroy();
+ virtual bool MakeCurrent();
+ virtual bool IsCurrent();
+ virtual bool IsOffscreen();
+ virtual void SwapBuffers();
+ virtual gfx::Size GetSize();
+ virtual void* GetHandle();
+
+ private:
+ gfx::PluginWindowHandle window_;
+ GLContextHandle context_;
+
+ DISALLOW_COPY_AND_ASSIGN(ViewGLContext);
+};
+
+// This class is a wrapper around a GL context used for offscreen rendering.
+// It is initially backed by a 1x1 pbuffer. Use it to create an FBO to do useful
+// rendering.
+class PbufferGLContext : public GLContext {
+ public:
+ explicit PbufferGLContext()
+ : context_(NULL),
+ pbuffer_(NULL) {
+ }
+
+ // Initializes the GL context.
+ bool Initialize(void* shared_handle);
+
+ virtual void Destroy();
+ virtual bool MakeCurrent();
+ virtual bool IsCurrent();
+ virtual bool IsOffscreen();
+ virtual void SwapBuffers();
+ virtual gfx::Size GetSize();
+ virtual void* GetHandle();
+
+ private:
+ GLContextHandle context_;
+ PbufferHandle pbuffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(PbufferGLContext);
+};
// scoped_ptr functor for XFree(). Use as follows:
// scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> foo(...);
@@ -35,9 +93,13 @@ class ScopedPtrXFree {
// load it, and use glew to dynamically resolve symbols.
// See http://code.google.com/p/chromium/issues/detail?id=16800
-static bool InitializeGLXEW(Display* display) {
- static bool glxew_initialized = false;
- if (!glxew_initialized) {
+static bool InitializeOneOff() {
+ static bool initialized = false;
+ if (initialized)
+ return true;
+
+ osmewInit();
+ if (!OSMesaCreateContext) {
void* handle = dlopen("libGL.so.1", RTLD_LAZY | RTLD_GLOBAL);
if (!handle) {
LOG(ERROR) << "Could not find libGL.so.1";
@@ -53,28 +115,23 @@ static bool InitializeGLXEW(Display* display) {
// complete, and we don't want to have to create an OpenGL context
// just to get access to GLX 1.3 entry points to create pbuffers.
// We therefore added a glxewContextInitWithDisplay entry point.
+ Display* display = x11_util::GetXDisplay();
if (glxewContextInitWithDisplay(display) != GLEW_OK) {
LOG(ERROR) << "glxewContextInit failed";
return false;
}
- glxew_initialized = true;
}
+ initialized = true;
return true;
}
-#endif // UNIT_TEST
-
bool ViewGLContext::Initialize(bool multisampled) {
-#if !defined(UNIT_TEST)
if (multisampled) {
DLOG(WARNING) << "Multisampling not implemented.";
}
Display* display = x11_util::GetXDisplay();
- if (!InitializeGLXEW(display))
- return false;
-
XWindowAttributes attributes;
XGetWindowAttributes(display, window_, &attributes);
XVisualInfo visual_info_template;
@@ -113,13 +170,10 @@ bool ViewGLContext::Initialize(bool multisampled) {
return false;
}
-#endif // UNIT_TEST
-
return true;
}
void ViewGLContext::Destroy() {
-#if !defined(UNIT_TEST)
Display* display = x11_util::GetXDisplay();
Bool result = glXMakeCurrent(display, 0, 0);
@@ -131,11 +185,9 @@ void ViewGLContext::Destroy() {
glXDestroyContext(display, context_);
context_ = NULL;
}
-#endif // UNIT_TEST
}
bool ViewGLContext::MakeCurrent() {
-#if !defined(UNIT_TEST)
if (IsCurrent()) {
return true;
}
@@ -147,18 +199,13 @@ bool ViewGLContext::MakeCurrent() {
DLOG(ERROR) << "Couldn't make context current.";
return false;
}
-#endif // UNIT_TEST
return true;
}
bool ViewGLContext::IsCurrent() {
-#if !defined(UNIT_TEST)
return glXGetCurrentDrawable() == window_ &&
glXGetCurrentContext() == context_;
-#else
- return true;
-#endif
}
bool ViewGLContext::IsOffscreen() {
@@ -166,41 +213,41 @@ bool ViewGLContext::IsOffscreen() {
}
void ViewGLContext::SwapBuffers() {
-#if !defined(UNIT_TEST)
Display* display = x11_util::GetXDisplay();
glXSwapBuffers(display, window_);
-#endif // UNIT_TEST
}
gfx::Size ViewGLContext::GetSize() {
-#if !defined(UNIT_TEST)
XWindowAttributes attributes;
Display* display = x11_util::GetXDisplay();
XGetWindowAttributes(display, window_, &attributes);
return gfx::Size(attributes.width, attributes.height);
-#else
- return gfx::Size();
-#endif // UNIT_TEST
}
-GLContextHandle ViewGLContext::GetHandle() {
-#if !defined(UNIT_TEST)
+void* ViewGLContext::GetHandle() {
return context_;
-#else
- return NULL;
-#endif // UNIT_TEST
}
-bool PbufferGLContext::Initialize(GLContext* shared_context) {
- return Initialize(shared_context ? shared_context->GetHandle() : NULL);
-}
+GLContext* GLContext::CreateViewGLContext(gfx::PluginWindowHandle window,
+ bool multisampled) {
+ if (!InitializeOneOff())
+ return NULL;
-bool PbufferGLContext::Initialize(GLContextHandle shared_handle) {
-#if !defined(UNIT_TEST)
- Display* display = x11_util::GetXDisplay();
- if (!InitializeGLXEW(display))
- return false;
+ if (OSMesaCreateContext) {
+ // TODO(apatrick): Support OSMesa rendering to a window on Linux.
+ NOTREACHED() << "OSMesa rendering to a window is not yet implemented.";
+ return NULL;
+ } else {
+ scoped_ptr<ViewGLContext> context(new ViewGLContext(window));
+
+ if (!context->Initialize(multisampled))
+ return NULL;
+
+ return context.release();
+ }
+}
+bool PbufferGLContext::Initialize(void* shared_handle) {
if (!glXChooseFBConfig ||
!glXCreateNewContext ||
!glXCreatePbuffer ||
@@ -219,6 +266,8 @@ bool PbufferGLContext::Initialize(GLContextHandle shared_handle) {
0
};
+ Display* display = x11_util::GetXDisplay();
+
int nelements = 0;
// TODO(kbr): figure out whether hardcoding screen to 0 is sufficient.
scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> config(
@@ -234,7 +283,7 @@ bool PbufferGLContext::Initialize(GLContextHandle shared_handle) {
context_ = glXCreateNewContext(display,
config.get()[0],
GLX_RGBA_TYPE,
- shared_handle,
+ static_cast<GLContextHandle>(shared_handle),
True);
if (!context_) {
DLOG(ERROR) << "glXCreateNewContext failed.";
@@ -271,13 +320,10 @@ bool PbufferGLContext::Initialize(GLContextHandle shared_handle) {
return false;
}
-#endif // UNIT_TEST
-
return true;
}
void PbufferGLContext::Destroy() {
-#if !defined(UNIT_TEST)
Display* display = x11_util::GetXDisplay();
Bool result = glXMakeCurrent(display, 0, 0);
// glXMakeCurrent isn't supposed to fail when unsetting the context, unless
@@ -293,11 +339,9 @@ void PbufferGLContext::Destroy() {
glXDestroyPbuffer(display, pbuffer_);
pbuffer_ = NULL;
}
-#endif // UNIT_TEST
}
bool PbufferGLContext::MakeCurrent() {
-#if !defined(UNIT_TEST)
if (IsCurrent()) {
return true;
}
@@ -308,18 +352,13 @@ bool PbufferGLContext::MakeCurrent() {
DLOG(ERROR) << "Couldn't make context current.";
return false;
}
-#endif // UNIT_TEST
return true;
}
bool PbufferGLContext::IsCurrent() {
-#if !defined(UNIT_TEST)
return glXGetCurrentDrawable() == pbuffer_ &&
glXGetCurrentContext() == context_;
-#else
- return true;
-#endif
}
bool PbufferGLContext::IsOffscreen() {
@@ -335,12 +374,28 @@ gfx::Size PbufferGLContext::GetSize() {
return gfx::Size(1, 1);
}
-GLContextHandle PbufferGLContext::GetHandle() {
-#if !defined(UNIT_TEST)
+void* PbufferGLContext::GetHandle() {
return context_;
-#else
- return NULL;
-#endif // UNIT_TEST
+}
+
+GLContext* GLContext::CreateOffscreenGLContext(void* shared_handle) {
+ if (!InitializeOneOff())
+ return NULL;
+
+ if (OSMesaCreateContext) {
+ scoped_ptr<OSMesaGLContext> context(new OSMesaGLContext);
+
+ if (!context->Initialize(shared_handle))
+ return NULL;
+
+ return context.release();
+ } else {
+ scoped_ptr<PbufferGLContext> context(new PbufferGLContext);
+ if (!context->Initialize(shared_handle))
+ return NULL;
+
+ return context.release();
+ }
}
} // namespace gpu
diff --git a/gpu/command_buffer/service/gl_context_mac.cc b/gpu/command_buffer/service/gl_context_mac.cc
index 509e965..7fed885 100644
--- a/gpu/command_buffer/service/gl_context_mac.cc
+++ b/gpu/command_buffer/service/gl_context_mac.cc
@@ -4,84 +4,59 @@
// This file implements the ViewGLContext and PbufferGLContext classes.
-#include "gpu/command_buffer/service/gl_context.h"
-#include "gpu/command_buffer/common/logging.h"
+// Ensure that gl_utils.h is included before any GL headers.
+#include "gpu/command_buffer/service/gl_utils.h"
-#if !defined(UNIT_TEST)
#include "app/surface/accelerated_surface_mac.h"
-#endif
+#include "base/scoped_ptr.h"
+#include "gpu/command_buffer/service/gl_context.h"
+#include "gpu/command_buffer/service/gl_context_osmesa.h"
+#include "gpu/command_buffer/common/logging.h"
namespace gpu {
-static const char* error_message =
- "ViewGLContext not supported on Mac platform.";
+typedef CGLContextObj GLContextHandle;
+typedef CGLPBufferObj PbufferHandle;
+
+// This class is a wrapper around a GL context used for offscreen rendering.
+// It is initially backed by a 1x1 pbuffer. Use it to create an FBO to do useful
+// rendering.
+class PbufferGLContext : public GLContext {
+ public:
+ PbufferGLContext()
+ : context_(NULL),
+ pbuffer_(NULL) {
+ }
-bool ViewGLContext::Initialize(bool multisampled) {
-#if !defined(UNIT_TEST)
- NOTIMPLEMENTED() << error_message;
- return false;
-#else
- return true;
-#endif // UNIT_TEST
-}
+ // Initializes the GL context.
+ bool Initialize(void* shared_handle);
-void ViewGLContext::Destroy() {
-#if !defined(UNIT_TEST)
- NOTIMPLEMENTED() << error_message;
-#endif // UNIT_TEST
-}
+ virtual void Destroy();
+ virtual bool MakeCurrent();
+ virtual bool IsCurrent();
+ virtual bool IsOffscreen();
+ virtual void SwapBuffers();
+ virtual gfx::Size GetSize();
+ virtual void* GetHandle();
-bool ViewGLContext::MakeCurrent() {
-#if !defined(UNIT_TEST)
- NOTIMPLEMENTED() << error_message;
- return false;
-#else
- return true;
-#endif
-}
+ private:
+ GLContextHandle context_;
+ PbufferHandle pbuffer_;
-bool ViewGLContext::IsCurrent() {
-#if !defined(UNIT_TEST)
- NOTIMPLEMENTED() << error_message;
- return false;
-#else
- return true;
-#endif
-}
+ DISALLOW_COPY_AND_ASSIGN(PbufferGLContext);
+};
-bool ViewGLContext::IsOffscreen() {
- NOTIMPLEMENTED() << error_message;
- return false;
-}
-
-void ViewGLContext::SwapBuffers() {
-#if !defined(UNIT_TEST)
- NOTIMPLEMENTED() << error_message;
-#endif // UNIT_TEST
-}
+static bool InitializeOneOff() {
+ static bool initialized = false;
+ if (initialized)
+ return true;
-gfx::Size ViewGLContext::GetSize() {
-#if !defined(UNIT_TEST)
- NOTIMPLEMENTED() << error_message;
- return gfx::Size();
-#else
- return gfx::Size();
-#endif // UNIT_TEST
-}
-
-GLContextHandle ViewGLContext::GetHandle() {
-#if !defined(UNIT_TEST)
- NOTIMPLEMENTED() << error_message;
-#endif // UNIT_TEST
- return NULL;
-}
-
-bool PbufferGLContext::Initialize(GLContext* shared_context) {
- return Initialize(shared_context ? shared_context->GetHandle() : NULL);
+ osmewInit();
+ initialized = true;
+ return true;
}
-bool PbufferGLContext::Initialize(GLContextHandle shared_handle) {
-#if !defined(UNIT_TEST)
+bool PbufferGLContext::Initialize(void* shared_handle) {
// Create a 1x1 pbuffer and associated context to bootstrap things.
static const CGLPixelFormatAttribute attribs[] = {
(CGLPixelFormatAttribute) kCGLPFAPBuffer,
@@ -99,7 +74,9 @@ bool PbufferGLContext::Initialize(GLContextHandle shared_handle) {
if (!pixel_format) {
return false;
}
- CGLError res = CGLCreateContext(pixel_format, shared_handle, &context_);
+ CGLError res = CGLCreateContext(pixel_format,
+ static_cast<GLContextHandle>(shared_handle),
+ &context_);
CGLDestroyPixelFormat(pixel_format);
if (res != kCGLNoError) {
DLOG(ERROR) << "Error creating context.";
@@ -135,13 +112,10 @@ bool PbufferGLContext::Initialize(GLContextHandle shared_handle) {
return false;
}
-#endif // UNIT_TEST
-
return true;
}
void PbufferGLContext::Destroy() {
-#if !defined(UNIT_TEST)
if (context_) {
CGLDestroyContext(context_);
context_ = NULL;
@@ -151,28 +125,21 @@ void PbufferGLContext::Destroy() {
CGLDestroyPBuffer(pbuffer_);
pbuffer_ = NULL;
}
-#endif // UNIT_TEST
}
bool PbufferGLContext::MakeCurrent() {
-#if !defined(UNIT_TEST)
if (!IsCurrent()) {
if (CGLSetCurrentContext(context_) != kCGLNoError) {
DLOG(ERROR) << "Unable to make gl context current.";
return false;
}
}
-#endif // UNIT_TEST
return true;
}
bool PbufferGLContext::IsCurrent() {
-#if !defined(UNIT_TEST)
return CGLGetCurrentContext() == context_;
-#else
- return true;
-#endif
}
bool PbufferGLContext::IsOffscreen() {
@@ -188,12 +155,28 @@ gfx::Size PbufferGLContext::GetSize() {
return gfx::Size(1, 1);
}
-GLContextHandle PbufferGLContext::GetHandle() {
-#if !defined(UNIT_TEST)
+void* PbufferGLContext::GetHandle() {
return context_;
-#else
- return NULL;
-#endif // UNIT_TEST
+}
+
+GLContext* GLContext::CreateOffscreenGLContext(void* shared_handle) {
+ if (!InitializeOneOff())
+ return NULL;
+
+ if (OSMesaCreateContext) {
+ scoped_ptr<OSMesaGLContext> context(new OSMesaGLContext);
+
+ if (!context->Initialize(shared_handle))
+ return NULL;
+
+ return context.release();
+ } else {
+ scoped_ptr<PbufferGLContext> context(new PbufferGLContext);
+ if (!context->Initialize(shared_handle))
+ return NULL;
+
+ return context.release();
+ }
}
} // namespace gpu
diff --git a/gpu/command_buffer/service/gl_context_osmesa.cc b/gpu/command_buffer/service/gl_context_osmesa.cc
new file mode 100644
index 0000000..6ec7489
--- /dev/null
+++ b/gpu/command_buffer/service/gl_context_osmesa.cc
@@ -0,0 +1,106 @@
+// Copyright (c) 2009 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 <algorithm>
+
+#include "gpu/command_buffer/service/gl_context_osmesa.h"
+
+namespace gpu {
+
+OSMesaGLContext::OSMesaGLContext()
+#if !defined(UNIT_TEST)
+ : context_(NULL)
+#endif
+{
+}
+
+OSMesaGLContext::~OSMesaGLContext() {
+}
+
+bool OSMesaGLContext::Initialize(void* shared_handle) {
+#if !defined(UNIT_TEST)
+ DCHECK(!context_);
+
+ size_ = gfx::Size(1, 1);
+ buffer_.reset(new int32[1]);
+
+ context_ = OSMesaCreateContext(GL_RGBA,
+ static_cast<OSMesaContext>(shared_handle));
+ return context_ != NULL;
+#else
+ return true;
+#endif
+}
+
+void OSMesaGLContext::Destroy() {
+#if !defined(UNIT_TEST)
+ if (context_) {
+ OSMesaDestroyContext(static_cast<OSMesaContext>(context_));
+ context_ = NULL;
+ }
+#endif
+}
+
+bool OSMesaGLContext::MakeCurrent() {
+#if !defined(UNIT_TEST)
+ DCHECK(context_);
+ return OSMesaMakeCurrent(static_cast<OSMesaContext>(context_),
+ buffer_.get(),
+ GL_UNSIGNED_BYTE,
+ size_.width(), size_.height()) == GL_TRUE;
+#endif
+ return true;
+}
+
+bool OSMesaGLContext::IsCurrent() {
+#if !defined(UNIT_TEST)
+ DCHECK(context_);
+ return context_ == OSMesaGetCurrentContext();
+#endif
+ return true;
+}
+
+bool OSMesaGLContext::IsOffscreen() {
+ return true;
+}
+
+void OSMesaGLContext::SwapBuffers() {
+ NOTREACHED() << "Should not call SwapBuffers on an OSMesaGLContext.";
+}
+
+gfx::Size OSMesaGLContext::GetSize() {
+ return size_;
+}
+
+void* OSMesaGLContext::GetHandle() {
+ return context_;
+}
+
+void OSMesaGLContext::Resize(const gfx::Size& new_size) {
+ if (new_size == size_)
+ return;
+
+ // Allocate a new back buffer.
+ scoped_array<int32> new_buffer(new int32[new_size.GetArea()]);
+ memset(new_buffer.get(), 0, new_size.GetArea() * sizeof(new_buffer[0]));
+
+ // Copy the current back buffer into the new buffer.
+ int copy_width = std::min(size_.width(), new_size.width());
+ int copy_height = std::min(size_.height(), new_size.height());
+ for (int y = 0; y < copy_height; ++y) {
+ for (int x = 0; x < copy_width; ++x) {
+ new_buffer[y * new_size.width() + x] = buffer_[y * size_.width() + x];
+ }
+ }
+
+ buffer_.reset(new_buffer.release());
+ size_ = new_size;
+
+ // If this context is current, need to call MakeCurrent again so OSMesa uses
+ // the new buffer.
+ if (IsCurrent())
+ MakeCurrent();
+}
+
+} // namespace gpu
diff --git a/gpu/command_buffer/service/gl_context_osmesa.h b/gpu/command_buffer/service/gl_context_osmesa.h
new file mode 100644
index 0000000..06b14ca
--- /dev/null
+++ b/gpu/command_buffer/service/gl_context_osmesa.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2010 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.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GL_CONTEXT_OSMESA_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GL_CONTEXT_OSMESA_H_
+
+// Ensure that gl_utils.h is included before any GL headers.
+#include "gpu/command_buffer/service/gl_utils.h"
+
+#include "base/scoped_ptr.h"
+#include "gfx/size.h"
+#include "gpu/command_buffer/service/gl_context.h"
+
+namespace gpu {
+
+// Encapsulates an OSMesa OpenGL context that uses software rendering.
+class OSMesaGLContext : public GLContext {
+ public:
+ OSMesaGLContext();
+ virtual ~OSMesaGLContext();
+
+ // Initialize an OSMesa GL context with the default 1 x 1 initial size.
+ bool Initialize(void* shared_handle);
+
+ // Implement GLContext.
+ virtual void Destroy();
+ virtual bool MakeCurrent();
+ virtual bool IsCurrent();
+ virtual bool IsOffscreen();
+ virtual void SwapBuffers();
+ virtual gfx::Size GetSize();
+ virtual void* GetHandle();
+
+ // Resize the back buffer, preserving the old content. Does nothing if the
+ // size is unchanged.
+ void Resize(const gfx::Size& new_size);
+
+ const void* buffer() const {
+ return buffer_.get();
+ }
+
+ protected:
+ bool InitializeCommon();
+
+ private:
+#if !defined(UNIT_TEST)
+ gfx::Size size_;
+ scoped_array<int32> buffer_;
+ OSMesaContext context_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(OSMesaGLContext);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_GL_CONTEXT_OSMESA_H_
diff --git a/gpu/command_buffer/service/gl_context_stub.cc b/gpu/command_buffer/service/gl_context_stub.cc
new file mode 100644
index 0000000..84e6209
--- /dev/null
+++ b/gpu/command_buffer/service/gl_context_stub.cc
@@ -0,0 +1,39 @@
+// Copyright (c) 2010 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.
+
+// This file implements the StubGLContext.
+
+#include "build/build_config.h"
+#include "gpu/command_buffer/service/gl_context.h"
+
+namespace gpu {
+
+// A GLContext that does nothing for unit tests.
+class StubGLContext : public GLContext {
+ public:
+
+ // Implement GLContext.
+ virtual void Destroy() {}
+ virtual bool MakeCurrent() { return true; }
+ virtual bool IsCurrent() { return true; }
+ virtual bool IsOffscreen() { return true; }
+ virtual void SwapBuffers() {}
+ virtual gfx::Size GetSize() { return gfx::Size(); }
+ virtual void* GetHandle() { return NULL; }
+};
+
+#if !defined(OS_MACOSX)
+
+GLContext* GLContext::CreateViewGLContext(gfx::PluginWindowHandle /* window */,
+ bool /* multisampled */) {
+ return new StubGLContext;
+}
+
+#endif // OS_MACOSX
+
+GLContext* GLContext::CreateOffscreenGLContext(void* /* shared_handle */) {
+ return new StubGLContext;
+}
+
+} // namespace gpu
diff --git a/gpu/command_buffer/service/gl_context_win.cc b/gpu/command_buffer/service/gl_context_win.cc
index 0425e17..05cee5b 100644
--- a/gpu/command_buffer/service/gl_context_win.cc
+++ b/gpu/command_buffer/service/gl_context_win.cc
@@ -2,14 +2,113 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// This file implements the ViewGLContext and PbufferGLContext classes.
+// This file implements the NativeViewGLContext and PbufferGLContext classes.
+#include <algorithm>
+
+// Ensure that gl_utils.h is included before any GL headers.
+#include "gpu/command_buffer/service/gl_utils.h"
+
+#include "base/scoped_ptr.h"
#include "gpu/command_buffer/service/gl_context.h"
+#include "gpu/command_buffer/service/gl_context_osmesa.h"
#include "gpu/command_buffer/common/logging.h"
namespace gpu {
-#if !defined(UNIT_TEST)
+typedef HGLRC GLContextHandle;
+typedef HPBUFFERARB PbufferHandle;
+
+// This class is a wrapper around a GL context that renders directly to a
+// window.
+class NativeViewGLContext : public GLContext {
+ public:
+ explicit NativeViewGLContext(gfx::PluginWindowHandle window)
+ : window_(window),
+ device_context_(NULL),
+ context_(NULL) {
+ DCHECK(window);
+ }
+
+ // Initializes the GL context.
+ bool Initialize(bool multisampled);
+
+ virtual void Destroy();
+ virtual bool MakeCurrent();
+ virtual bool IsCurrent();
+ virtual bool IsOffscreen();
+ virtual void SwapBuffers();
+ virtual gfx::Size GetSize();
+ virtual void* GetHandle();
+
+ private:
+ gfx::PluginWindowHandle window_;
+ HDC device_context_;
+ GLContextHandle context_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeViewGLContext);
+};
+
+// This class is a wrapper around a GL context that uses OSMesa to render
+// to an offscreen buffer and then blits it to a window.
+class OSMesaViewGLContext : public GLContext {
+ public:
+ explicit OSMesaViewGLContext(gfx::PluginWindowHandle window)
+ : window_(window),
+ device_context_(NULL) {
+ DCHECK(window);
+ }
+
+ // Initializes the GL context.
+ bool Initialize();
+
+ virtual void Destroy();
+ virtual bool MakeCurrent();
+ virtual bool IsCurrent();
+ virtual bool IsOffscreen();
+ virtual void SwapBuffers();
+ virtual gfx::Size GetSize();
+ virtual void* GetHandle();
+
+ private:
+ void UpdateSize();
+
+ gfx::PluginWindowHandle window_;
+ HDC device_context_;
+ OSMesaGLContext osmesa_context_;
+
+ DISALLOW_COPY_AND_ASSIGN(OSMesaViewGLContext);
+};
+
+// This class is a wrapper around a GL context used for offscreen rendering.
+// It is initially backed by a 1x1 pbuffer. Use it to create an FBO to do useful
+// rendering.
+class PbufferGLContext : public GLContext {
+ public:
+ PbufferGLContext()
+ : context_(NULL),
+ device_context_(NULL),
+ pbuffer_(NULL) {
+ }
+
+ // Initializes the GL context.
+ bool Initialize(void* shared_handle);
+
+ virtual void Destroy();
+ virtual bool MakeCurrent();
+ virtual bool IsCurrent();
+ virtual bool IsOffscreen();
+ virtual void SwapBuffers();
+ virtual gfx::Size GetSize();
+ virtual void* GetHandle();
+
+ private:
+ GLContextHandle context_;
+ HDC device_context_;
+ PbufferHandle pbuffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(PbufferGLContext);
+};
static int g_regular_pixel_format = 0;
static int g_multisampled_pixel_format = 0;
@@ -41,92 +140,74 @@ LRESULT CALLBACK IntermediateWindowProc(HWND window,
return ::DefWindowProc(window, message, w_param, l_param);
}
-#endif // UNIT_TEST
-
// Helper routine that does one-off initialization like determining the
// pixel format and initializing glew.
static bool InitializeOneOff() {
-#if !defined(UNIT_TEST)
static bool initialized = false;
if (initialized)
return true;
- // 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;
- }
+ osmewInit();
+ if (!OSMesaCreateContext) {
+ // 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;
+ }
- 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;
- }
+ 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;
+ }
- HDC intermediate_dc = ::GetDC(intermediate_window);
- g_regular_pixel_format = ::ChoosePixelFormat(intermediate_dc,
- &kPixelFormatDescriptor);
- if (g_regular_pixel_format == 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, g_regular_pixel_format,
- &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;
- }
+ 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;
+ }
- // Create a temporary GL context to query for multisampled pixel formats.
- 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.
- if (InitializeGLEW()) {
- DLOG(INFO) << "Initialized GLEW " << glewGetString(GLEW_VERSION);
- } else {
- ::wglMakeCurrent(intermediate_dc, NULL);
- ::wglDeleteContext(gl_context);
+ HDC intermediate_dc = ::GetDC(intermediate_window);
+ g_regular_pixel_format = ::ChoosePixelFormat(intermediate_dc,
+ &kPixelFormatDescriptor);
+ if (g_regular_pixel_format == 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, g_regular_pixel_format,
+ &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),
@@ -134,59 +215,73 @@ static bool InitializeOneOff() {
return false;
}
- // If the multi-sample extensions are present, query the api to determine
- // the pixel format.
- if (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};
- 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,
- &g_multisampled_pixel_format,
- &num_formats)) {
- break;
+ // Create a temporary GL context to query for multisampled pixel formats.
+ 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.
+ if (InitializeGLEW()) {
+ DLOG(INFO) << "Initialized GLEW " << glewGetString(GLEW_VERSION);
+ } else {
+ ::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 (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};
+ 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,
+ &g_multisampled_pixel_format,
+ &num_formats)) {
+ 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);
+ ::wglMakeCurrent(intermediate_dc, NULL);
+ ::wglDeleteContext(gl_context);
+ ::ReleaseDC(intermediate_window, intermediate_dc);
+ ::DestroyWindow(intermediate_window);
+ ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration),
+ module_handle);
+ }
initialized = true;
-#endif // UNIT_TEST
return true;
}
-bool ViewGLContext::Initialize(bool multisampled) {
-#if !defined(UNIT_TEST)
- InitializeOneOff();
-
+bool NativeViewGLContext::Initialize(bool multisampled) {
// The GL context will render to this window.
device_context_ = GetDC(window_);
@@ -207,18 +302,25 @@ bool ViewGLContext::Initialize(bool multisampled) {
return false;
}
- if (!InitializeCommon()) {
+ if (!MakeCurrent()) {
Destroy();
return false;
}
-#endif // UNIT_TEST
+ if (!InitializeGLEW()) {
+ Destroy();
+ return false;
+ }
+
+ if (!InitializeCommon()) {
+ Destroy();
+ return false;
+ }
return true;
}
-void ViewGLContext::Destroy() {
-#if !defined(UNIT_TEST)
+void NativeViewGLContext::Destroy() {
if (context_) {
wglDeleteContext(context_);
context_ = NULL;
@@ -229,11 +331,9 @@ void ViewGLContext::Destroy() {
window_ = NULL;
device_context_ = NULL;
-#endif // UNIT_TEST
}
-bool ViewGLContext::MakeCurrent() {
-#if !defined(UNIT_TEST)
+bool NativeViewGLContext::MakeCurrent() {
if (IsCurrent()) {
return true;
}
@@ -241,57 +341,156 @@ bool ViewGLContext::MakeCurrent() {
DLOG(ERROR) << "Unable to make gl context current.";
return false;
}
-#endif // UNIT_TEST
return true;
}
-bool ViewGLContext::IsCurrent() {
-#if !defined(UNIT_TEST)
+bool NativeViewGLContext::IsCurrent() {
return wglGetCurrentDC() == device_context_ &&
wglGetCurrentContext() == context_;
-#else
- return true;
-#endif
}
-bool ViewGLContext::IsOffscreen() {
+bool NativeViewGLContext::IsOffscreen() {
return false;
}
-void ViewGLContext::SwapBuffers() {
-#if !defined(UNIT_TEST)
+void NativeViewGLContext::SwapBuffers() {
DCHECK(device_context_);
::SwapBuffers(device_context_);
-#endif // UNIT_TEST
}
-gfx::Size ViewGLContext::GetSize() {
-#if !defined(UNIT_TEST)
+gfx::Size NativeViewGLContext::GetSize() {
RECT rect;
CHECK(GetClientRect(window_, &rect));
return gfx::Size(rect.right - rect.left, rect.bottom - rect.top);
-#else
- return gfx::Size();
-#endif // UNIT_TEST
}
-GLContextHandle ViewGLContext::GetHandle() {
-#if !defined(UNIT_TEST)
+void* NativeViewGLContext::GetHandle() {
return context_;
-#else
- return NULL;
-#endif // UNIT_TEST
}
-bool PbufferGLContext::Initialize(GLContext* shared_context) {
- return Initialize(shared_context ? shared_context->GetHandle() : NULL);
+bool OSMesaViewGLContext::Initialize() {
+ // The GL context will render to this window.
+ device_context_ = GetDC(window_);
+
+ if (!osmesa_context_.Initialize(NULL)) {
+ Destroy();
+ return false;
+ }
+
+ if (!MakeCurrent()) {
+ Destroy();
+ return false;
+ }
+
+ if (!InitializeGLEW()) {
+ Destroy();
+ return false;
+ }
+
+ if (!InitializeCommon()) {
+ Destroy();
+ return false;
+ }
+
+ UpdateSize();
+
+ return true;
+}
+
+void OSMesaViewGLContext::Destroy() {
+ osmesa_context_.Destroy();
+
+ if (window_ && device_context_)
+ ReleaseDC(window_, device_context_);
+
+ window_ = NULL;
+ device_context_ = NULL;
+}
+
+bool OSMesaViewGLContext::MakeCurrent() {
+ return osmesa_context_.MakeCurrent();
+}
+
+bool OSMesaViewGLContext::IsCurrent() {
+ return osmesa_context_.IsCurrent();
}
-bool PbufferGLContext::Initialize(GLContextHandle shared_handle) {
-#if !defined(UNIT_TEST)
- InitializeOneOff();
+bool OSMesaViewGLContext::IsOffscreen() {
+ return false;
+}
+
+void OSMesaViewGLContext::SwapBuffers() {
+ DCHECK(device_context_);
+
+ // Update the size before blitting so that the blit size is exactly the same
+ // as the window.
+ UpdateSize();
+
+ gfx::Size size = osmesa_context_.GetSize();
+
+ BITMAPV4HEADER info = { sizeof(BITMAPV4HEADER) };
+ info.bV4Width = size.width();
+ info.bV4Height = size.height();
+ info.bV4Planes = 1;
+ info.bV4BitCount = 32;
+ info.bV4V4Compression = BI_BITFIELDS;
+ info.bV4RedMask = 0xFF000000;
+ info.bV4GreenMask = 0x00FF0000;
+ info.bV4BlueMask = 0x0000FF00;
+ info.bV4AlphaMask = 0x000000FF;
+
+ // Copy the back buffer to the window's device context.
+ StretchDIBits(device_context_,
+ 0, 0, size.width(), size.height(),
+ 0, 0, size.width(), size.height(),
+ osmesa_context_.buffer(),
+ reinterpret_cast<BITMAPINFO*>(&info),
+ DIB_RGB_COLORS,
+ SRCCOPY);
+}
+
+gfx::Size OSMesaViewGLContext::GetSize() {
+ return osmesa_context_.GetSize();
+}
+
+void* OSMesaViewGLContext::GetHandle() {
+ return osmesa_context_.GetHandle();
+}
+
+void OSMesaViewGLContext::UpdateSize() {
+ // Change back buffer size to that of window.
+ RECT rect;
+ GetWindowRect(window_, &rect);
+ gfx::Size window_size = gfx::Size(
+ std::max(1, static_cast<int>(rect.right - rect.left)),
+ std::max(1, static_cast<int>(rect.bottom - rect.top)));
+ osmesa_context_.Resize(window_size);
+}
+
+GLContext* GLContext::CreateViewGLContext(gfx::PluginWindowHandle window,
+ bool multisampled) {
+ if (!InitializeOneOff())
+ return NULL;
+
+ if (OSMesaCreateContext) {
+ scoped_ptr<OSMesaViewGLContext> context(new OSMesaViewGLContext(window));
+
+ if (!context->Initialize())
+ return NULL;
+
+ return context.release();
+ } else {
+ scoped_ptr<NativeViewGLContext> context(new NativeViewGLContext(window));
+
+ if (!context->Initialize(multisampled))
+ return NULL;
+
+ return context.release();
+ }
+}
+bool PbufferGLContext::Initialize(void* shared_handle) {
// Create a device context compatible with the primary display.
HDC display_device_context = ::CreateDC(L"DISPLAY", NULL, NULL, NULL);
@@ -325,25 +524,32 @@ bool PbufferGLContext::Initialize(GLContextHandle shared_handle) {
}
if (shared_handle) {
- if (!wglShareLists(shared_handle, context_)) {
+ if (!wglShareLists(static_cast<GLContextHandle>(shared_handle), context_)) {
DLOG(ERROR) << "Could not share GL contexts.";
Destroy();
return false;
}
}
- if (!InitializeCommon()) {
+ if (!MakeCurrent()) {
Destroy();
return false;
}
-#endif // UNIT_TEST
+ if (!InitializeGLEW()) {
+ Destroy();
+ return false;
+ }
+
+ if (!InitializeCommon()) {
+ Destroy();
+ return false;
+ }
return true;
}
void PbufferGLContext::Destroy() {
-#if !defined(UNIT_TEST)
if (context_) {
wglDeleteContext(context_);
context_ = NULL;
@@ -358,11 +564,9 @@ void PbufferGLContext::Destroy() {
wglDestroyPbufferARB(pbuffer_);
pbuffer_ = NULL;
}
-#endif // UNIT_TEST
}
bool PbufferGLContext::MakeCurrent() {
-#if !defined(UNIT_TEST)
if (IsCurrent()) {
return true;
}
@@ -370,18 +574,13 @@ bool PbufferGLContext::MakeCurrent() {
DLOG(ERROR) << "Unable to make gl context current.";
return false;
}
-#endif // UNIT_TEST
return true;
}
bool PbufferGLContext::IsCurrent() {
-#if !defined(UNIT_TEST)
return wglGetCurrentDC() == device_context_ &&
wglGetCurrentContext() == context_;
-#else
- return true;
-#endif
}
bool PbufferGLContext::IsOffscreen() {
@@ -397,12 +596,28 @@ gfx::Size PbufferGLContext::GetSize() {
return gfx::Size(1, 1);
}
-GLContextHandle PbufferGLContext::GetHandle() {
-#if !defined(UNIT_TEST)
+void* PbufferGLContext::GetHandle() {
return context_;
-#else
- return NULL;
-#endif // UNIT_TEST
+}
+
+GLContext* GLContext::CreateOffscreenGLContext(void* shared_handle) {
+ if (!InitializeOneOff())
+ return NULL;
+
+ if (OSMesaCreateContext) {
+ scoped_ptr<OSMesaGLContext> context(new OSMesaGLContext);
+
+ if (!context->Initialize(shared_handle))
+ return NULL;
+
+ return context.release();
+ } else {
+ scoped_ptr<PbufferGLContext> context(new PbufferGLContext);
+ if (!context->Initialize(shared_handle))
+ return NULL;
+
+ return context.release();
+ }
}
} // namespace gpu
diff --git a/gpu/command_buffer/service/gl_utils.h b/gpu/command_buffer/service/gl_utils.h
index ca8c630..9b9437a 100644
--- a/gpu/command_buffer/service/gl_utils.h
+++ b/gpu/command_buffer/service/gl_utils.h
@@ -51,6 +51,7 @@
#else // !GLES2_GPU_SERVICE_BACKEND_NATIVE_GLES2
#include <GL/glew.h> // NOLINT
+ #include <GL/osmew.h>
#if defined(OS_WIN)
#include <GL/wglew.h> // NOLINT
#include <windows.h> // NOLINT
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 0c25c2f..2b35aa0 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -830,7 +830,7 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
// clearing a render buffer when it is created.
// TODO(apatrick): Decoders in the same ContextGroup could potentially share
// the same default GL context.
- scoped_ptr<PbufferGLContext> default_context_;
+ scoped_ptr<GLContext> default_context_;
// A parent decoder can access this decoders saved offscreen frame buffer.
// The parent pointer is reset if the parent is destroyed.
@@ -1168,13 +1168,15 @@ bool GLES2DecoderImpl::Initialize(GLContext* context,
const gfx::Size& size,
GLES2Decoder* parent,
uint32 parent_client_texture_id) {
+ DCHECK(context);
DCHECK(!context_);
context_ = context;
// Create a GL context that is kept in a default state and shares a namespace
// with the main GL context.
- default_context_.reset(new PbufferGLContext);
- if (!default_context_->Initialize(context_)) {
+ default_context_.reset(GLContext::CreateOffscreenGLContext(
+ context_->GetHandle()));
+ if (!default_context_.get()) {
Destroy();
return false;
}
@@ -1589,40 +1591,42 @@ void GLES2DecoderImpl::SetSwapBuffersCallback(Callback0::Type* callback) {
}
void GLES2DecoderImpl::Destroy() {
- MakeCurrent();
+ if (context_) {
+ MakeCurrent();
- // Remove the saved frame buffer mapping from the parent decoder. The
- // parent pointer is a weak pointer so it will be null if the parent has
- // already been destroyed.
- if (parent_) {
- // First check the texture has been mapped into the parent. This might not
- // be the case if initialization failed midway through.
- GLuint service_id = offscreen_saved_color_texture_->id();
- GLuint client_id;
- if (parent_->id_manager()->GetClientId(service_id, &client_id)) {
- parent_->texture_manager()->RemoveTextureInfo(service_id);
- parent_->id_manager()->RemoveMapping(client_id, service_id);
+ // Remove the saved frame buffer mapping from the parent decoder. The
+ // parent pointer is a weak pointer so it will be null if the parent has
+ // already been destroyed.
+ if (parent_) {
+ // First check the texture has been mapped into the parent. This might not
+ // be the case if initialization failed midway through.
+ GLuint service_id = offscreen_saved_color_texture_->id();
+ GLuint client_id;
+ if (parent_->id_manager()->GetClientId(service_id, &client_id)) {
+ parent_->texture_manager()->RemoveTextureInfo(service_id);
+ parent_->id_manager()->RemoveMapping(client_id, service_id);
+ }
}
- }
- if (offscreen_target_frame_buffer_.get()) {
- offscreen_target_frame_buffer_->Destroy();
- offscreen_target_frame_buffer_.reset();
- }
+ if (offscreen_target_frame_buffer_.get()) {
+ offscreen_target_frame_buffer_->Destroy();
+ offscreen_target_frame_buffer_.reset();
+ }
- if (offscreen_target_color_texture_.get()) {
- offscreen_target_color_texture_->Destroy();
- offscreen_target_color_texture_.reset();
- }
+ if (offscreen_target_color_texture_.get()) {
+ offscreen_target_color_texture_->Destroy();
+ offscreen_target_color_texture_.reset();
+ }
- if (offscreen_target_depth_stencil_render_buffer_.get()) {
- offscreen_target_depth_stencil_render_buffer_->Destroy();
- offscreen_target_depth_stencil_render_buffer_.reset();
- }
+ if (offscreen_target_depth_stencil_render_buffer_.get()) {
+ offscreen_target_depth_stencil_render_buffer_->Destroy();
+ offscreen_target_depth_stencil_render_buffer_.reset();
+ }
- if (offscreen_saved_color_texture_.get()) {
- offscreen_saved_color_texture_->Destroy();
- offscreen_saved_color_texture_.reset();
+ if (offscreen_saved_color_texture_.get()) {
+ offscreen_saved_color_texture_->Destroy();
+ offscreen_saved_color_texture_.reset();
+ }
}
if (default_context_.get()) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
index 35b5ec6..385779e 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -94,8 +94,10 @@ void GLES2DecoderTestBase::SetUp() {
shared_memory_offset_;
shared_memory_id_ = kSharedMemoryId;
+ context_.reset(GLContext::CreateOffscreenGLContext(NULL));
+
decoder_.reset(GLES2Decoder::Create(&group_));
- decoder_->Initialize(NULL, gfx::Size(), NULL, 0);
+ decoder_->Initialize(context_.get(), gfx::Size(), NULL, 0);
decoder_->set_engine(engine_.get());
EXPECT_CALL(*gl_, GenBuffersARB(_, _))
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
index 0513d6a..773e285 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
@@ -11,6 +11,7 @@
#include "gpu/command_buffer/service/cmd_buffer_engine.h"
#include "gpu/command_buffer/service/context_group.h"
#include "gpu/command_buffer/service/framebuffer_manager.h"
+#include "gpu/command_buffer/service/gl_context.h"
#include "gpu/command_buffer/service/gl_mock.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
#include "gpu/command_buffer/service/program_manager.h"
@@ -173,6 +174,7 @@ class GLES2DecoderTestBase : public testing::Test {
// Use StrictMock to make 100% sure we know how GL will be called.
scoped_ptr< ::testing::StrictMock< ::gles2::MockGLInterface> > gl_;
+ scoped_ptr<GLContext> context_;
scoped_ptr<GLES2Decoder> decoder_;
GLuint client_buffer_id_;
diff --git a/gpu/command_buffer/service/gpu_processor_linux.cc b/gpu/command_buffer/service/gpu_processor_linux.cc
index aae4d7b..39fd234 100644
--- a/gpu/command_buffer/service/gpu_processor_linux.cc
+++ b/gpu/command_buffer/service/gpu_processor_linux.cc
@@ -20,35 +20,32 @@ bool GPUProcessor::Initialize(gfx::PluginWindowHandle window,
// Get the parent decoder and the GLContext to share IDs with, if any.
gles2::GLES2Decoder* parent_decoder = NULL;
GLContext* parent_context = NULL;
+ void* parent_handle = NULL;
if (parent) {
parent_decoder = parent->decoder_.get();
DCHECK(parent_decoder);
parent_context = parent_decoder->GetGLContext();
DCHECK(parent_context);
+
+ parent_handle = parent_context->GetHandle();
+ DCHECK(parent_handle);
}
// Create either a view or pbuffer based GLContext.
if (window) {
- scoped_ptr<ViewGLContext> context(new ViewGLContext(window));
+ DCHECK(!parent_handle);
+
// TODO(apatrick): support multisampling.
- if (!context->Initialize(false)) {
- Destroy();
- return false;
- }
- context_.reset(context.release());
+ context_.reset(GLContext::CreateViewGLContext(window, false));
} else {
- scoped_ptr<PbufferGLContext> context(new PbufferGLContext());
- if (!context->Initialize(parent_context)) {
- Destroy();
- return false;
- }
- context_.reset(context.release());
+ context_.reset(GLContext::CreateOffscreenGLContext(parent_handle));
}
- return InitializeCommon(size, parent_decoder, parent_texture_id);
+ if (!context_.get())
+ return false;
- return true;
+ return InitializeCommon(size, parent_decoder, parent_texture_id);
}
void GPUProcessor::Destroy() {
diff --git a/gpu/command_buffer/service/gpu_processor_mac.cc b/gpu/command_buffer/service/gpu_processor_mac.cc
index 4893c89..e7a3f6a 100644
--- a/gpu/command_buffer/service/gpu_processor_mac.cc
+++ b/gpu/command_buffer/service/gpu_processor_mac.cc
@@ -20,20 +20,22 @@ bool GPUProcessor::Initialize(gfx::PluginWindowHandle window,
// Get the parent decoder and the GLContext to share IDs with, if any.
gles2::GLES2Decoder* parent_decoder = NULL;
GLContext* parent_context = NULL;
+ void* parent_handle = NULL;
if (parent) {
parent_decoder = parent->decoder_.get();
DCHECK(parent_decoder);
parent_context = parent_decoder->GetGLContext();
DCHECK(parent_context);
+
+ parent_handle = parent_context->GetHandle();
+ DCHECK(parent_handle);
}
- scoped_ptr<PbufferGLContext> context(new PbufferGLContext);
- if (!context->Initialize(parent_context)) {
- Destroy();
+ context_.reset(GLContext::CreateOffscreenGLContext(parent_handle));
+ if (!context_.get())
return false;
- }
- context_.reset(context.release());
+
// On Mac OS X since we can not render on-screen we don't even
// attempt to create a view based GLContext. The only difference
// between "on-screen" and "off-screen" rendering on this platform
@@ -42,7 +44,9 @@ bool GPUProcessor::Initialize(gfx::PluginWindowHandle window,
if (window) {
#if !defined(UNIT_TEST)
surface_.reset(new AcceleratedSurface());
- if (!surface_->Initialize(context_->GetHandle(), false)) {
+ // TODO(apatrick): AcceleratedSurface will not work with an OSMesa context.
+ if (!surface_->Initialize(
+ static_cast<CGLContextObj>(context_->GetHandle()), false)) {
Destroy();
return false;
}
diff --git a/gpu/command_buffer/service/gpu_processor_win.cc b/gpu/command_buffer/service/gpu_processor_win.cc
index 77523be..f4e3d54 100644
--- a/gpu/command_buffer/service/gpu_processor_win.cc
+++ b/gpu/command_buffer/service/gpu_processor_win.cc
@@ -22,35 +22,32 @@ bool GPUProcessor::Initialize(gfx::PluginWindowHandle window,
// Get the parent decoder and the GLContext to share IDs with, if any.
gles2::GLES2Decoder* parent_decoder = NULL;
GLContext* parent_context = NULL;
+ void* parent_handle = NULL;
if (parent) {
parent_decoder = parent->decoder_.get();
DCHECK(parent_decoder);
parent_context = parent_decoder->GetGLContext();
DCHECK(parent_context);
+
+ parent_handle = parent_context->GetHandle();
+ DCHECK(parent_handle);
}
// Create either a view or pbuffer based GLContext.
if (window) {
- scoped_ptr<ViewGLContext> context(new ViewGLContext(window));
+ DCHECK(!parent_handle);
+
// TODO(apatrick): support multisampling.
- if (!context->Initialize(false)) {
- Destroy();
- return false;
- }
- context_.reset(context.release());
+ context_.reset(GLContext::CreateViewGLContext(window, false));
} else {
- scoped_ptr<PbufferGLContext> context(new PbufferGLContext);
- if (!context->Initialize(parent_context)) {
- Destroy();
- return false;
- }
- context_.reset(context.release());
+ context_.reset(GLContext::CreateOffscreenGLContext(parent_handle));
}
- return InitializeCommon(size, parent_decoder, parent_texture_id);
+ if (!context_.get())
+ return false;
- return true;
+ return InitializeCommon(size, parent_decoder, parent_texture_id);
}
void GPUProcessor::Destroy() {
diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp
index a139cbc..5110762 100644
--- a/gpu/gpu.gyp
+++ b/gpu/gpu.gyp
@@ -43,7 +43,6 @@
['OS == "linux"',
{
'gpu_service_source_files': [
- 'command_buffer/service/gl_context_linux.cc',
'command_buffer/service/gpu_processor_linux.cc',
],
},
@@ -51,7 +50,6 @@
['OS == "win"',
{
'gpu_service_source_files': [
- 'command_buffer/service/gl_context_win.cc',
'command_buffer/service/gpu_processor_win.cc',
],
},
@@ -59,7 +57,6 @@
['OS == "mac"',
{
'gpu_service_source_files': [
- 'command_buffer/service/gl_context_mac.cc',
'command_buffer/service/gpu_processor_mac.cc',
],
},
@@ -284,13 +281,32 @@
],
'sources': [
'<@(gpu_service_source_files)',
+ 'command_buffer/service/gl_context_osmesa.cc',
+ 'command_buffer/service/gl_context_osmesa.h',
],
'conditions': [
['OS == "linux"',
{
'dependencies': [
'../build/linux/system.gyp:gtk',
- ]
+ ],
+ 'sources': [
+ 'command_buffer/service/gl_context_linux.cc',
+ ],
+ },
+ ],
+ ['OS == "win"',
+ {
+ 'sources': [
+ 'command_buffer/service/gl_context_win.cc',
+ ],
+ },
+ ],
+ ['OS == "mac"',
+ {
+ 'sources': [
+ 'command_buffer/service/gl_context_mac.cc',
+ ],
},
],
],
@@ -355,6 +371,7 @@
'command_buffer/service/common_decoder_unittest.cc',
'command_buffer/service/framebuffer_manager_unittest.cc',
'command_buffer/service/gpu_processor_unittest.cc',
+ 'command_buffer/service/gl_context_stub.cc',
'command_buffer/service/gl_interface.h',
'command_buffer/service/gl_interface.cc',
'command_buffer/service/gl_mock.h',