diff options
author | apatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-20 22:08:54 +0000 |
---|---|---|
committer | apatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-20 22:08:54 +0000 |
commit | 4bedba77d40df5fa5f1e00f5918123ee8711ca76 (patch) | |
tree | 0d34ff8aac44eaf1281fbcbdbe38867cb2a35f19 /gpu | |
parent | 163cf4a0682a5e32f9db5e413dab296f17027015 (diff) | |
download | chromium_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.h | 131 | ||||
-rw-r--r-- | gpu/command_buffer/service/gl_context_linux.cc | 175 | ||||
-rw-r--r-- | gpu/command_buffer/service/gl_context_mac.cc | 145 | ||||
-rw-r--r-- | gpu/command_buffer/service/gl_context_osmesa.cc | 106 | ||||
-rw-r--r-- | gpu/command_buffer/service/gl_context_osmesa.h | 58 | ||||
-rw-r--r-- | gpu/command_buffer/service/gl_context_stub.cc | 39 | ||||
-rw-r--r-- | gpu/command_buffer/service/gl_context_win.cc | 553 | ||||
-rw-r--r-- | gpu/command_buffer/service/gl_utils.h | 1 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder.cc | 66 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc | 4 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h | 2 | ||||
-rw-r--r-- | gpu/command_buffer/service/gpu_processor_linux.cc | 25 | ||||
-rw-r--r-- | gpu/command_buffer/service/gpu_processor_mac.cc | 16 | ||||
-rw-r--r-- | gpu/command_buffer/service/gpu_processor_win.cc | 25 | ||||
-rw-r--r-- | gpu/gpu.gyp | 25 |
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', |