diff options
author | apatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-09 21:16:02 +0000 |
---|---|---|
committer | apatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-09 21:16:02 +0000 |
commit | d37231fa18e0978822c6aa2c9d03e7a56e61810b (patch) | |
tree | 2765f8b09fe2f23a667cc1c0fb821d384a35dbd0 /gpu | |
parent | 7b70a92006d329a3e2df40ec6b61322212f75d95 (diff) | |
download | chromium_src-d37231fa18e0978822c6aa2c9d03e7a56e61810b.zip chromium_src-d37231fa18e0978822c6aa2c9d03e7a56e61810b.tar.gz chromium_src-d37231fa18e0978822c6aa2c9d03e7a56e61810b.tar.bz2 |
- Extracted platform specific code from GLES2 command decoder to platform specific GLContext classes.
- GLContext encapsulates management of GL contexts on each platform.
- ReadPixels uses actual current window size to validate source rectangle.
TEST=trybots, running Pepper 3D and WebGL demos on all platforms
BUG=none
Review URL: http://codereview.chromium.org/1605014
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@44129 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu')
25 files changed, 1381 insertions, 1117 deletions
diff --git a/gpu/command_buffer/client/gles2_demo.cc b/gpu/command_buffer/client/gles2_demo.cc index 6035042..3e9ea77 100644 --- a/gpu/command_buffer/client/gles2_demo.cc +++ b/gpu/command_buffer/client/gles2_demo.cc @@ -56,8 +56,8 @@ bool GLES2Demo::Setup(void* hwnd, int32 size) { GPUProcessor* gpu_processor = new GPUProcessor(command_buffer.get()); if (!gpu_processor->Initialize(reinterpret_cast<HWND>(hwnd), - NULL, gfx::Size(), + NULL, 0)) { return NULL; } diff --git a/gpu/command_buffer/service/cmd_parser.cc b/gpu/command_buffer/service/cmd_parser.cc index 804b894..191ddfa 100644 --- a/gpu/command_buffer/service/cmd_parser.cc +++ b/gpu/command_buffer/service/cmd_parser.cc @@ -4,7 +4,6 @@ // This file contains the implementation of the command parser. -#include "gpu/command_buffer/service/precompile.h" #include "gpu/command_buffer/service/cmd_parser.h" namespace gpu { diff --git a/gpu/command_buffer/service/cmd_parser_test.cc b/gpu/command_buffer/service/cmd_parser_test.cc index d46cf3b..0f2509e 100644 --- a/gpu/command_buffer/service/cmd_parser_test.cc +++ b/gpu/command_buffer/service/cmd_parser_test.cc @@ -4,8 +4,6 @@ // Tests for the command parser. -#include "gpu/command_buffer/service/precompile.h" - #include "base/scoped_ptr.h" #include "gpu/command_buffer/service/cmd_parser.h" #include "gpu/command_buffer/service/mocks.h" diff --git a/gpu/command_buffer/service/common_decoder.cc b/gpu/command_buffer/service/common_decoder.cc index feb59eb..c28c448 100644 --- a/gpu/command_buffer/service/common_decoder.cc +++ b/gpu/command_buffer/service/common_decoder.cc @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "gpu/command_buffer/service/precompile.h" #include "gpu/command_buffer/service/common_decoder.h" #include "gpu/command_buffer/service/cmd_buffer_engine.h" diff --git a/gpu/command_buffer/service/gl_context.cc b/gpu/command_buffer/service/gl_context.cc new file mode 100644 index 0000000..3602a07 --- /dev/null +++ b/gpu/command_buffer/service/gl_context.cc @@ -0,0 +1,81 @@ +// 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 "gpu/command_buffer/service/gl_context.h" +#include "gpu/command_buffer/service/gl_utils.h" +#include "gpu/command_buffer/common/logging.h" + +namespace gpu { + +GLContext::GLContext() { +} + +GLContext::~GLContext() { +} + +// GLEW initialization is extremely expensive because it looks up +// hundreds of function pointers. Realistically we are not going to +// switch between GL implementations on the fly, so for the time being +// we only do the context-dependent GLEW initialization once. +bool InitializeGLEW() { +#if defined(UNIT_TEST) + return true; +#else + static bool initialized = false; + if (initialized) + return true; + + // Initializes context-dependent parts of GLEW. + if (glewInit() != GLEW_OK) { + LOG(ERROR) << "GLEW failed initialization"; + return false; + } + + // Check to see that we can use the OpenGL vertex attribute APIs + // TODO(petersont): Return false if this check fails, but because some + // Intel hardware does not support OpenGL 2.0, yet does support all of the + // extensions we require, we only log an error. A future CL should change + // this check to ensure that all of the extension strings we require are + // present. + if (!GLEW_VERSION_2_0) { + DLOG(ERROR) << "GL drivers do not have OpenGL 2.0 functionality."; + } + + // Check for necessary extensions. + bool extensions_found = true; + if (!GLEW_ARB_vertex_buffer_object) { + // NOTE: Linux NVidia drivers claim to support OpenGL 2.0 when using + // indirect rendering (e.g. remote X), but it is actually lying. The + // ARB_vertex_buffer_object functions silently no-op (!) when using + // indirect rendering, leading to crashes. Fortunately, in that case, the + // driver claims to not support ARB_vertex_buffer_object, so fail in that + // case. + DLOG(ERROR) << "GL drivers do not support vertex buffer objects."; + extensions_found = false; + } + if (!GLEW_EXT_framebuffer_object) { + DLOG(ERROR) << "GL drivers do not support framebuffer objects."; + extensions_found = false; + } + if (!GLEW_VERSION_2_0 && !GLEW_EXT_stencil_two_side) { + DLOG(ERROR) << "Two sided stencil extension missing."; + extensions_found = false; + } + if (!GLEW_VERSION_1_4 && !GLEW_EXT_blend_func_separate) { + DLOG(ERROR) <<"Separate blend func extension missing."; + extensions_found = false; + } + if (!GLEW_VERSION_2_0 && !GLEW_EXT_blend_equation_separate) { + DLOG(ERROR) << "Separate blend function extension missing."; + extensions_found = false; + } + if (!extensions_found) + return false; + + initialized = true; + return true; +#endif +} + +} // namespace gpu diff --git a/gpu/command_buffer/service/gl_context.h b/gpu/command_buffer/service/gl_context.h new file mode 100644 index 0000000..832624db9 --- /dev/null +++ b/gpu/command_buffer/service/gl_context.h @@ -0,0 +1,169 @@ +// 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_H_ +#define GPU_COMMAND_BUFFER_SERVICE_GL_CONTEXT_H_ + +#include <build/build_config.h> + +#include "base/basictypes.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" + +class AcceleratedSurface; + +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. +class GLContext { + public: + GLContext(); + virtual ~GLContext(); + + // Destroys the GL context. + virtual void Destroy() = 0; + + // Makes the GL context current on the current thread. + virtual bool MakeCurrent() = 0; + + // Returns true if this context is offscreen. + virtual bool IsOffscreen() = 0; + + // Swaps front and back buffers. This has no effect for off-screen + // contexts. + virtual void SwapBuffers() = 0; + + // Get the size of the back buffer. + virtual gfx::Size GetSize() = 0; + + // Get the underlying platform specific GL context "handle". + virtual GLContextHandle GetHandle() = 0; + + 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) + ViewGLContext(Display* display, gfx::PluginWindowHandle window) + : display_(display), + window_(window), + context_(NULL) { + DCHECK(display); + DCHECK(window); + } +#elif defined(OS_MACOSX) + explicit ViewGLContext(AcceleratedSurface* surface) : surface_(surface) { + DCHECK(surface); + } +#endif + + // Initializes the GL context. + bool Initialize(bool multisampled); + + virtual void Destroy(); + virtual bool MakeCurrent(); + virtual bool IsOffscreen(); + virtual void SwapBuffers(); + virtual gfx::Size GetSize(); + virtual GLContextHandle GetHandle(); + + private: +#if defined(OS_WIN) + gfx::PluginWindowHandle window_; + HDC device_context_; + GLContextHandle context_; +#elif defined(OS_LINUX) + Display* display_; + gfx::PluginWindowHandle window_; + GLContextHandle context_; +#elif defined(OS_MACOSX) + AcceleratedSurface* surface_; +#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(Display* display) + : context_(NULL), + display_(display), + pbuffer_(NULL) { + DCHECK(display_); + } +#elif defined(OS_MACOSX) + PbufferGLContext() + : context_(NULL), + pbuffer_(NULL) { + } +#endif + + // Initializes the GL context. + bool Initialize(GLContext* shared_context); + + virtual void Destroy(); + virtual bool MakeCurrent(); + virtual bool IsOffscreen(); + virtual void SwapBuffers(); + virtual gfx::Size GetSize(); + virtual GLContextHandle GetHandle(); + + private: + GLContextHandle context_; +#if defined(OS_WIN) + HDC device_context_; + PbufferHandle pbuffer_; +#elif defined(OS_LINUX) + Display* display_; + PbufferHandle pbuffer_; +#elif defined(OS_MACOSX) + PbufferHandle pbuffer_; +#endif + DISALLOW_COPY_AND_ASSIGN(PbufferGLContext); +}; + +} // namespace gpu + +#endif // GPU_COMMAND_BUFFER_SERVICE_GL_CONTEXT_H_ diff --git a/gpu/command_buffer/service/x_utils.cc b/gpu/command_buffer/service/gl_context_linux.cc index 30a9167..0acbb02 100644 --- a/gpu/command_buffer/service/x_utils.cc +++ b/gpu/command_buffer/service/gl_context_linux.cc @@ -1,18 +1,24 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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 class implements the XWindowWrapper class. +// This file implements the ViewGLContext and PbufferGLContext classes. +#if !defined(UNIT_TEST) #include <dlfcn.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#endif +#include "gpu/command_buffer/service/gl_context.h" #include "base/scoped_ptr.h" -#include "gpu/command_buffer/service/precompile.h" +#include "gpu/command_buffer/service/gl_utils.h" #include "gpu/command_buffer/common/logging.h" -#include "gpu/command_buffer/service/x_utils.h" namespace gpu { +#if !defined(UNIT_TEST) + // scoped_ptr functor for XFree(). Use as follows: // scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> foo(...); // where "XVisualInfo" is any X type that is freed with XFree. @@ -28,11 +34,9 @@ class ScopedPtrXFree { // load it, and use glew to dynamically resolve symbols. // See http://code.google.com/p/chromium/issues/detail?id=16800 -static bool g_glxew_initialized = false; -static bool g_glew_initialized = false; - static bool InitializeGLXEW(Display* display) { - if (!g_glxew_initialized) { + static bool glxew_initialized = false; + if (!glxew_initialized) { void* handle = dlopen("libGL.so.1", RTLD_LAZY | RTLD_GLOBAL); if (!handle) { LOG(ERROR) << "Could not find libGL.so.1"; @@ -52,36 +56,45 @@ static bool InitializeGLXEW(Display* display) { LOG(ERROR) << "glxewContextInit failed"; return false; } - g_glxew_initialized = true; + glxew_initialized = true; } + return true; } -// GLEW initialization is extremely expensive because it looks up -// hundreds of function pointers. Realistically we are not going to -// switch between GL implementations on the fly, so for the time being -// we only do the context-dependent GLEW initialization once. -static bool InitializeGLEW() { - if (!g_glew_initialized) { - // Initializes context-dependent parts of GLEW - if (glewInit() != GLEW_OK) { - LOG(ERROR) << "GLEW failed initialization"; - return false; - } +#endif // UNIT_TEST - if (!glewIsSupported("GL_VERSION_2_0")) { - LOG(ERROR) << "GL implementation doesn't support GL version 2.0"; - return false; - } - g_glew_initialized = true; +bool ViewGLContext::Initialize(bool multisampled) { +#if !defined(UNIT_TEST) + if (multisampled) { + DLOG(WARNING) << "Multisampling not implemented."; } - return true; -} -GLXContextWrapper::~GLXContextWrapper() { -} + if (!InitializeGLXEW(display_)) + return false; + + XWindowAttributes attributes; + XGetWindowAttributes(display_, window_, &attributes); + XVisualInfo visual_info_template; + visual_info_template.visualid = XVisualIDFromVisual(attributes.visual); + int visual_info_count = 0; + scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info_list( + XGetVisualInfo(display_, VisualIDMask, + &visual_info_template, + &visual_info_count)); + DCHECK(visual_info_list.get()); + DCHECK_GT(visual_info_count, 0); + context_ = NULL; + for (int i = 0; i < visual_info_count; ++i) { + context_ = glXCreateContext(display_, visual_info_list.get() + i, 0, True); + if (context_) + break; + } + if (!context_) { + DLOG(ERROR) << "Couldn't create GL context."; + return false; + } -bool GLXContextWrapper::Initialize() { if (!MakeCurrent()) { Destroy(); DLOG(ERROR) << "Couldn't make context current for initialization."; @@ -92,75 +105,73 @@ bool GLXContextWrapper::Initialize() { Destroy(); return false; } +#endif // UNIT_TEST return true; } -void GLXContextWrapper::Destroy() { - Bool result = glXMakeCurrent(GetDisplay(), 0, 0); +void ViewGLContext::Destroy() { + #if !defined(UNIT_TEST) +Bool result = glXMakeCurrent(display_, 0, 0); // glXMakeCurrent isn't supposed to fail when unsetting the context, unless // we have pending draws on an invalid window - which shouldn't be the case // here. DCHECK(result); - if (GetContext()) { - glXDestroyContext(GetDisplay(), GetContext()); - SetContext(NULL); + if (context_) { + glXDestroyContext(display_, context_); + context_ = NULL; } +#endif // UNIT_TEST } -bool XWindowWrapper::Initialize() { - if (!InitializeGLXEW(GetDisplay())) - return false; - - XWindowAttributes attributes; - XGetWindowAttributes(GetDisplay(), window_, &attributes); - XVisualInfo visual_info_template; - visual_info_template.visualid = XVisualIDFromVisual(attributes.visual); - int visual_info_count = 0; - scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info_list( - XGetVisualInfo(GetDisplay(), VisualIDMask, - &visual_info_template, - &visual_info_count)); - DCHECK(visual_info_list.get()); - DCHECK_GT(visual_info_count, 0); - SetContext(NULL); - for (int i = 0; i < visual_info_count; ++i) { - SetContext(glXCreateContext(GetDisplay(), visual_info_list.get() + i, 0, - True)); - if (GetContext()) - break; - } - if (!GetContext()) { - DLOG(ERROR) << "Couldn't create GL context."; - return false; - } - return GLXContextWrapper::Initialize(); -} - -bool XWindowWrapper::MakeCurrent() { +bool ViewGLContext::MakeCurrent() { +#if !defined(UNIT_TEST) if (glXGetCurrentDrawable() == window_ && - glXGetCurrentContext() == GetContext()) { + glXGetCurrentContext() == context_) { return true; } - if (glXMakeCurrent(GetDisplay(), window_, GetContext()) != True) { - glXDestroyContext(GetDisplay(), GetContext()); - SetContext(0); + if (glXMakeCurrent(display_, window_, context_) != True) { + glXDestroyContext(display_, context_); + context_ = 0; DLOG(ERROR) << "Couldn't make context current."; return false; } +#endif // UNIT_TEST + return true; } -bool XWindowWrapper::IsOffscreen() { +bool ViewGLContext::IsOffscreen() { return false; } -void XWindowWrapper::SwapBuffers() { - glXSwapBuffers(GetDisplay(), window_); +void ViewGLContext::SwapBuffers() { +#if !defined(UNIT_TEST) + glXSwapBuffers(display_, window_); +#endif // UNIT_TEST } -bool GLXPbufferWrapper::Initialize() { - if (!InitializeGLXEW(GetDisplay())) +gfx::Size ViewGLContext::GetSize() { +#if !defined(UNIT_TEST) + XWindowAttributes attributes; + 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) + return context_; +#else + return NULL; +#endif // UNIT_TEST +} + +bool PbufferGLContext::Initialize(GLContext* shared_context) { +#if !defined(UNIT_TEST) + if (!InitializeGLXEW(display_)) return false; if (!glXChooseFBConfig || @@ -171,6 +182,11 @@ bool GLXPbufferWrapper::Initialize() { return false; } + // Get the shared context handle. + GLContextHandle shared_handle = NULL; + if (shared_context) + shared_handle = shared_context->GetHandle(); + static const int config_attributes[] = { GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT, @@ -184,7 +200,7 @@ bool GLXPbufferWrapper::Initialize() { int nelements = 0; // TODO(kbr): figure out whether hardcoding screen to 0 is sufficient. scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> config( - glXChooseFBConfig(GetDisplay(), 0, config_attributes, &nelements)); + glXChooseFBConfig(display_, 0, config_attributes, &nelements)); if (!config.get()) { DLOG(ERROR) << "glXChooseFBConfig failed."; return false; @@ -193,9 +209,12 @@ bool GLXPbufferWrapper::Initialize() { DLOG(ERROR) << "glXChooseFBConfig returned 0 elements."; return false; } - SetContext(glXCreateNewContext(GetDisplay(), - config.get()[0], GLX_RGBA_TYPE, 0, True)); - if (!GetContext()) { + context_ = glXCreateNewContext(display_, + config.get()[0], + GLX_RGBA_TYPE, + shared_handle, + True); + if (!context_) { DLOG(ERROR) << "glXCreateNewContext failed."; return false; } @@ -206,43 +225,84 @@ bool GLXPbufferWrapper::Initialize() { 1, 0 }; - pbuffer_ = glXCreatePbuffer(GetDisplay(), + pbuffer_ = glXCreatePbuffer(display_, config.get()[0], pbuffer_attributes); if (!pbuffer_) { Destroy(); DLOG(ERROR) << "glXCreatePbuffer failed."; return false; } - return GLXContextWrapper::Initialize(); + + if (!MakeCurrent()) { + Destroy(); + DLOG(ERROR) << "Couldn't make context current for initialization."; + return false; + } + + if (!InitializeGLEW()) { + Destroy(); + return false; + } +#endif // UNIT_TEST + + return true; } -void GLXPbufferWrapper::Destroy() { - GLXContextWrapper::Destroy(); +void PbufferGLContext::Destroy() { +#if !defined(UNIT_TEST) + Bool result = glXMakeCurrent(display_, 0, 0); + // glXMakeCurrent isn't supposed to fail when unsetting the context, unless + // we have pending draws on an invalid window - which shouldn't be the case + // here. + DCHECK(result); + if (context_) { + glXDestroyContext(display_, context_); + context_ = NULL; + } + if (pbuffer_) { - glXDestroyPbuffer(GetDisplay(), pbuffer_); + glXDestroyPbuffer(display_, pbuffer_); pbuffer_ = NULL; } +#endif // UNIT_TEST } -bool GLXPbufferWrapper::MakeCurrent() { +bool PbufferGLContext::MakeCurrent() { +#if !defined(UNIT_TEST) if (glXGetCurrentDrawable() == pbuffer_ && - glXGetCurrentContext() == GetContext()) { + glXGetCurrentContext() == context_) { return true; } - if (glXMakeCurrent(GetDisplay(), pbuffer_, GetContext()) != True) { - glXDestroyContext(GetDisplay(), GetContext()); - SetContext(0); + if (glXMakeCurrent(display_, pbuffer_, context_) != True) { + glXDestroyContext(display_, context_); + context_ = NULL; DLOG(ERROR) << "Couldn't make context current."; return false; } +#endif // UNIT_TEST + return true; } -bool GLXPbufferWrapper::IsOffscreen() { +bool PbufferGLContext::IsOffscreen() { return true; } -void GLXPbufferWrapper::SwapBuffers() { +void PbufferGLContext::SwapBuffers() { + NOTREACHED() << "Attempted to call SwapBuffers on a pbuffer."; +} + +gfx::Size PbufferGLContext::GetSize() { + NOTREACHED() << "Should not be requesting size of this pbuffer."; + return gfx::Size(1, 1); +} + +GLContextHandle PbufferGLContext::GetHandle() { +#if !defined(UNIT_TEST) + return context_; +#else + return NULL; +#endif // UNIT_TEST } } // namespace gpu diff --git a/gpu/command_buffer/service/gl_context_mac.cc b/gpu/command_buffer/service/gl_context_mac.cc new file mode 100644 index 0000000..9e79a69 --- /dev/null +++ b/gpu/command_buffer/service/gl_context_mac.cc @@ -0,0 +1,191 @@ +// 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 ViewGLContext and PbufferGLContext classes. + +#include "gpu/command_buffer/service/gl_context.h" +#include "gpu/command_buffer/common/logging.h" + +#if !defined(UNIT_TEST) +#include "app/surface/accelerated_surface_mac.h" +#endif + +namespace gpu { + +bool ViewGLContext::Initialize(bool multisampled) { +#if !defined(UNIT_TEST) + if (multisampled) { + DLOG(WARNING) << "Multisampling not implemented."; + } + + if (!surface_->Initialize()) { + DLOG(ERROR) << "Error initializing accelerated surface."; + return false; + } + + if (!MakeCurrent()) { + Destroy(); + DLOG(ERROR) << "Couldn't make context current for initialization."; + return false; + } + + if (!InitializeGLEW()) { + Destroy(); + return false; + } + + return true; +#else + return true; +#endif // UNIT_TEST +} + +void ViewGLContext::Destroy() { +#if !defined(UNIT_TEST) + surface_->Destroy(); +#endif // UNIT_TEST +} + +bool ViewGLContext::MakeCurrent() { +#if !defined(UNIT_TEST) + return surface_->MakeCurrent(); +#else + return true; +#endif +} + +bool ViewGLContext::IsOffscreen() { + return false; +} + +void ViewGLContext::SwapBuffers() { +#if !defined(UNIT_TEST) + surface_->SwapBuffers(); +#endif // UNIT_TEST +} + +gfx::Size ViewGLContext::GetSize() { +#if !defined(UNIT_TEST) + return surface_->GetSize(); +#else + return gfx::Size(); +#endif // UNIT_TEST +} + +GLContextHandle ViewGLContext::GetHandle() { +#if !defined(UNIT_TEST) + return surface_->context(); +#else + return NULL; +#endif // UNIT_TEST +} + +bool PbufferGLContext::Initialize(GLContext* shared_context) { +#if !defined(UNIT_TEST) + // Get the shared context handle. + GLContextHandle shared_handle = NULL; + if (shared_context) + shared_handle = shared_context->GetHandle(); + + // Create a 1x1 pbuffer and associated context to bootstrap things. + static const CGLPixelFormatAttribute attribs[] = { + (CGLPixelFormatAttribute) kCGLPFAPBuffer, + (CGLPixelFormatAttribute) 0 + }; + CGLPixelFormatObj pixel_format; + GLint num_pixel_formats; + if (CGLChoosePixelFormat(attribs, + &pixel_format, + &num_pixel_formats) != kCGLNoError) { + DLOG(ERROR) << "Error choosing pixel format."; + Destroy(); + return false; + } + if (!pixel_format) { + return false; + } + CGLError res = CGLCreateContext(pixel_format, shared_handle, &context_); + CGLDestroyPixelFormat(pixel_format); + if (res != kCGLNoError) { + DLOG(ERROR) << "Error creating context."; + Destroy(); + return false; + } + if (CGLCreatePBuffer(1, 1, + GL_TEXTURE_2D, GL_RGBA, + 0, &pbuffer_) != kCGLNoError) { + DLOG(ERROR) << "Error creating pbuffer."; + Destroy(); + return false; + } + if (CGLSetPBuffer(context_, pbuffer_, 0, 0, 0) != kCGLNoError) { + DLOG(ERROR) << "Error attaching pbuffer to context."; + Destroy(); + return false; + } + + if (!MakeCurrent()) { + Destroy(); + DLOG(ERROR) << "Couldn't make context current for initialization."; + return false; + } + + if (!InitializeGLEW()) { + Destroy(); + return false; + } +#endif // UNIT_TEST + + return true; +} + +void PbufferGLContext::Destroy() { +#if !defined(UNIT_TEST) + if (context_) { + CGLDestroyContext(context_); + context_ = NULL; + } + + if (pbuffer_) { + CGLDestroyPBuffer(pbuffer_); + pbuffer_ = NULL; + } +#endif // UNIT_TEST +} + +bool PbufferGLContext::MakeCurrent() { +#if !defined(UNIT_TEST) + if (CGLGetCurrentContext() != context_) { + if (CGLSetCurrentContext(context_) != kCGLNoError) { + DLOG(ERROR) << "Unable to make gl context current."; + return false; + } + } +#endif // UNIT_TEST + + return true; +} + +bool PbufferGLContext::IsOffscreen() { + return true; +} + +void PbufferGLContext::SwapBuffers() { + NOTREACHED() << "Cannot call SwapBuffers on a PbufferGLContext."; +} + +gfx::Size PbufferGLContext::GetSize() { + NOTREACHED() << "Should not be requesting size of a PbufferGLContext."; + return gfx::Size(1, 1); +} + +GLContextHandle PbufferGLContext::GetHandle() { +#if !defined(UNIT_TEST) + return context_; +#else + return NULL; +#endif // UNIT_TEST +} + +} // namespace gpu diff --git a/gpu/command_buffer/service/gl_context_win.cc b/gpu/command_buffer/service/gl_context_win.cc new file mode 100644 index 0000000..3be106a --- /dev/null +++ b/gpu/command_buffer/service/gl_context_win.cc @@ -0,0 +1,376 @@ +// 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 ViewGLContext and PbufferGLContext classes. + +#include "gpu/command_buffer/service/gl_context.h" +#include "gpu/command_buffer/common/logging.h" + +namespace gpu { + +#if !defined(UNIT_TEST) + +static int g_regular_pixel_format = 0; +static int g_multisampled_pixel_format = 0; + +const PIXELFORMATDESCRIPTOR kPixelFormatDescriptor = { + sizeof(kPixelFormatDescriptor), // Size of structure. + 1, // Default version. + PFD_DRAW_TO_WINDOW | // Window drawing support. + PFD_SUPPORT_OPENGL | // OpenGL support. + PFD_DOUBLEBUFFER, // Double buffering support (not stereo). + PFD_TYPE_RGBA, // RGBA color mode (not indexed). + 24, // 24 bit color mode. + 0, 0, 0, 0, 0, 0, // Don't set RGB bits & shifts. + 8, 0, // 8 bit alpha + 0, // No accumulation buffer. + 0, 0, 0, 0, // Ignore accumulation bits. + 24, // 24 bit z-buffer size. + 8, // 8-bit stencil buffer. + 0, // No aux buffer. + PFD_MAIN_PLANE, // Main drawing plane (not overlay). + 0, // Reserved. + 0, 0, 0, // Layer masks ignored. +}; + +LRESULT CALLBACK IntermediateWindowProc(HWND window, + UINT message, + WPARAM w_param, + LPARAM l_param) { + return ::DefWindowProc(window, message, w_param, l_param); +} + +#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; + } + + HWND intermediate_window = ::CreateWindow( + reinterpret_cast<wchar_t*>(class_registration), + L"", + WS_OVERLAPPEDWINDOW, + 0, 0, + CW_USEDEFAULT, CW_USEDEFAULT, + NULL, + NULL, + NULL, + NULL); + + if (!intermediate_window) { + ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration), + module_handle); + return false; + } + + HDC intermediate_dc = ::GetDC(intermediate_window); + 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; + } + + // 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); + + initialized = true; +#endif // UNIT_TEST + + return true; +} + +bool ViewGLContext::Initialize(bool multisampled) { +#if !defined(UNIT_TEST) + InitializeOneOff(); + + // The GL context will render to this window. + device_context_ = GetDC(window_); + + int pixel_format = + multisampled ? g_multisampled_pixel_format : g_regular_pixel_format; + if (!SetPixelFormat(device_context_, + pixel_format, + &kPixelFormatDescriptor)) { + DLOG(ERROR) << "Unable to set the pixel format for GL context."; + Destroy(); + return false; + } + + context_ = wglCreateContext(device_context_); + if (!context_) { + DLOG(ERROR) << "Failed to create GL context."; + Destroy(); + return false; + } +#endif // UNIT_TEST + + return true; +} + +void ViewGLContext::Destroy() { +#if !defined(UNIT_TEST) + if (context_) { + wglDeleteContext(context_); + context_ = NULL; + } + + if (window_ && device_context_) + ReleaseDC(window_, device_context_); + + window_ = NULL; + device_context_ = NULL; +#endif // UNIT_TEST +} + +bool ViewGLContext::MakeCurrent() { +#if !defined(UNIT_TEST) + if (wglGetCurrentDC() == device_context_ && + wglGetCurrentContext() == context_) { + return true; + } + if (!wglMakeCurrent(device_context_, context_)) { + DLOG(ERROR) << "Unable to make gl context current."; + return false; + } +#endif // UNIT_TEST + + return true; +} + +bool ViewGLContext::IsOffscreen() { + return false; +} + +void ViewGLContext::SwapBuffers() { +#if !defined(UNIT_TEST) + DCHECK(device_context_); + ::SwapBuffers(device_context_); +#endif // UNIT_TEST +} + +gfx::Size ViewGLContext::GetSize() { +#if !defined(UNIT_TEST) + 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) + return context_; +#else + return NULL; +#endif // UNIT_TEST +} + +bool PbufferGLContext::Initialize(GLContext* shared_context) { +#if !defined(UNIT_TEST) + InitializeOneOff(); + + // Create a device context compatible with the primary display. + HDC display_device_context = ::CreateDC(L"DISPLAY", NULL, NULL, NULL); + + // Create a 1 x 1 pbuffer suitable for use with the device. This is just + // a stepping stone towards creating a frame buffer object. It doesn't + // matter what size it is. + const int kNoAttributes[] = { 0 }; + pbuffer_ = ::wglCreatePbufferARB(display_device_context, + g_regular_pixel_format, + 1, 1, + kNoAttributes); + ::DeleteDC(display_device_context); + if (!pbuffer_) { + DLOG(ERROR) << "Unable to create pbuffer."; + Destroy(); + return false; + } + + device_context_ = ::wglGetPbufferDCARB(pbuffer_); + if (!device_context_) { + DLOG(ERROR) << "Unable to get pbuffer device context."; + Destroy(); + return false; + } + + context_ = ::wglCreateContext(device_context_); + if (!context_) { + DLOG(ERROR) << "Failed to create GL context."; + Destroy(); + return false; + } + + if (shared_context) { + if (!wglShareLists(shared_context->GetHandle(), context_)) { + DLOG(ERROR) << "Could not share GL contexts."; + Destroy(); + return false; + } + } +#endif // UNIT_TEST + + return true; +} + +void PbufferGLContext::Destroy() { +#if !defined(UNIT_TEST) + if (context_) { + wglDeleteContext(context_); + context_ = NULL; + } + + if (pbuffer_ && device_context_) + wglReleasePbufferDCARB(pbuffer_, device_context_); + + device_context_ = NULL; + + if (pbuffer_) { + wglDestroyPbufferARB(pbuffer_); + pbuffer_ = NULL; + } +#endif // UNIT_TEST +} + +bool PbufferGLContext::MakeCurrent() { +#if !defined(UNIT_TEST) + if (wglGetCurrentDC() == device_context_ && + wglGetCurrentContext() == context_) { + return true; + } + if (!wglMakeCurrent(device_context_, context_)) { + DLOG(ERROR) << "Unable to make gl context current."; + return false; + } +#endif // UNIT_TEST + + return true; +} + +bool PbufferGLContext::IsOffscreen() { + return true; +} + +void PbufferGLContext::SwapBuffers() { + NOTREACHED() << "Attempted to call SwapBuffers on a pbuffer."; +} + +gfx::Size PbufferGLContext::GetSize() { + NOTREACHED() << "Should not be requesting size of this pbuffer."; + return gfx::Size(1, 1); +} + +GLContextHandle PbufferGLContext::GetHandle() { +#if !defined(UNIT_TEST) + return context_; +#else + return NULL; +#endif // UNIT_TEST +} + +} // namespace gpu diff --git a/gpu/command_buffer/service/gl_utils.h b/gpu/command_buffer/service/gl_utils.h index 943681c..c5a3c98 100644 --- a/gpu/command_buffer/service/gl_utils.h +++ b/gpu/command_buffer/service/gl_utils.h @@ -53,8 +53,12 @@ #include <GL/glew.h> // NOLINT #if defined(OS_WIN) #include <GL/wglew.h> // NOLINT + #include <windows.h> // NOLINT #elif defined(OS_LINUX) #include <GL/glxew.h> // NOLINT + #include <GL/glx.h> // NOLINT + #elif defined(OS_MACOSX) + #include <OpenGL/OpenGL.h> // NOLINT #endif // OS_WIN // GLES2 defines not part of Desktop GL diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 32308a5..4f70ecf 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -10,11 +10,11 @@ #include <vector> #include <string> #include <map> -#include <build/build_config.h> // NOLINT #include "base/callback.h" #include "base/linked_ptr.h" #include "base/scoped_ptr.h" #include "base/weak_ptr.h" +#include "build/build_config.h" #define GLES2_GPU_SERVICE 1 #include "gpu/command_buffer/common/gles2_cmd_format.h" #include "gpu/command_buffer/common/gles2_cmd_utils.h" @@ -22,6 +22,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_utils.h" #include "gpu/command_buffer/service/gles2_cmd_validation.h" #include "gpu/command_buffer/service/id_manager.h" @@ -29,13 +30,6 @@ #include "gpu/command_buffer/service/renderbuffer_manager.h" #include "gpu/command_buffer/service/shader_manager.h" #include "gpu/command_buffer/service/texture_manager.h" -#if defined(UNIT_TEST) -#elif defined(OS_LINUX) -// GLXContextWrapper is stubbed out for unit-tests. -#include "gpu/command_buffer/service/x_utils.h" -#elif defined(OS_MACOSX) -#include "app/surface/accelerated_surface_mac.h" -#endif #if !defined(GL_DEPTH24_STENCIL8) #define GL_DEPTH24_STENCIL8 0x88F0 @@ -185,9 +179,14 @@ class Texture { return id_; } + gfx::Size size() const { + return size_; + } + private: GLES2DecoderImpl* decoder_; GLuint id_; + gfx::Size size_; DISALLOW_COPY_AND_ASSIGN(Texture); }; @@ -256,17 +255,7 @@ class FrameBuffer { GLES2Decoder::GLES2Decoder(ContextGroup* group) : group_(group), -#if defined(UNIT_TEST) debug_(false) { -#elif defined(OS_LINUX) - debug_(false), - context_(NULL) { -#elif defined(OS_WIN) - debug_(false), - hwnd_(NULL) { -#else - debug_(false) { -#endif } GLES2Decoder::~GLES2Decoder() { @@ -356,34 +345,16 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, virtual const char* GetCommandName(unsigned int command_id) const; // Overridden from GLES2Decoder. - virtual bool Initialize(GLES2Decoder* parent, + virtual bool Initialize(GLContext* context, const gfx::Size& size, + GLES2Decoder* parent, uint32 parent_client_texture_id); virtual void Destroy(); virtual void ResizeOffscreenFrameBuffer(const gfx::Size& size); virtual bool MakeCurrent(); virtual uint32 GetServiceIdForTesting(uint32 client_id); virtual GLES2Util* GetGLES2Util() { return &util_; } - -#if defined(OS_MACOSX) - // Overridden from GLES2Decoder. - - // The recommended usage is to call SetWindowSizeForIOSurface() first, and if - // that returns 0, try calling SetWindowSizeForTransportDIB(). A return value - // of 0 from SetWindowSizeForIOSurface() might mean the IOSurface API is not - // available, which is true if you are not running on Max OS X 10.6 or later. - // If SetWindowSizeForTransportDIB() also returns a NULL handle, then an - // error has occured. - virtual uint64 SetWindowSizeForIOSurface(int32 width, int32 height); - virtual TransportDIB::Handle SetWindowSizeForTransportDIB(int32 width, - int32 height); - // |allocator| sends a message to the renderer asking for a new - // TransportDIB big enough to hold the rendered bits. The parameters to the - // call back are the size of the DIB and the handle (filled in on return). - virtual void SetTransportDIBAllocAndFree( - Callback2<size_t, TransportDIB::Handle*>::Type* allocator, - Callback1<TransportDIB::Id>::Type* deallocator); -#endif + virtual GLContext* GetGLContext() { return context_; } virtual void SetSwapBuffersCallback(Callback0::Type* callback); @@ -456,15 +427,6 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, return group_->texture_manager(); } -#if defined(OS_WIN) - static bool InitializeOneOff(bool anti_aliased); -#endif - - - bool InitPlatformSpecific(); - static bool InitGlew(); - void DestroyPlatformSpecific(); - bool UpdateOffscreenFrameBufferSize(); // Template to help call glGenXXX functions. @@ -517,6 +479,10 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, texture_manager()->RemoveTextureInfo(texture); } + // Get the size (in pixels) of the currently bound frame buffer (either FBO + // or regular back buffer). + gfx::Size GetBoundFrameBufferSize(); + // Wrapper for CompressedTexImage2D commands. error::Error DoCompressedTexImage2D( GLenum target, @@ -813,16 +779,16 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, #undef GLES2_CMD_OP + // The GL context this decoder renders to. + GLContext* context_; + // A parent decoder can access this decoders saved offscreen frame buffer. // The parent pointer is reset if the parent is destroyed. base::WeakPtr<GLES2DecoderImpl> parent_; // Width and height to which an offscreen frame buffer should be resized on // the next call to SwapBuffers. - gfx::Size pending_size_; - - // Width and height of a decoder that renders to an offscreen frame buffer. - gfx::Size current_size_; + gfx::Size pending_offscreen_size_; // Current GL error bits. uint32 error_bits_; @@ -871,19 +837,6 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, // The currently bound renderbuffer GLuint bound_renderbuffer_; -#if defined(UNIT_TEST) -#elif defined(GLES2_GPU_SERVICE_BACKEND_NATIVE_GLES2) -#elif defined(OS_WIN) - static int pixel_format_; - HDC gl_device_context_; - HGLRC gl_context_; - HPBUFFERARB pbuffer_; -#elif defined(OS_MACOSX) - CGLContextObj gl_context_; - CGLPBufferObj pbuffer_; - AcceleratedSurface surface_; -#endif - bool anti_aliased_; // The offscreen frame buffer that the client renders to. @@ -1006,6 +959,8 @@ bool Texture::AllocateStorage(const gfx::Size& size) { GL_UNSIGNED_BYTE, NULL); + size_ = size; + return glGetError() == GL_NO_ERROR; } @@ -1136,14 +1091,9 @@ GLES2Decoder* GLES2Decoder::Create(ContextGroup* group) { return new GLES2DecoderImpl(group); } -#if defined(UNIT_TEST) -#elif defined(GLES2_GPU_SERVICE_BACKEND_NATIVE_GLES2) -#elif defined(OS_WIN) -int GLES2DecoderImpl::pixel_format_; -#endif - GLES2DecoderImpl::GLES2DecoderImpl(ContextGroup* group) : GLES2Decoder(group), + context_(NULL), error_bits_(0), util_(0), // TODO(gman): Set to actual num compress texture formats. pack_alignment_(4), @@ -1153,48 +1103,26 @@ GLES2DecoderImpl::GLES2DecoderImpl(ContextGroup* group) black_cube_texture_id_(0), bound_framebuffer_(0), bound_renderbuffer_(0), -#if defined(UNIT_TEST) -#elif defined(GLES2_GPU_SERVICE_BACKEND_NATIVE_GLES2) -#elif defined(OS_WIN) - gl_device_context_(NULL), - gl_context_(NULL), - pbuffer_(NULL), -#elif defined(OS_MAC) - gl_context_(NULL), - pbuffer_(NULL), -#endif anti_aliased_(false) { } -bool GLES2DecoderImpl::Initialize(GLES2Decoder* parent, +bool GLES2DecoderImpl::Initialize(GLContext* context, const gfx::Size& size, + GLES2Decoder* parent, uint32 parent_client_texture_id) { + DCHECK(!context_); + context_ = context; + // Keep only a weak pointer to the parent so we don't unmap its client - // frame buffer is after it has been destroyed. + // frame buffer after it has been destroyed. if (parent) parent_ = static_cast<GLES2DecoderImpl*>(parent)->AsWeakPtr(); - pending_size_ = size; - - if (!InitPlatformSpecific()) { - Destroy(); - return false; - } - if (!MakeCurrent()) { Destroy(); return false; } - // This happens in InitializeOneOff in windows. TODO(apatrick): generalize to - // other platforms. -#if !defined(OS_WIN) - if (!InitGlew()) { - Destroy(); - return false; - } -#endif - CHECK_GL_ERROR(); if (!group_->Initialize()) { @@ -1232,7 +1160,8 @@ bool GLES2DecoderImpl::Initialize(GLES2Decoder* parent, glBindTexture(GL_TEXTURE_CUBE_MAP, 0); CHECK_GL_ERROR(); - if (size.width() > 0 && size.height() > 0) { +#if !defined(UNIT_TEST) + if (context_->IsOffscreen()) { // Create the target frame buffer. This is the one that the client renders // directly to. offscreen_target_frame_buffer_.reset(new FrameBuffer(this)); @@ -1267,6 +1196,7 @@ bool GLES2DecoderImpl::Initialize(GLES2Decoder* parent, // Allocate the render buffers at their initial size and check the status // of the frame buffers is okay. + pending_offscreen_size_ = size; if (!UpdateOffscreenFrameBufferSize()) { DLOG(ERROR) << "Could not allocate offscreen buffer storage."; Destroy(); @@ -1277,6 +1207,7 @@ bool GLES2DecoderImpl::Initialize(GLES2Decoder* parent, // This should now be associated with ID zero. DoBindFramebuffer(GL_FRAMEBUFFER, 0); } +#endif // UNIT_TEST #if !defined(GLES2_GPU_SERVICE_BACKEND_NATIVE_GLES2) // OpenGL ES 2.0 implicitly enables the desktop GL capability @@ -1289,176 +1220,6 @@ bool GLES2DecoderImpl::Initialize(GLES2Decoder* parent, return true; } -// TODO(kbr): the use of this anonymous namespace core dumps the -// linker on Mac OS X 10.6 when the symbol ordering file is used -// namespace { - -#if defined(UNIT_TEST) -#elif defined(GLES2_GPU_SERVICE_BACKEND_NATIVE_GLES2) -#elif defined(OS_WIN) - -const PIXELFORMATDESCRIPTOR kPixelFormatDescriptor = { - sizeof(kPixelFormatDescriptor), // Size of structure. - 1, // Default version. - PFD_DRAW_TO_WINDOW | // Window drawing support. - PFD_SUPPORT_OPENGL | // OpenGL support. - PFD_DOUBLEBUFFER, // Double buffering support (not stereo). - PFD_TYPE_RGBA, // RGBA color mode (not indexed). - 24, // 24 bit color mode. - 0, 0, 0, 0, 0, 0, // Don't set RGB bits & shifts. - 8, 0, // 8 bit alpha - 0, // No accumulation buffer. - 0, 0, 0, 0, // Ignore accumulation bits. - 24, // 24 bit z-buffer size. - 8, // 8-bit stencil buffer. - 0, // No aux buffer. - PFD_MAIN_PLANE, // Main drawing plane (not overlay). - 0, // Reserved. - 0, 0, 0, // Layer masks ignored. -}; - -LRESULT CALLBACK IntermediateWindowProc(HWND window, - UINT message, - WPARAM w_param, - LPARAM l_param) { - return ::DefWindowProc(window, message, w_param, l_param); -} - -// Helper routine that does one-off initialization like determining the -// pixel format and initializing glew. -bool GLES2DecoderImpl::InitializeOneOff(bool anti_aliased) { - // We must initialize a GL context before we can determine the multi-sampling - // supported on the current hardware, so we create an intermediate window - // and context here. - HINSTANCE module_handle; - if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | - GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, - reinterpret_cast<wchar_t*>(IntermediateWindowProc), - &module_handle)) { - return false; - } - - WNDCLASS intermediate_class; - intermediate_class.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; - intermediate_class.lpfnWndProc = IntermediateWindowProc; - intermediate_class.cbClsExtra = 0; - intermediate_class.cbWndExtra = 0; - intermediate_class.hInstance = module_handle; - intermediate_class.hIcon = LoadIcon(NULL, IDI_APPLICATION); - intermediate_class.hCursor = LoadCursor(NULL, IDC_ARROW); - intermediate_class.hbrBackground = NULL; - intermediate_class.lpszMenuName = NULL; - intermediate_class.lpszClassName = L"Intermediate GL Window"; - - ATOM class_registration = ::RegisterClass(&intermediate_class); - if (!class_registration) { - return false; - } - - HWND intermediate_window = ::CreateWindow( - reinterpret_cast<wchar_t*>(class_registration), - L"", - WS_OVERLAPPEDWINDOW, - 0, 0, - CW_USEDEFAULT, CW_USEDEFAULT, - NULL, - NULL, - NULL, - NULL); - - if (!intermediate_window) { - ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration), - module_handle); - return false; - } - - HDC intermediate_dc = ::GetDC(intermediate_window); - pixel_format_ = ::ChoosePixelFormat(intermediate_dc, - &kPixelFormatDescriptor); - if (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, 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; - } - - // 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 (InitGlew()) { - 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 (anti_aliased && WGLEW_ARB_pixel_format && WGLEW_ARB_multisample) { - int pixel_attributes[] = { - WGL_SAMPLES_ARB, 4, - WGL_DRAW_TO_WINDOW_ARB, GL_TRUE, - WGL_SUPPORT_OPENGL_ARB, GL_TRUE, - WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, - WGL_COLOR_BITS_ARB, 24, - WGL_ALPHA_BITS_ARB, 8, - WGL_DEPTH_BITS_ARB, 24, - WGL_STENCIL_BITS_ARB, 8, - WGL_DOUBLE_BUFFER_ARB, GL_TRUE, - WGL_SAMPLE_BUFFERS_ARB, GL_TRUE, - 0, 0}; - - float pixel_attributes_f[] = {0, 0}; - int msaa_pixel_format; - unsigned int num_formats; - - // Query for the highest sampling rate supported, starting at 4x. - static const int kSampleCount[] = {4, 2}; - static const int kNumSamples = 2; - for (int sample = 0; sample < kNumSamples; ++sample) { - pixel_attributes[1] = kSampleCount[sample]; - if (GL_TRUE == ::wglChoosePixelFormatARB(intermediate_dc, - pixel_attributes, - pixel_attributes_f, - 1, - &msaa_pixel_format, - &num_formats)) { - pixel_format_ = msaa_pixel_format; - break; - } - } - } - } - - ::wglMakeCurrent(intermediate_dc, NULL); - ::wglDeleteContext(gl_context); - ::ReleaseDC(intermediate_window, intermediate_dc); - ::DestroyWindow(intermediate_window); - ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration), - module_handle); - return true; -} - -#endif // OS_WIN - // These commands convert from c calls to local os calls. void GLGenBuffersHelper( GLES2DecoderImpl* decoder, GLsizei n, GLuint* ids) { @@ -1537,36 +1298,8 @@ void GLDeleteTexturesHelper( bool GLES2DecoderImpl::MakeCurrent() { #if defined(UNIT_TEST) return true; -#elif defined(GLES2_GPU_SERVICE_BACKEND_NATIVE_GLES2) - return true; -#elif defined(OS_WIN) - if (::wglGetCurrentDC() == gl_device_context_ && - ::wglGetCurrentContext() == gl_context_) { - return true; - } - if (!::wglMakeCurrent(gl_device_context_, gl_context_)) { - DLOG(ERROR) << "Unable to make gl context current."; - return false; - } - return true; -#elif defined(OS_LINUX) - // TODO(apatrick): offscreen rendering not yet supported on this platform. - return context()->MakeCurrent(); -#elif defined(OS_MACOSX) - if (gl_context_) { - if (CGLGetCurrentContext() != gl_context_) { - if (CGLSetCurrentContext(gl_context_) != kCGLNoError) { - DLOG(ERROR) << "Unable to make gl context current."; - return false; - } - } - return true; - } else { - return surface_.MakeCurrent(); - } #else - NOTREACHED(); - return false; + return context_->MakeCurrent(); #endif } @@ -1614,233 +1347,99 @@ void GLES2DecoderImpl::UnregisterObjects( } } -bool GLES2DecoderImpl::InitPlatformSpecific() { -#if !defined(UNIT_TEST) && !defined(OS_LINUX) - bool offscreen = pending_size_.width() > 0 && pending_size_.height() > 0; -#endif -#if defined(UNIT_TEST) -#elif defined(GLES2_GPU_SERVICE_BACKEND_NATIVE_GLES2) -#elif defined(OS_WIN) - // Do one-off initialization. - static bool success = InitializeOneOff(anti_aliased_); - if (!success) - return false; - - if (offscreen) { - // Create a device context compatible with the primary display. - HDC display_device_context = ::CreateDC(L"DISPLAY", NULL, NULL, NULL); - - // Create a 1 x 1 pbuffer suitable for use with the device. This is just - // a stepping stone towards creating a frame buffer object. It doesn't - // matter what size it is. - const int kNoAttributes[] = { 0 }; - pbuffer_ = ::wglCreatePbufferARB(display_device_context, - pixel_format_, - 1, 1, - kNoAttributes); - ::DeleteDC(display_device_context); - if (!pbuffer_) { - DLOG(ERROR) << "Unable to create pbuffer."; - DestroyPlatformSpecific(); - return false; - } - - gl_device_context_ = ::wglGetPbufferDCARB(pbuffer_); - if (!gl_device_context_) { - DLOG(ERROR) << "Unable to get pbuffer device context."; - DestroyPlatformSpecific(); - return false; - } - } else { - // The GL context will render to this window. - gl_device_context_ = ::GetDC(hwnd()); - - if (!::SetPixelFormat(gl_device_context_, - pixel_format_, - &kPixelFormatDescriptor)) { - DLOG(ERROR) << "Unable to set the pixel format for GL context."; - DestroyPlatformSpecific(); - return false; - } - } - - gl_context_ = ::wglCreateContext(gl_device_context_); - if (!gl_context_) { - DLOG(ERROR) << "Failed to create GL context."; - DestroyPlatformSpecific(); - return false; - } +gfx::Size GLES2DecoderImpl::GetBoundFrameBufferSize() { + if (bound_framebuffer_ != 0) { + int width = 0; + int height = 0; - if (parent_) { - if (!wglShareLists(parent_->gl_context_, gl_context_)) { - DLOG(ERROR) << "Could not share GL contexts."; - DestroyPlatformSpecific(); - return false; + // Assume we have to have COLOR_ATTACHMENT0. Should we check for depth and + // stencil. + GLint fb_type = 0; + glGetFramebufferAttachmentParameterivEXT( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, + &fb_type); + switch (fb_type) { + case GL_RENDERBUFFER: + { + GLint renderbuffer_id = 0; + glGetFramebufferAttachmentParameterivEXT( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, + &renderbuffer_id); + if (renderbuffer_id != 0) { + glGetRenderbufferParameterivEXT( + GL_RENDERBUFFER, + GL_RENDERBUFFER_WIDTH, + &width); + glGetRenderbufferParameterivEXT( + GL_RENDERBUFFER, + GL_RENDERBUFFER_HEIGHT, + &height); + } + break; + } + case GL_TEXTURE: + { + GLint texture_id = 0; + glGetFramebufferAttachmentParameterivEXT( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, + &texture_id); + if (texture_id != 0) { + TextureManager::TextureInfo* texture_info = + GetTextureInfo(texture_id); + if (texture_info) { + GLint level = 0; + GLint face = 0; + glGetFramebufferAttachmentParameterivEXT( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL, + &level); + glGetFramebufferAttachmentParameterivEXT( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE, + &face); + texture_info->GetLevelSize( + face ? face : GL_TEXTURE_2D, level, &width, &height); + } + } + break; + } + default: + // unknown so assume width and height are zero. + break; } - } -#elif defined(OS_LINUX) - // TODO(apatrick): parent contexts not yet supported on this platform. - DCHECK(!parent_); - - DCHECK(context()); - - // Offscreen / onscreen handling done earlier on this platform (in - // GPUProcessor::Initialize). - - if (!context()->Initialize()) - return false; -#elif defined(OS_MACOSX) - // TODO(apatrick): parent contexts not yet supported on this platform. - DCHECK(!parent_); - - if (offscreen) { - // Create a 1x1 pbuffer and associated context to bootstrap things - static const CGLPixelFormatAttribute attribs[] = { - (CGLPixelFormatAttribute) kCGLPFAPBuffer, - (CGLPixelFormatAttribute) 0 - }; - CGLPixelFormatObj pixel_format; - GLint num_pixel_formats; - if (CGLChoosePixelFormat(attribs, - &pixel_format, - &num_pixel_formats) != kCGLNoError) { - DLOG(ERROR) << "Error choosing pixel format."; - DestroyPlatformSpecific(); - return false; - } - if (!pixel_format) { - return false; - } - CGLError res = CGLCreateContext(pixel_format, 0, &gl_context_); - CGLDestroyPixelFormat(pixel_format); - if (res != kCGLNoError) { - DLOG(ERROR) << "Error creating context."; - DestroyPlatformSpecific(); - return false; - } - if (CGLCreatePBuffer(1, 1, - GL_TEXTURE_2D, GL_RGBA, - 0, &pbuffer_) != kCGLNoError) { - DLOG(ERROR) << "Error creating pbuffer."; - DestroyPlatformSpecific(); - return false; - } - if (CGLSetPBuffer(gl_context_, pbuffer_, 0, 0, 0) != kCGLNoError) { - DLOG(ERROR) << "Error attaching pbuffer to context."; - DestroyPlatformSpecific(); - return false; - } - return true; + return gfx::Size(width, height); + } else if (offscreen_target_color_texture_.get()) { + return offscreen_target_color_texture_->size(); } else { - return surface_.Initialize(); - } -#endif - - return true; -} - -bool GLES2DecoderImpl::InitGlew() { -#if !defined(UNIT_TEST) && !defined(GLES2_GPU_SERVICE_BACKEND_NATIVE_GLES2) - DLOG(INFO) << "Initializing GL and GLEW for GLES2Decoder."; - - GLenum glew_error = glewInit(); - if (glew_error != GLEW_OK) { - DLOG(ERROR) << "Unable to initialise GLEW : " - << glewGetErrorString(glew_error); - return false; - } - - // Check to see that we can use the OpenGL vertex attribute APIs - // TODO(petersont): Return false if this check fails, but because some - // Intel hardware does not support OpenGL 2.0, yet does support all of the - // extensions we require, we only log an error. A future CL should change - // this check to ensure that all of the extension strings we require are - // present. - if (!GLEW_VERSION_2_0) { - DLOG(ERROR) << "GL drivers do not have OpenGL 2.0 functionality."; - } - - bool extensions_found = true; - if (!GLEW_ARB_vertex_buffer_object) { - // NOTE: Linux NVidia drivers claim to support OpenGL 2.0 when using - // indirect rendering (e.g. remote X), but it is actually lying. The - // ARB_vertex_buffer_object functions silently no-op (!) when using - // indirect rendering, leading to crashes. Fortunately, in that case, the - // driver claims to not support ARB_vertex_buffer_object, so fail in that - // case. - DLOG(ERROR) << "GL drivers do not support vertex buffer objects."; - extensions_found = false; - } - if (!GLEW_EXT_framebuffer_object) { - DLOG(ERROR) << "GL drivers do not support framebuffer objects."; - extensions_found = false; - } - // Check for necessary extensions - if (!GLEW_VERSION_2_0 && !GLEW_EXT_stencil_two_side) { - DLOG(ERROR) << "Two sided stencil extension missing."; - extensions_found = false; - } - if (!GLEW_VERSION_1_4 && !GLEW_EXT_blend_func_separate) { - DLOG(ERROR) <<"Separate blend func extension missing."; - extensions_found = false; - } - if (!GLEW_VERSION_2_0 && !GLEW_EXT_blend_equation_separate) { - DLOG(ERROR) << "Separate blend function extension missing."; - extensions_found = false; - } - if (!extensions_found) - return false; -#endif - - return true; -} - -void GLES2DecoderImpl::DestroyPlatformSpecific() { #if defined(UNIT_TEST) -#elif defined(GLES2_GPU_SERVICE_BACKEND_NATIVE_GLES2) -#elif defined(OS_WIN) - if (gl_context_) { - ::wglDeleteContext(gl_context_); - } - - if (gl_device_context_) { - if (hwnd()) - ::ReleaseDC(hwnd(), gl_device_context_); - else - ::wglReleasePbufferDCARB(pbuffer_, gl_device_context_); - - gl_device_context_ = NULL; - } - - if (pbuffer_) { - ::wglDestroyPbufferARB(pbuffer_); - pbuffer_ = NULL; - } -#elif defined(OS_MAC) - if (gl_context_) { - CGLDestroyContext(gl_context_); - gl_context_ = NULL; - } - - if (pbuffer_) { - CGLDestroyPBuffer(pbuffer_); - pbuffer_ = NULL; - } + return gfx::Size(INT_MAX, INT_MAX); +#else + return context_->GetSize(); #endif + } } bool GLES2DecoderImpl::UpdateOffscreenFrameBufferSize() { - if (current_size_ != pending_size_) + if (offscreen_target_color_texture_->size() == pending_offscreen_size_) return true; // Reallocate the offscreen target buffers. - if (!offscreen_target_color_texture_->AllocateStorage(pending_size_)) { + if (!offscreen_target_color_texture_->AllocateStorage( + pending_offscreen_size_)) { return false; } if (!offscreen_target_depth_stencil_render_buffer_->AllocateStorage( - pending_size_, GL_DEPTH24_STENCIL8)) { + pending_offscreen_size_, GL_DEPTH24_STENCIL8)) { return false; } @@ -1875,20 +1474,21 @@ bool GLES2DecoderImpl::UpdateOffscreenFrameBufferSize() { return false; } - // Create the saved offscreen color texture. - offscreen_saved_color_texture_->AllocateStorage(pending_size_); - - // Clear the offscreen saved color texture by copying the cleared target - // frame buffer into it. - { - ScopedFrameBufferBinder binder(this, offscreen_target_frame_buffer_->id()); - offscreen_saved_color_texture_->Copy(pending_size_); - } - // Update the info about the offscreen saved color texture in the parent. // The reference to the parent is a weak pointer and will become null if the // parent is later destroyed. if (parent_) { + // Create the saved offscreen color texture (only accessible to parent). + offscreen_saved_color_texture_->AllocateStorage(pending_offscreen_size_); + + // Clear the offscreen saved color texture by copying the cleared target + // frame buffer into it. + { + ScopedFrameBufferBinder binder(this, + offscreen_target_frame_buffer_->id()); + offscreen_saved_color_texture_->Copy(pending_offscreen_size_); + } + GLuint service_id = offscreen_saved_color_texture_->id(); TextureManager::TextureInfo* info = @@ -1898,49 +1498,17 @@ bool GLES2DecoderImpl::UpdateOffscreenFrameBufferSize() { info->SetLevelInfo(GL_TEXTURE_2D, 0, // level GL_RGBA, - pending_size_.width(), pending_size_.height(), + pending_offscreen_size_.width(), + pending_offscreen_size_.height(), 1, // depth 0, // border GL_RGBA, GL_UNSIGNED_BYTE); } - current_size_ = pending_size_; return true; } -#if defined(OS_MACOSX) - -uint64 GLES2DecoderImpl::SetWindowSizeForIOSurface(int32 width, int32 height) { -#if defined(UNIT_TEST) - return 0; -#elif defined(GLES2_GPU_SERVICE_BACKEND_NATIVE_GLES2) - return 0; -#else - return surface_.SetSurfaceSize(width, height); -#endif // !defined(UNIT_TEST) -} - -TransportDIB::Handle GLES2DecoderImpl::SetWindowSizeForTransportDIB( - int32 width, int32 height) { -#if defined(UNIT_TEST) - return TransportDIB::DefaultHandleValue(); -#elif defined(GLES2_GPU_SERVICE_BACKEND_NATIVE_GLES2) - return TransportDIB::DefaultHandleValue(); -#else - return surface_.SetTransportDIBSize(width, height); -#endif // !defined(UNIT_TEST) -} - -void GLES2DecoderImpl::SetTransportDIBAllocAndFree( - Callback2<size_t, TransportDIB::Handle*>::Type* allocator, - Callback1<TransportDIB::Id>::Type* deallocator) { -#if !defined(UNIT_TEST) - surface_.SetTransportDIBAllocAndFree(allocator, deallocator); -#endif -} -#endif // defined(OS_MACOSX) - void GLES2DecoderImpl::SetSwapBuffersCallback(Callback0::Type* callback) { swap_buffers_callback_.reset(callback); } @@ -1962,38 +1530,37 @@ void GLES2DecoderImpl::Destroy() { } } - if (offscreen_target_frame_buffer_.get()) + if (offscreen_target_frame_buffer_.get()) { offscreen_target_frame_buffer_->Destroy(); + offscreen_target_frame_buffer_.reset(); + } - if (offscreen_target_color_texture_.get()) + if (offscreen_target_color_texture_.get()) { offscreen_target_color_texture_->Destroy(); + offscreen_target_color_texture_.reset(); + } - if (offscreen_target_depth_stencil_render_buffer_.get()) + if (offscreen_target_depth_stencil_render_buffer_.get()) { offscreen_target_depth_stencil_render_buffer_->Destroy(); + offscreen_target_depth_stencil_render_buffer_.reset(); + } - if (temporary_frame_buffer_.get()) + if (temporary_frame_buffer_.get()) { temporary_frame_buffer_->Destroy(); + temporary_frame_buffer_.reset(); + } - if (offscreen_saved_color_texture_.get()) + if (offscreen_saved_color_texture_.get()) { offscreen_saved_color_texture_->Destroy(); - -#if defined(UNIT_TEST) -#elif defined(GLES2_GPU_SERVICE_BACKEND_NATIVE_GLES2) -#elif defined(OS_LINUX) - DCHECK(context()); - context()->Destroy(); -#elif defined(OS_MACOSX) - surface_.Destroy(); -#endif - - DestroyPlatformSpecific(); + offscreen_saved_color_texture_.reset(); + } } void GLES2DecoderImpl::ResizeOffscreenFrameBuffer(const gfx::Size& size) { // We can't resize the render buffers immediately because there might be a // partial frame rendered into them and we don't want the tail end of that // rendered into the reallocated storage. Defer until the next SwapBuffers. - pending_size_ = size; + pending_offscreen_size_ = size; } const char* GLES2DecoderImpl::GetCommandName(unsigned int command_id) const { @@ -2831,77 +2398,7 @@ error::Error GLES2DecoderImpl::HandleReadPixels( CopyRealGLErrorsToWrapper(); // Get the size of the current fbo or backbuffer. - GLsizei max_width = 0; - GLsizei max_height = 0; - if (bound_framebuffer_ != 0) { - // Assume we have to have COLOR_ATTACHMENT0. Should we check for depth and - // stencil. - GLint fb_type = 0; - glGetFramebufferAttachmentParameterivEXT( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, - &fb_type); - switch (fb_type) { - case GL_RENDERBUFFER: - { - GLint renderbuffer_id = 0; - glGetFramebufferAttachmentParameterivEXT( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, - &renderbuffer_id); - if (renderbuffer_id != 0) { - glGetRenderbufferParameterivEXT( - GL_RENDERBUFFER, - GL_RENDERBUFFER_WIDTH, - &max_width); - glGetRenderbufferParameterivEXT( - GL_RENDERBUFFER, - GL_RENDERBUFFER_HEIGHT, - &max_height); - } - break; - } - case GL_TEXTURE: - { - GLint texture_id = 0; - glGetFramebufferAttachmentParameterivEXT( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, - &texture_id); - if (texture_id != 0) { - TextureManager::TextureInfo* texture_info = - GetTextureInfo(texture_id); - if (texture_info) { - GLint level = 0; - GLint face = 0; - glGetFramebufferAttachmentParameterivEXT( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL, - &level); - glGetFramebufferAttachmentParameterivEXT( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE, - &face); - texture_info->GetLevelSize( - face ? face : GL_TEXTURE_2D, level, &max_width, &max_height); - } - } - break; - } - default: - // unknown so assume max_width = 0. - break; - } - } else { - // TODO(gman): Get these values from the proper place. - max_width = 300; - max_height = 300; - } + gfx::Size max_size = GetBoundFrameBufferSize(); GLint max_x; GLint max_y; @@ -2910,7 +2407,7 @@ error::Error GLES2DecoderImpl::HandleReadPixels( return error::kNoError; } - if (x < 0 || y < 0 || max_x > max_width || max_y > max_height) { + if (x < 0 || y < 0 || max_x > max_size.width() || max_y > max_size.height()) { // The user requested an out of range area. Get the results 1 line // at a time. uint32 temp_size; @@ -2942,7 +2439,7 @@ error::Error GLES2DecoderImpl::HandleReadPixels( // Copy each row into the larger dest rect. int8* dst = static_cast<int8*>(pixels); GLint read_x = std::max(0, x); - GLint read_end_x = std::max(0, std::min(max_width, max_x)); + GLint read_end_x = std::max(0, std::min(max_size.width(), max_x)); GLint read_width = read_end_x - read_x; for (GLint yy = 0; yy < height; ++yy) { GLint ry = y + yy; @@ -2951,7 +2448,7 @@ error::Error GLES2DecoderImpl::HandleReadPixels( memset(dst, 0, unpadded_row_size); // If the row is in range, copy it. - if (ry >= 0 && ry < max_height && read_width > 0) { + if (ry >= 0 && ry < max_size.height() && read_width > 0) { glReadPixels( read_x, ry, read_width, 1, format, type, dst + dest_row_offset); } @@ -3679,19 +3176,11 @@ error::Error GLES2DecoderImpl::HandleSwapBuffers( return error::kLostContext; ScopedFrameBufferBinder binder(this, offscreen_target_frame_buffer_->id()); - offscreen_saved_color_texture_->Copy(current_size_); + offscreen_saved_color_texture_->Copy( + offscreen_saved_color_texture_->size()); } else { -#if defined(UNIT_TEST) -#elif defined(GLES2_GPU_SERVICE_BACKEND_NATIVE_GLES2) -#elif defined(OS_WIN) - ::SwapBuffers(gl_device_context_); -#elif defined(OS_LINUX) - DCHECK(context()); - context()->SwapBuffers(); -#elif defined(OS_MACOSX) - // TODO(kbr): Need to property hook up and track the OpenGL state and hook - // up the notion of the currently bound FBO. - surface_.SwapBuffers(); +#if !defined(UNIT_TEST) + context_->SwapBuffers(); #endif } diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h index 05951a2..08e664b 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder.h @@ -7,23 +7,16 @@ #ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_H_ #define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_H_ -#include <build/build_config.h> -#if defined(OS_WIN) -#include <windows.h> -#endif #include "base/callback.h" -#if defined(OS_MACOSX) -#include "app/surface/transport_dib.h" -#endif - +#include "build/build_config.h" #include "gfx/size.h" #include "gpu/command_buffer/service/common_decoder.h" namespace gpu { -// Forward-declared instead of including x_utils.h, because including glx.h +// Forward-declared instead of including gl_context.h, because including glx.h // causes havok. -class GLXContextWrapper; +class GLContext; namespace gles2 { @@ -49,37 +42,21 @@ class GLES2Decoder : public CommonDecoder { debug_ = debug; } -#if defined(OS_LINUX) - void set_context_wrapper(GLXContextWrapper *context) { - context_ = context; - } - GLXContextWrapper* context() const { - return context_; - } -#elif defined(OS_WIN) - void set_hwnd(HWND hwnd) { - hwnd_ = hwnd; - } - - HWND hwnd() const { - return hwnd_; - } -#elif defined(OS_MACOSX) - virtual uint64 SetWindowSizeForIOSurface(int32 width, int32 height) = 0; - virtual TransportDIB::Handle SetWindowSizeForTransportDIB(int32 width, - int32 height) = 0; - virtual void SetTransportDIBAllocAndFree( - Callback2<size_t, TransportDIB::Handle*>::Type* allocator, - Callback1<TransportDIB::Id>::Type* deallocator) = 0; -#endif - // Initializes the graphics context. Can create an offscreen // decoder with a frame buffer that can be referenced from the parent. + // Parameters: + // context: the GL context to render to. + // size: the size if the GL context is offscreen. + // parent: the GLES2 decoder that can access this decoder's front buffer + // through a texture ID in its namespace. + // parent_client_texture_id: the texture ID of the front buffer in the + // parent's namespace. // Returns: // true if successful. - virtual bool Initialize(GLES2Decoder* parent, + virtual bool Initialize(GLContext* context, const gfx::Size& size, - uint32 parent_texture_id) = 0; + GLES2Decoder* parent, + uint32 parent_client_texture_id) = 0; // Destroys the graphics context. virtual void Destroy() = 0; @@ -96,6 +73,9 @@ class GLES2Decoder : public CommonDecoder { // Gets the GLES2 Util which holds info. virtual GLES2Util* GetGLES2Util() = 0; + // Gets the associated GLContext. + virtual GLContext* GetGLContext() = 0; + // Sets a callback which is called when a SwapBuffers command is processed. virtual void SetSwapBuffersCallback(Callback0::Type* callback) = 0; @@ -107,13 +87,6 @@ class GLES2Decoder : public CommonDecoder { private: bool debug_; -#if defined(OS_LINUX) - GLXContextWrapper *context_; -#elif defined(OS_WIN) - // Handle to the GL device. - HWND hwnd_; -#endif - DISALLOW_COPY_AND_ASSIGN(GLES2Decoder); }; diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h index 4ba9217..e29a1fe8 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h @@ -13,6 +13,8 @@ #include "testing/gmock/include/gmock/gmock.h" namespace gpu { +class GLContext; + namespace gles2 { class ContextGroup; @@ -26,22 +28,16 @@ class MockGLES2Decoder : public GLES2Decoder { .WillByDefault(testing::Return(true)); } -#if defined(OS_MACOSX) - MOCK_METHOD2(SetWindowSizeForIOSurface, uint64(int32 width, int32 height)); - MOCK_METHOD2(SetWindowSizeForTransportDIB, - TransportDIB::Handle(int32 width, int32 height)); - MOCK_METHOD2(SetTransportDIBAllocAndFree, - void(Callback2<size_t, TransportDIB::Handle*>::Type* allocator, - Callback1<TransportDIB::Id>::Type* deallocator)); -#endif - MOCK_METHOD3(Initialize, bool(GLES2Decoder* parent, + MOCK_METHOD4(Initialize, bool(GLContext* context, const gfx::Size& size, + GLES2Decoder* parent, uint32 parent_texture_id)); MOCK_METHOD0(Destroy, void()); MOCK_METHOD1(ResizeOffscreenFrameBuffer, void(const gfx::Size& size)); MOCK_METHOD0(MakeCurrent, bool()); MOCK_METHOD1(GetServiceIdForTesting, uint32(uint32 client_id)); MOCK_METHOD0(GetGLES2Util, GLES2Util*()); + MOCK_METHOD0(GetGLContext, GLContext*()); MOCK_METHOD1(SetSwapBuffersCallback, void(Callback0::Type*)); MOCK_METHOD3(DoCommand, error::Error(unsigned int command, unsigned int arg_count, 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 63a4bd5..35b5ec6 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc @@ -95,7 +95,7 @@ void GLES2DecoderTestBase::SetUp() { shared_memory_id_ = kSharedMemoryId; decoder_.reset(GLES2Decoder::Create(&group_)); - decoder_->Initialize(NULL, gfx::Size(), 0); + decoder_->Initialize(NULL, gfx::Size(), NULL, 0); decoder_->set_engine(engine_.get()); EXPECT_CALL(*gl_, GenBuffersARB(_, _)) diff --git a/gpu/command_buffer/service/gpu_processor.cc b/gpu/command_buffer/service/gpu_processor.cc index d08069c..4514211 100644 --- a/gpu/command_buffer/service/gpu_processor.cc +++ b/gpu/command_buffer/service/gpu_processor.cc @@ -5,6 +5,7 @@ #include "base/callback.h" #include "base/compiler_specific.h" #include "base/message_loop.h" +#include "gpu/command_buffer/service/gl_context.h" #include "gpu/command_buffer/service/gpu_processor.h" using ::base::SharedMemory; @@ -36,6 +37,52 @@ GPUProcessor::~GPUProcessor() { Destroy(); } +bool GPUProcessor::InitializeCommon(const gfx::Size& size, + gles2::GLES2Decoder* parent_decoder, + uint32 parent_texture_id) { + // Context should have been created by platform specific Initialize(). + DCHECK(context_.get()); + + // Map the ring buffer and create the parser. + Buffer ring_buffer = command_buffer_->GetRingBuffer(); + if (ring_buffer.ptr) { + parser_.reset(new CommandParser(ring_buffer.ptr, + ring_buffer.size, + 0, + ring_buffer.size, + 0, + decoder_.get())); + } else { + parser_.reset(new CommandParser(NULL, 0, 0, 0, 0, + decoder_.get())); + } + + // Initialize the decoder with either the view or pbuffer GLContext. + if (!decoder_->Initialize(context_.get(), + size, + parent_decoder, + parent_texture_id)) { + Destroy(); + return false; + } + + return true; +} + +void GPUProcessor::Destroy() { + if (decoder_.get()) { + decoder_->Destroy(); + decoder_.reset(); + } + + if (context_.get()) { + context_->Destroy(); + context_.reset(); + } + + parser_.reset(); +} + void GPUProcessor::ProcessCommands() { CommandBuffer::State state = command_buffer_->GetState(); if (state.error != error::kNoError) @@ -92,23 +139,6 @@ void GPUProcessor::ResizeOffscreenFrameBuffer(const gfx::Size& size) { decoder_->ResizeOffscreenFrameBuffer(size); } -#if defined(OS_MACOSX) -uint64 GPUProcessor::SetWindowSizeForIOSurface(int32 width, int32 height) { - return decoder_->SetWindowSizeForIOSurface(width, height); -} - -TransportDIB::Handle GPUProcessor::SetWindowSizeForTransportDIB(int32 width, - int32 height) { - return decoder_->SetWindowSizeForTransportDIB(width, height); -} - -void GPUProcessor::SetTransportDIBAllocAndFree( - Callback2<size_t, TransportDIB::Handle*>::Type* allocator, - Callback1<TransportDIB::Id>::Type* deallocator) { - decoder_->SetTransportDIBAllocAndFree(allocator, deallocator); -} -#endif - void GPUProcessor::SetSwapBuffersCallback( Callback0::Type* callback) { decoder_->SetSwapBuffersCallback(callback); diff --git a/gpu/command_buffer/service/gpu_processor.h b/gpu/command_buffer/service/gpu_processor.h index d61bd60..c4c0ea5 100644 --- a/gpu/command_buffer/service/gpu_processor.h +++ b/gpu/command_buffer/service/gpu_processor.h @@ -5,6 +5,7 @@ #ifndef GPU_COMMAND_BUFFER_SERVICE_GPU_PROCESSOR_H_ #define GPU_COMMAND_BUFFER_SERVICE_GPU_PROCESSOR_H_ +#include "app/surface/transport_dib.h" #include "base/callback.h" #include "base/ref_counted.h" #include "base/scoped_ptr.h" @@ -18,8 +19,14 @@ #include "gpu/command_buffer/service/context_group.h" #include "gpu/command_buffer/service/gles2_cmd_decoder.h" +#if defined(OS_MACOSX) && !defined(UNIT_TEST) +#include "app/surface/accelerated_surface_mac.h" +#endif + namespace gpu { +class GLContext; + // This class processes commands in a command buffer. It is event driven and // posts tasks to the current message loop to do additional work. class GPUProcessor : public CommandBufferEngine { @@ -32,14 +39,18 @@ class GPUProcessor : public CommandBufferEngine { CommandParser* parser, int commands_per_update); - virtual bool Initialize(gfx::PluginWindowHandle hwnd, - GPUProcessor* parent, - const gfx::Size& size, - uint32 parent_texture_id); - virtual ~GPUProcessor(); - virtual void Destroy(); + bool Initialize(gfx::PluginWindowHandle hwnd, + const gfx::Size& size, + GPUProcessor* parent, + uint32 parent_texture_id); + + bool InitializeCommon(const gfx::Size& size, + gles2::GLES2Decoder* parent_decoder, + uint32 parent_texture_id); + + void Destroy(); virtual void ProcessCommands(); @@ -59,9 +70,9 @@ class GPUProcessor : public CommandBufferEngine { // There are two versions of this method: one for use with the IOSurface // available in Mac OS X 10.6; and, one for use with the // TransportDIB-based version used on Mac OS X 10.5. - virtual uint64 SetWindowSizeForIOSurface(int32 width, int32 height); - virtual TransportDIB::Handle SetWindowSizeForTransportDIB(int32 width, - int32 height); + virtual uint64 SetWindowSizeForIOSurface(const gfx::Size& size); + virtual TransportDIB::Handle SetWindowSizeForTransportDIB( + const gfx::Size& size); virtual void SetTransportDIBAllocAndFree( Callback2<size_t, TransportDIB::Handle*>::Type* allocator, Callback1<TransportDIB::Id>::Type* deallocator); @@ -83,6 +94,11 @@ class GPUProcessor : public CommandBufferEngine { gles2::ContextGroup group_; scoped_ptr<gles2::GLES2Decoder> decoder_; scoped_ptr<CommandParser> parser_; + scoped_ptr<GLContext> context_; + +#if defined(OS_MACOSX) && !defined(UNIT_TEST) + AcceleratedSurface surface_; +#endif ScopedRunnableMethodFactory<GPUProcessor> method_factory_; }; diff --git a/gpu/command_buffer/service/gpu_processor_linux.cc b/gpu/command_buffer/service/gpu_processor_linux.cc index b477021..10f1a87 100644 --- a/gpu/command_buffer/service/gpu_processor_linux.cc +++ b/gpu/command_buffer/service/gpu_processor_linux.cc @@ -2,71 +2,59 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#if !defined(UNIT_TEST) #include <gdk/gdkx.h> +#else +#define GDK_DISPLAY() NULL +#endif + +#include "gpu/command_buffer/service/gl_context.h" #include "gpu/command_buffer/service/gpu_processor.h" -#include "gpu/command_buffer/service/x_utils.h" using ::base::SharedMemory; namespace gpu { -bool GPUProcessor::Initialize(gfx::PluginWindowHandle handle, - GPUProcessor* parent, +bool GPUProcessor::Initialize(gfx::PluginWindowHandle window, const gfx::Size& size, + GPUProcessor* parent, uint32 parent_texture_id) { // Cannot reinitialize. - if (decoder_->context() != NULL) + if (context_.get()) return false; - // Map the ring buffer and create the parser. - Buffer ring_buffer = command_buffer_->GetRingBuffer(); - if (ring_buffer.ptr) { - parser_.reset(new CommandParser(ring_buffer.ptr, - ring_buffer.size, - 0, - ring_buffer.size, - 0, - decoder_.get())); - } else { - parser_.reset(new CommandParser(NULL, 0, 0, 0, 0, - decoder_.get())); + // Get the parent decoder and the GLContext to share IDs with, if any. + gles2::GLES2Decoder* parent_decoder = NULL; + GLContext* parent_context = NULL; + if (parent) { + parent_decoder = parent->decoder_.get(); + DCHECK(parent_decoder); + + parent_context = parent_decoder->GetGLContext(); + DCHECK(parent_context); } - // Initialize GAPI immediately. - GLXContextWrapper* wrapper = NULL; - if (size.width() > 0 && size.height() > 0) { - // Offscreen code path. - DCHECK(!handle); - wrapper = new GLXPbufferWrapper(GDK_DISPLAY()); + // Create either a view or pbuffer based GLContext. + if (window) { + scoped_ptr<ViewGLContext> context(new ViewGLContext(GDK_DISPLAY(), window)); + // TODO(apatrick): support multisampling. + if (!context->Initialize(false)) { + Destroy(); + return false; + } + context_.reset(context.release()); } else { - DCHECK(handle); - // Onscreen code path. - wrapper = new XWindowWrapper(GDK_DISPLAY(), handle); - } - decoder_->set_context_wrapper(wrapper); - gles2::GLES2Decoder* parent_decoder = parent ? parent->decoder_.get() : NULL; - if (!decoder_->Initialize(parent_decoder, - size, - parent_texture_id)) { - Destroy(); - return false; + scoped_ptr<PbufferGLContext> context(new PbufferGLContext(GDK_DISPLAY())); + if (!context->Initialize(parent_context)) { + Destroy(); + return false; + } + context_.reset(context.release()); } - return true; -} - -void GPUProcessor::Destroy() { - // Destroy decoder if initialized. - // TODO(gman): simplify cleanup logic. http://crbug.com/39895 - if (decoder_.get()) { - GLXContextWrapper *context = decoder_->context(); - decoder_->Destroy(); - decoder_->set_context_wrapper(NULL); - delete context; - decoder_.reset(); - } + return InitializeCommon(size, parent_decoder, parent_texture_id); - parser_.reset(); + return true; } } // namespace gpu diff --git a/gpu/command_buffer/service/gpu_processor_mac.cc b/gpu/command_buffer/service/gpu_processor_mac.cc index ef13fc6..55b6816 100644 --- a/gpu/command_buffer/service/gpu_processor_mac.cc +++ b/gpu/command_buffer/service/gpu_processor_mac.cc @@ -2,55 +2,84 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "gpu/command_buffer/service/gl_context.h" #include "gpu/command_buffer/service/gpu_processor.h" using ::base::SharedMemory; namespace gpu { -bool GPUProcessor::Initialize(gfx::PluginWindowHandle handle, - GPUProcessor* parent, +bool GPUProcessor::Initialize(gfx::PluginWindowHandle window, const gfx::Size& size, + GPUProcessor* parent, uint32 parent_texture_id) { - // At this level we do not need the PluginWindowHandle. It is only - // needed at the CommandBufferStub level to identify which GPU - // plugin instance is creating a new backing store in response to a - // resize event. - - // Map the ring buffer and create the parser. - Buffer ring_buffer = command_buffer_->GetRingBuffer(); - if (ring_buffer.ptr) { - parser_.reset(new CommandParser(ring_buffer.ptr, - ring_buffer.size, - 0, - ring_buffer.size, - 0, - decoder_.get())); - } else { - parser_.reset(new CommandParser(NULL, 0, 0, 0, 0, - decoder_.get())); + // Cannot reinitialize. + if (context_.get()) + return false; + + // Get the parent decoder and the GLContext to share IDs with, if any. + gles2::GLES2Decoder* parent_decoder = NULL; + GLContext* parent_context = NULL; + if (parent) { + parent_decoder = parent->decoder_.get(); + DCHECK(parent_decoder); + + parent_context = parent_decoder->GetGLContext(); + DCHECK(parent_context); } - // Initialize GAPI. - gles2::GLES2Decoder* parent_decoder = parent ? parent->decoder_.get() : NULL; - if (!decoder_->Initialize(parent_decoder, - size, - parent_texture_id)) { - Destroy(); - return false; + // Create either a view or pbuffer based GLContext. + if (window) { +#if !defined(UNIT_TEST) + AcceleratedSurface* surface_ptr = &surface_; +#else + AcceleratedSurface* surface_ptr = NULL; +#endif + scoped_ptr<ViewGLContext> context(new ViewGLContext(surface_ptr)); + // TODO(apatrick): support multisampling. + if (!context->Initialize(false)) { + Destroy(); + return false; + } + context_.reset(context.release()); + } else { + scoped_ptr<PbufferGLContext> context(new PbufferGLContext); + if (!context->Initialize(parent_context)) { + Destroy(); + return false; + } + context_.reset(context.release()); } + return InitializeCommon(size, parent_decoder, parent_texture_id); + return true; } -void GPUProcessor::Destroy() { - // Destroy decoder if initialized. - if (decoder_.get()) { - decoder_->Destroy(); - decoder_.reset(); - } +uint64 GPUProcessor::SetWindowSizeForIOSurface(const gfx::Size& size) { +#if !defined(UNIT_TEST) + return surface_.SetSurfaceSize(size); +#else + return 0; +#endif +} - parser_.reset(); +TransportDIB::Handle GPUProcessor::SetWindowSizeForTransportDIB( + const gfx::Size& size) { +#if !defined(UNIT_TEST) + return surface_.SetTransportDIBSize(size); +#else + return TransportDIB::DefaultHandleValue(); +#endif } + +void GPUProcessor::SetTransportDIBAllocAndFree( + Callback2<size_t, TransportDIB::Handle*>::Type* allocator, + Callback1<TransportDIB::Id>::Type* deallocator) { +#if !defined(UNIT_TEST) + surface_.SetTransportDIBAllocAndFree(allocator, deallocator); +#endif +} + } // namespace gpu diff --git a/gpu/command_buffer/service/gpu_processor_mock.h b/gpu/command_buffer/service/gpu_processor_mock.h index ca257e8..8eab35d 100644 --- a/gpu/command_buffer/service/gpu_processor_mock.h +++ b/gpu/command_buffer/service/gpu_processor_mock.h @@ -16,8 +16,6 @@ class MockGPUProcessor : public GPUProcessor { : GPUProcessor(command_buffer) { } - MOCK_METHOD1(Initialize, bool(gfx::PluginWindowHandle handle)); - MOCK_METHOD0(Destroy, void()); MOCK_METHOD0(ProcessCommands, void()); MOCK_METHOD1(GetSharedMemoryBuffer, Buffer(int32 shm_id)); MOCK_METHOD1(set_token, void(int32 token)); diff --git a/gpu/command_buffer/service/gpu_processor_win.cc b/gpu/command_buffer/service/gpu_processor_win.cc index 537872c..143d5a6 100644 --- a/gpu/command_buffer/service/gpu_processor_win.cc +++ b/gpu/command_buffer/service/gpu_processor_win.cc @@ -4,55 +4,52 @@ #include <windows.h> +#include "gpu/command_buffer/service/gl_context.h" #include "gpu/command_buffer/service/gpu_processor.h" using ::base::SharedMemory; namespace gpu { -bool GPUProcessor::Initialize(gfx::PluginWindowHandle handle, - GPUProcessor* parent, +bool GPUProcessor::Initialize(gfx::PluginWindowHandle window, const gfx::Size& size, + GPUProcessor* parent, uint32 parent_texture_id) { // Cannot reinitialize. - if (parser_.get()) + if (context_.get()) return false; - // Map the ring buffer and create the parser. - Buffer ring_buffer = command_buffer_->GetRingBuffer(); - if (ring_buffer.ptr) { - parser_.reset(new CommandParser(ring_buffer.ptr, - ring_buffer.size, - 0, - ring_buffer.size, - 0, - decoder_.get())); - } else { - parser_.reset(new CommandParser(NULL, 0, 0, 0, 0, - decoder_.get())); - } + // Get the parent decoder and the GLContext to share IDs with, if any. + gles2::GLES2Decoder* parent_decoder = NULL; + GLContext* parent_context = NULL; + if (parent) { + parent_decoder = parent->decoder_.get(); + DCHECK(parent_decoder); - // Initialize GAPI immediately if the window handle is valid. - decoder_->set_hwnd(handle); - gles2::GLES2Decoder* parent_decoder = parent ? parent->decoder_.get() : NULL; - if (!decoder_->Initialize(parent_decoder, - size, - parent_texture_id)) { - Destroy(); - return false; + parent_context = parent_decoder->GetGLContext(); + DCHECK(parent_context); } - return true; -} - -void GPUProcessor::Destroy() { - // Destroy decoder if initialized. - if (decoder_.get()) { - decoder_->Destroy(); - decoder_->set_hwnd(NULL); - decoder_.reset(); + // Create either a view or pbuffer based GLContext. + if (window) { + scoped_ptr<ViewGLContext> context(new ViewGLContext(window)); + // TODO(apatrick): support multisampling. + if (!context->Initialize(false)) { + Destroy(); + return false; + } + context_.reset(context.release()); + } else { + scoped_ptr<PbufferGLContext> context(new PbufferGLContext); + if (!context->Initialize(parent_context)) { + Destroy(); + return false; + } + context_.reset(context.release()); } - parser_.reset(); + return InitializeCommon(size, parent_decoder, parent_texture_id); + + return true; } } // namespace gpu diff --git a/gpu/command_buffer/service/precompile.cc b/gpu/command_buffer/service/precompile.cc deleted file mode 100644 index 07870fa..0000000 --- a/gpu/command_buffer/service/precompile.cc +++ /dev/null @@ -1,5 +0,0 @@ -// 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 "gpu/command_buffer/service/precompile.h" diff --git a/gpu/command_buffer/service/precompile.h b/gpu/command_buffer/service/precompile.h deleted file mode 100644 index 19dc80c..0000000 --- a/gpu/command_buffer/service/precompile.h +++ /dev/null @@ -1,22 +0,0 @@ -// 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. - -// This file contains includes for common headers used by command buffer server -// files. It is used for pre-compiled header support. - -#ifndef GPU_COMMAND_BUFFER_SERVICE_PRECOMPILE_H_ -#define GPU_COMMAND_BUFFER_SERVICE_PRECOMPILE_H_ - -#include <build/build_config.h> - -#if defined(OS_WIN) -#include <windows.h> -#endif - -#include <assert.h> -#include <algorithm> -#include <map> -#include <vector> - -#endif // O3D_CORE_PRECOMPILE_H_ diff --git a/gpu/command_buffer/service/x_utils.h b/gpu/command_buffer/service/x_utils.h deleted file mode 100644 index ca88f73..0000000 --- a/gpu/command_buffer/service/x_utils.h +++ /dev/null @@ -1,109 +0,0 @@ -// 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. - -// This file declares the XWindowWrapper class. - -#ifndef GPU_COMMAND_BUFFER_SERVICE_X_UTILS_H_ -#define GPU_COMMAND_BUFFER_SERVICE_X_UTILS_H_ - -#include "base/basictypes.h" -#include "gpu/command_buffer/common/logging.h" -#include "gpu/command_buffer/service/gl_utils.h" - -namespace gpu { - -// Abstracts between on-screen and off-screen GLX contexts. -class GLXContextWrapper { - public: - explicit GLXContextWrapper(Display* display) - : display_(display), - context_(NULL) { - DCHECK(display_); - } - - virtual ~GLXContextWrapper(); - - // Initializes the GL context. Subclasses should perform their - // initialization work and then call the superclass implementation. - virtual bool Initialize(); - - // Destroys the GL context. Subclasses may call this before or after - // doing any necessary cleanup work. - virtual void Destroy(); - - // Makes the GL context current on the current thread. - virtual bool MakeCurrent() = 0; - - // Returns true if this context is offscreen. - virtual bool IsOffscreen() = 0; - - // Swaps front and back buffers. This has no effect for off-screen - // contexts. - virtual void SwapBuffers() = 0; - - // Fetches the GLX context for sharing of server-side objects. - GLXContext GetContext() { - return context_; - } - - protected: - Display* GetDisplay() { - return display_; - } - - void SetContext(GLXContext context) { - context_ = context; - } - - private: - Display* display_; - GLXContext context_; - - DISALLOW_COPY_AND_ASSIGN(GLXContextWrapper); -}; - -// This class is a wrapper around an X Window and associated GL context. It is -// useful to isolate intrusive X headers, since it can be forward declared -// (Window and GLXContext can't). -class XWindowWrapper : public GLXContextWrapper { - public: - XWindowWrapper(Display *display, Window window) - : GLXContextWrapper(display), - window_(window) { - DCHECK(window_); - } - - virtual bool Initialize(); - virtual bool MakeCurrent(); - virtual bool IsOffscreen(); - virtual void SwapBuffers(); - - private: - Window window_; - DISALLOW_COPY_AND_ASSIGN(XWindowWrapper); -}; - -// This class is a wrapper around a GLX pbuffer and associated GL context. It -// serves the same purpose as the XWindowWrapper for initializing off-screen -// rendering. -class GLXPbufferWrapper : public GLXContextWrapper { - public: - explicit GLXPbufferWrapper(Display* display) - : GLXContextWrapper(display) { - } - - virtual bool Initialize(); - virtual void Destroy(); - virtual bool MakeCurrent(); - virtual bool IsOffscreen(); - virtual void SwapBuffers(); - - private: - GLXPbuffer pbuffer_; - DISALLOW_COPY_AND_ASSIGN(GLXPbufferWrapper); -}; - -} // namespace gpu - -#endif // GPU_COMMAND_BUFFER_SERVICE_X_UTILS_H_ diff --git a/gpu/demos/framework/window.cc b/gpu/demos/framework/window.cc index 0a9db79..5e3a309 100644 --- a/gpu/demos/framework/window.cc +++ b/gpu/demos/framework/window.cc @@ -61,7 +61,7 @@ bool Window::CreateRenderContext(gfx::PluginWindowHandle hwnd) { GPUProcessor* gpu_processor( new GPUProcessor(command_buffer.get())); - if (!gpu_processor->Initialize(hwnd, NULL, gfx::Size(), 0)) { + if (!gpu_processor->Initialize(hwnd, gfx::Size(), NULL, 0)) { return false; } diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp index fac0dee..da7172b 100644 --- a/gpu/gpu.gyp +++ b/gpu/gpu.gyp @@ -22,7 +22,12 @@ 'command_buffer/service/gles2_cmd_validation.cc', 'command_buffer/service/gles2_cmd_validation_autogen.h', 'command_buffer/service/gles2_cmd_validation_implementation_autogen.h', + 'command_buffer/service/gl_context.cc', + 'command_buffer/service/gl_context.h', 'command_buffer/service/gl_utils.h', + 'command_buffer/service/gpu_processor.h', + 'command_buffer/service/gpu_processor.cc', + 'command_buffer/service/gpu_processor_mock.h', 'command_buffer/service/id_manager.h', 'command_buffer/service/id_manager.cc', 'command_buffer/service/program_manager.h', @@ -34,6 +39,32 @@ 'command_buffer/service/texture_manager.h', 'command_buffer/service/texture_manager.cc', ], + 'conditions': [ + ['OS == "linux"', + { + 'gpu_service_source_files': [ + 'command_buffer/service/gl_context_linux.cc', + 'command_buffer/service/gpu_processor_linux.cc', + ], + }, + ], + ['OS == "win"', + { + 'gpu_service_source_files': [ + 'command_buffer/service/gl_context_win.cc', + 'command_buffer/service/gpu_processor_win.cc', + ], + }, + ], + ['OS == "mac"', + { + 'gpu_service_source_files': [ + 'command_buffer/service/gl_context_mac.cc', + 'command_buffer/service/gpu_processor_mac.cc', + ], + }, + ], + ], }, 'targets': [ { @@ -233,40 +264,7 @@ 'command_buffer/service/command_buffer_service.h', 'command_buffer/service/cmd_parser.cc', 'command_buffer/service/cmd_parser.h', - 'command_buffer/service/gpu_processor.h', - 'command_buffer/service/gpu_processor.cc', - 'command_buffer/service/gpu_processor_mock.h', 'command_buffer/service/mocks.h', - 'command_buffer/service/precompile.cc', - 'command_buffer/service/precompile.h', - ], - 'conditions': [ - ['OS == "linux"', - { - 'sources': [ - 'command_buffer/service/gpu_processor_linux.cc', - 'command_buffer/service/x_utils.cc', - 'command_buffer/service/x_utils.h', - ], - 'dependencies': [ - '../build/linux/system.gyp:gtk', - ] - }, - ], - ['OS == "win"', - { - 'sources': [ - 'command_buffer/service/gpu_processor_win.cc', - ], - }, - ], - ['OS == "mac"', - { - 'sources': [ - 'command_buffer/service/gpu_processor_mac.cc', - ], - }, - ], ], }, { @@ -287,6 +285,15 @@ 'sources': [ '<@(gpu_service_source_files)', ], + 'conditions': [ + ['OS == "linux"', + { + 'dependencies': [ + '../build/linux/system.gyp:gtk', + ] + }, + ], + ], }, { 'target_name': 'gpu_plugin', |