diff options
author | apatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-15 21:35:12 +0000 |
---|---|---|
committer | apatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-15 21:35:12 +0000 |
commit | a3e1b635a1f31e1c736ebb5dad2e772b12ac7aac (patch) | |
tree | 87fad4399b3337096e825e88d213ad88e939955a /ui | |
parent | 95aa1a3d894423e0ac4f7075ef369ab103cfbf64 (diff) | |
download | chromium_src-a3e1b635a1f31e1c736ebb5dad2e772b12ac7aac.zip chromium_src-a3e1b635a1f31e1c736ebb5dad2e772b12ac7aac.tar.gz chromium_src-a3e1b635a1f31e1c736ebb5dad2e772b12ac7aac.tar.bz2 |
Split WGL implementations of *GLContext in GLContextWGL and *GLSurfaceWGL.
Surfaces are independent of contexts in GL. To facilitate sharing of surfaces between processes, I have separated them from the notion of contexts because contexts cannot be shared between processes.
I started with EGL in r81512. This is the same thing for WGL.
GLContextEGL still has a pointer to a surface and still has some surface specific operations that just forward through to it. Once I have refactored all the GLContext implementations in this way, I will remove these pointers and the surface specific opertations.
There will not be "view" and "offscreen" GL contexts. Rather there will be a single context type for each backend which can be made current with a surface that directs output either to a view or offscreen surface.
Review URL: http://codereview.chromium.org/6864002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@81807 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r-- | ui/gfx/gl/gl.gyp | 4 | ||||
-rw-r--r-- | ui/gfx/gl/gl_context_egl.cc | 6 | ||||
-rw-r--r-- | ui/gfx/gl/gl_context_wgl.cc | 122 | ||||
-rw-r--r-- | ui/gfx/gl/gl_context_wgl.h | 46 | ||||
-rw-r--r-- | ui/gfx/gl/gl_context_win.cc | 484 | ||||
-rw-r--r-- | ui/gfx/gl/gl_surface.h | 8 | ||||
-rw-r--r-- | ui/gfx/gl/gl_surface_wgl.cc | 297 | ||||
-rw-r--r-- | ui/gfx/gl/gl_surface_wgl.h | 74 |
8 files changed, 567 insertions, 474 deletions
diff --git a/ui/gfx/gl/gl.gyp b/ui/gfx/gl/gl.gyp index 50a9785..507d9b4 100644 --- a/ui/gfx/gl/gl.gyp +++ b/ui/gfx/gl/gl.gyp @@ -144,6 +144,10 @@ }], ['OS=="win"', { 'sources': [ + 'gl_context_wgl.cc', + 'gl_context_wgl.h', + 'gl_surface_wgl.cc', + 'gl_surface_wgl.h', '<(gl_binding_output_dir)/gl_bindings_autogen_wgl.cc', '<(gl_binding_output_dir)/gl_bindings_autogen_wgl.h', ], diff --git a/ui/gfx/gl/gl_context_egl.cc b/ui/gfx/gl/gl_context_egl.cc index dd2ed27..8f64041 100644 --- a/ui/gfx/gl/gl_context_egl.cc +++ b/ui/gfx/gl/gl_context_egl.cc @@ -40,6 +40,7 @@ GLContextEGL::GLContextEGL(GLSurfaceEGL* surface) } GLContextEGL::~GLContextEGL() { + Destroy(); } bool GLContextEGL::Initialize(GLContext* shared_context) { @@ -86,6 +87,11 @@ void GLContextEGL::Destroy() { context_ = NULL; } + + if (surface_.get()) { + surface_->Destroy(); + surface_.reset(); + } } bool GLContextEGL::MakeCurrent() { diff --git a/ui/gfx/gl/gl_context_wgl.cc b/ui/gfx/gl/gl_context_wgl.cc new file mode 100644 index 0000000..361f8e9 --- /dev/null +++ b/ui/gfx/gl/gl_context_wgl.cc @@ -0,0 +1,122 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file implements the GLContextWGL and PbufferGLContext classes. + +#include "ui/gfx/gl/gl_context_wgl.h" + +#include "base/logging.h" +#include "ui/gfx/gl/gl_bindings.h" +#include "ui/gfx/gl/gl_implementation.h" + +namespace gfx { + +GLContextWGL::GLContextWGL(GLSurfaceWGL* surface) + : surface_(surface), + context_(NULL) { + DCHECK(surface); +} + +GLContextWGL::~GLContextWGL() { + Destroy(); +} + +std::string GLContextWGL::GetExtensions() { + if (wglGetExtensionsStringARB) { + // TODO(apatrick): When contexts and surfaces are separated, we won't be + // able to use surface_ here. Either use a display device context or the + // surface that was passed to MakeCurrent. + const char* extensions = wglGetExtensionsStringARB( + static_cast<HDC>(surface_->GetHandle())); + if (extensions) { + return GLContext::GetExtensions() + " " + extensions; + } + } + + return GLContext::GetExtensions(); +} + +bool GLContextWGL::Initialize(GLContext* shared_context) { + // TODO(apatrick): When contexts and surfaces are separated, we won't be + // able to use surface_ here. Either use a display device context or a + // surface that the context is compatible with not necessarily limited to + // rendering to. + context_ = wglCreateContext(static_cast<HDC>(surface_->GetHandle())); + if (!context_) { + LOG(ERROR) << "Failed to create GL context."; + Destroy(); + return false; + } + + if (shared_context) { + if (!wglShareLists( + static_cast<HGLRC>(shared_context->GetHandle()), + context_)) { + LOG(ERROR) << "Could not share GL contexts."; + Destroy(); + return false; + } + } + + return true; +} + +void GLContextWGL::Destroy() { + if (context_) { + wglDeleteContext(context_); + context_ = NULL; + } + + if (surface_.get()) { + surface_->Destroy(); + surface_.reset(); + } +} + +bool GLContextWGL::MakeCurrent() { + if (IsCurrent()) { + return true; + } + + if (!wglMakeCurrent(static_cast<HDC>(surface_->GetHandle()), + context_)) { + LOG(ERROR) << "Unable to make gl context current."; + return false; + } + + return true; +} + +bool GLContextWGL::IsCurrent() { + return wglGetCurrentDC() == surface_->GetHandle() && + wglGetCurrentContext() == context_; +} + +bool GLContextWGL::IsOffscreen() { + // TODO(apatrick): remove this from GLContext interface. + return surface_->IsOffscreen(); +} + +bool GLContextWGL::SwapBuffers() { + // TODO(apatrick): remove this from GLContext interface. + return surface_->SwapBuffers(); +} + +gfx::Size GLContextWGL::GetSize() { + // TODO(apatrick): remove this from GLContext interface. + return surface_->GetSize(); +} + +void* GLContextWGL::GetHandle() { + return context_; +} + +void GLContextWGL::SetSwapInterval(int interval) { + DCHECK(IsCurrent()); + if (HasExtension("WGL_EXT_swap_control") && wglSwapIntervalEXT) { + wglSwapIntervalEXT(interval); + } +} + +} // namespace gfx diff --git a/ui/gfx/gl/gl_context_wgl.h b/ui/gfx/gl/gl_context_wgl.h new file mode 100644 index 0000000..c5c5783 --- /dev/null +++ b/ui/gfx/gl/gl_context_wgl.h @@ -0,0 +1,46 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_GFX_GL_GL_CONTEXT_WGL_H_ +#define UI_GFX_GL_GL_CONTEXT_WGL_H_ + +#include <string> + +#include "base/memory/scoped_ptr.h" +#include "ui/gfx/gl/gl_context.h" +#include "ui/gfx/gl/gl_surface_wgl.h" +#include "ui/gfx/size.h" + +namespace gfx { + +// This class is a wrapper around a GL context. +class GLContextWGL : public GLContext { + public: + explicit GLContextWGL(GLSurfaceWGL* surface); + virtual ~GLContextWGL(); + + // Initializes the GL context. + bool Initialize(GLContext* shared_context); + + // Implement GLContext. + virtual void Destroy(); + virtual bool MakeCurrent(); + virtual bool IsCurrent(); + virtual bool IsOffscreen(); + virtual bool SwapBuffers(); + virtual gfx::Size GetSize(); + virtual void* GetHandle(); + virtual void SetSwapInterval(int interval); + virtual std::string GetExtensions(); + + private: + scoped_ptr<GLSurfaceWGL> surface_; + HGLRC context_; + + DISALLOW_COPY_AND_ASSIGN(GLContextWGL); +}; + +} // namespace gfx + +#endif // UI_GFX_GL_GL_CONTEXT_WGL_H_ diff --git a/ui/gfx/gl/gl_context_win.cc b/ui/gfx/gl/gl_context_win.cc index d2bbe77..87f3d98 100644 --- a/ui/gfx/gl/gl_context_win.cc +++ b/ui/gfx/gl/gl_context_win.cc @@ -16,54 +16,13 @@ #include "ui/gfx/gl/gl_context_egl.h" #include "ui/gfx/gl/gl_context_osmesa.h" #include "ui/gfx/gl/gl_context_stub.h" +#include "ui/gfx/gl/gl_context_wgl.h" #include "ui/gfx/gl/gl_implementation.h" #include "ui/gfx/gl/gl_surface_egl.h" +#include "ui/gfx/gl/gl_surface_wgl.h" namespace gfx { -typedef HGLRC GLContextHandle; -typedef HPBUFFERARB PbufferHandle; - -class BaseWinGLContext : public GLContext { - public: - virtual std::string GetExtensions(); - - virtual HDC GetDC() = 0; -}; - -// This class is a wrapper around a GL context that renders directly to a -// window. -class NativeViewGLContext : public BaseWinGLContext { - public: - explicit NativeViewGLContext(gfx::PluginWindowHandle window) - : window_(window), - device_context_(NULL), - context_(NULL) { - DCHECK(window); - } - - // Initializes the GL context. - bool Initialize(bool multisampled); - - virtual void Destroy(); - virtual bool MakeCurrent(); - virtual bool IsCurrent(); - virtual bool IsOffscreen(); - virtual bool SwapBuffers(); - virtual gfx::Size GetSize(); - virtual void* GetHandle(); - virtual void SetSwapInterval(int interval); - - virtual HDC GetDC(); - - private: - gfx::PluginWindowHandle window_; - HDC device_context_; - GLContextHandle context_; - - DISALLOW_COPY_AND_ASSIGN(NativeViewGLContext); -}; - // This class is a wrapper around a GL context that uses OSMesa to render // to an offscreen buffer and then blits it to a window. class OSMesaViewGLContext : public GLContext { @@ -96,70 +55,6 @@ class OSMesaViewGLContext : public GLContext { DISALLOW_COPY_AND_ASSIGN(OSMesaViewGLContext); }; -// This class is a wrapper around a GL context used for offscreen rendering. -// It is initially backed by a 1x1 pbuffer. Use it to create an FBO to do useful -// rendering. -class PbufferGLContext : public GLContext { - public: - PbufferGLContext() - : context_(NULL), - device_context_(NULL), - pbuffer_(NULL) { - } - - // Initializes the GL context. - bool Initialize(GLContext* shared_context); - - virtual void Destroy(); - virtual bool MakeCurrent(); - virtual bool IsCurrent(); - virtual bool IsOffscreen(); - virtual bool SwapBuffers(); - virtual gfx::Size GetSize(); - virtual void* GetHandle(); - virtual void SetSwapInterval(int interval); - - virtual HDC GetDC(); - - private: - GLContextHandle context_; - HDC device_context_; - PbufferHandle pbuffer_; - - DISALLOW_COPY_AND_ASSIGN(PbufferGLContext); -}; - -static HWND g_window; -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); -} - // Helper routine that does one-off initialization like determining the // pixel format and initializing the GL bindings. bool GLContext::InitializeOneOff() { @@ -181,134 +76,11 @@ bool GLContext::InitializeOneOff() { return false; } - // 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)) { - LOG(ERROR) << "GetModuleHandleEx failed."; - 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) { - LOG(ERROR) << "RegisterClass failed."; - return false; - } - - g_window = ::CreateWindow( - reinterpret_cast<wchar_t*>(class_registration), - L"", - WS_OVERLAPPEDWINDOW, - 0, 0, - 100, 100, - NULL, - NULL, - NULL, - NULL); - - if (!g_window) { - ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration), - module_handle); - LOG(ERROR) << "CreateWindow failed."; - return false; - } - - // Early out if OSMesa offscreen renderer or EGL is present. switch (GetGLImplementation()) { - case kGLImplementationDesktopGL: { - HDC intermediate_dc = ::GetDC(g_window); - g_regular_pixel_format = ::ChoosePixelFormat(intermediate_dc, - &kPixelFormatDescriptor); - if (g_regular_pixel_format == 0) { - LOG(ERROR) << "Unable to get the pixel format for GL context."; - ::ReleaseDC(g_window, intermediate_dc); - ::DestroyWindow(g_window); - ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration), - module_handle); - return false; - } - if (!::SetPixelFormat(intermediate_dc, g_regular_pixel_format, - &kPixelFormatDescriptor)) { - LOG(ERROR) << "Unable to set the pixel format for GL context."; - ::ReleaseDC(g_window, intermediate_dc); - ::DestroyWindow(g_window); - ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration), - module_handle); + case kGLImplementationDesktopGL: + if (!GLSurfaceWGL::InitializeOneOff()) 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)) { - // Get bindings to extension functions that cannot be acquired without a - // current context. - InitializeGLBindingsGL(); - InitializeGLBindingsWGL(); - - // If the multi-sample extensions are present, query the api to - // determine the pixel format. - if (wglGetExtensionsStringARB) { - std::string extensions = - std::string(wglGetExtensionsStringARB(intermediate_dc)); - extensions += std::string(" "); - if (extensions.find("WGL_ARB_pixel_format ")) { - 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 (wglChoosePixelFormatARB(intermediate_dc, - pixel_attributes, - pixel_attributes_f, - 1, - &g_multisampled_pixel_format, - &num_formats)) { - break; - } - } - } - } - } - - wglMakeCurrent(intermediate_dc, NULL); - wglDeleteContext(gl_context); - ReleaseDC(g_window, intermediate_dc); - UnregisterClass(reinterpret_cast<wchar_t*>(class_registration), - module_handle); break; - } case kGLImplementationEGLGLES2: if (!GLSurfaceEGL::InitializeOneOff()) { LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed."; @@ -321,114 +93,6 @@ bool GLContext::InitializeOneOff() { return true; } - -std::string BaseWinGLContext::GetExtensions() { - if (wglGetExtensionsStringARB) { - const char* extensions = wglGetExtensionsStringARB(GetDC()); - if (extensions) { - return GLContext::GetExtensions() + " " + extensions; - } - } - - return GLContext::GetExtensions(); -} - -bool NativeViewGLContext::Initialize(bool multisampled) { - // 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)) { - LOG(ERROR) << "Unable to set the pixel format for GL context."; - Destroy(); - return false; - } - - context_ = wglCreateContext(device_context_); - if (!context_) { - LOG(ERROR) << "Failed to create GL context."; - Destroy(); - return false; - } - - if (!MakeCurrent()) { - LOG(ERROR) << "MakeCurrent failed."; - Destroy(); - return false; - } - - if (!InitializeCommon()) { - LOG(ERROR) << "GLContext::InitializeCommon failed."; - Destroy(); - return false; - } - - return true; -} - -void NativeViewGLContext::Destroy() { - if (context_) { - wglDeleteContext(context_); - context_ = NULL; - } - - if (window_ && device_context_) - ReleaseDC(window_, device_context_); - - window_ = NULL; - device_context_ = NULL; -} - -bool NativeViewGLContext::MakeCurrent() { - if (IsCurrent()) { - return true; - } - if (!wglMakeCurrent(device_context_, context_)) { - LOG(ERROR) << "Unable to make gl context current."; - return false; - } - - return true; -} - -bool NativeViewGLContext::IsCurrent() { - return wglGetCurrentDC() == device_context_ && - wglGetCurrentContext() == context_; -} - -bool NativeViewGLContext::IsOffscreen() { - return false; -} - -bool NativeViewGLContext::SwapBuffers() { - DCHECK(device_context_); - return ::SwapBuffers(device_context_) == TRUE; -} - -gfx::Size NativeViewGLContext::GetSize() { - RECT rect; - CHECK(GetClientRect(window_, &rect)); - return gfx::Size(rect.right - rect.left, rect.bottom - rect.top); -} - -void* NativeViewGLContext::GetHandle() { - return context_; -} - -void NativeViewGLContext::SetSwapInterval(int interval) { - DCHECK(IsCurrent()); - if (HasExtension("WGL_EXT_swap_control") && wglSwapIntervalEXT) { - wglSwapIntervalEXT(interval); - } -} - -HDC NativeViewGLContext::GetDC() { - return device_context_; -} - bool OSMesaViewGLContext::Initialize() { // The GL context will render to this window. device_context_ = GetDC(window_); @@ -561,8 +225,14 @@ GLContext* GLContext::CreateViewGLContext(gfx::PluginWindowHandle window, return context.release(); } case kGLImplementationDesktopGL: { - scoped_ptr<NativeViewGLContext> context(new NativeViewGLContext(window)); - if (!context->Initialize(multisampled)) + scoped_ptr<NativeViewGLSurfaceWGL> surface(new NativeViewGLSurfaceWGL( + window)); + if (!surface->Initialize()) + return NULL; + + scoped_ptr<GLContextWGL> context( + new GLContextWGL(surface.release())); + if (!context->Initialize(NULL)) return NULL; return context.release(); @@ -575,129 +245,6 @@ GLContext* GLContext::CreateViewGLContext(gfx::PluginWindowHandle window, } } -bool PbufferGLContext::Initialize(GLContext* shared_context) { - // 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. - if (!wglCreatePbufferARB) { - LOG(ERROR) << "wglCreatePbufferARB not available."; - Destroy(); - return false; - } - const int kNoAttributes[] = { 0 }; - pbuffer_ = wglCreatePbufferARB(display_device_context, - g_regular_pixel_format, - 1, 1, - kNoAttributes); - ::DeleteDC(display_device_context); - if (!pbuffer_) { - LOG(ERROR) << "Unable to create pbuffer."; - Destroy(); - return false; - } - - device_context_ = wglGetPbufferDCARB(pbuffer_); - if (!device_context_) { - LOG(ERROR) << "Unable to get pbuffer device context."; - Destroy(); - return false; - } - - context_ = wglCreateContext(device_context_); - if (!context_) { - LOG(ERROR) << "Failed to create GL context."; - Destroy(); - return false; - } - - if (shared_context) { - if (!wglShareLists( - static_cast<GLContextHandle>(shared_context->GetHandle()), context_)) { - LOG(ERROR) << "Could not share GL contexts."; - Destroy(); - return false; - } - } - - if (!MakeCurrent()) { - LOG(ERROR) << "MakeCurrent failed."; - Destroy(); - return false; - } - - if (!InitializeCommon()) { - LOG(ERROR) << "GLContext::InitializeCommon failed."; - Destroy(); - return false; - } - - return true; -} - -void PbufferGLContext::Destroy() { - if (context_) { - wglDeleteContext(context_); - context_ = NULL; - } - - if (pbuffer_ && device_context_) - wglReleasePbufferDCARB(pbuffer_, device_context_); - - device_context_ = NULL; - - if (pbuffer_) { - wglDestroyPbufferARB(pbuffer_); - pbuffer_ = NULL; - } -} - -bool PbufferGLContext::MakeCurrent() { - if (IsCurrent()) { - return true; - } - if (!wglMakeCurrent(device_context_, context_)) { - LOG(ERROR) << "Unable to make gl context current."; - return false; - } - - return true; -} - -bool PbufferGLContext::IsCurrent() { - return wglGetCurrentDC() == device_context_ && - wglGetCurrentContext() == context_; -} - -bool PbufferGLContext::IsOffscreen() { - return true; -} - -bool PbufferGLContext::SwapBuffers() { - NOTREACHED() << "Attempted to call SwapBuffers on a pbuffer."; - return false; -} - -gfx::Size PbufferGLContext::GetSize() { - NOTREACHED() << "Should not be requesting size of this pbuffer."; - return gfx::Size(1, 1); -} - -void* PbufferGLContext::GetHandle() { - return context_; -} - -void PbufferGLContext::SetSwapInterval(int interval) { - DCHECK(IsCurrent()); - NOTREACHED() << "Attempt to call SetSwapInterval on a PbufferGLContext."; -} - -HDC PbufferGLContext::GetDC() { - return device_context_; -} - GLContext* GLContext::CreateOffscreenGLContext(GLContext* shared_context) { switch (GetGLImplementation()) { case kGLImplementationOSMesaGL: { @@ -720,7 +267,12 @@ GLContext* GLContext::CreateOffscreenGLContext(GLContext* shared_context) { return context.release(); } case kGLImplementationDesktopGL: { - scoped_ptr<PbufferGLContext> context(new PbufferGLContext); + scoped_ptr<PbufferGLSurfaceWGL> surface(new PbufferGLSurfaceWGL( + gfx::Size(1, 1))); + if (!surface->Initialize()) + return NULL; + + scoped_ptr<GLContextWGL> context(new GLContextWGL(surface.release())); if (!context->Initialize(shared_context)) return NULL; diff --git a/ui/gfx/gl/gl_surface.h b/ui/gfx/gl/gl_surface.h index c0ab1e9..811b232 100644 --- a/ui/gfx/gl/gl_surface.h +++ b/ui/gfx/gl/gl_surface.h @@ -39,14 +39,6 @@ class GLSurface { // FBO. Otherwise returns 0. virtual unsigned int GetBackingFrameBufferObject(); -#if !defined(OS_MACOSX) - // Create a surface corresponding to a view. - static GLSurface* CreateViewGLContext(gfx::PluginWindowHandle window); -#endif - - // Create a surface used for offscreen rendering. - static GLSurface* CreateOffscreenGLContext(const gfx::Size& size); - private: DISALLOW_COPY_AND_ASSIGN(GLSurface); }; diff --git a/ui/gfx/gl/gl_surface_wgl.cc b/ui/gfx/gl/gl_surface_wgl.cc new file mode 100644 index 0000000..0218266 --- /dev/null +++ b/ui/gfx/gl/gl_surface_wgl.cc @@ -0,0 +1,297 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/gfx/gl/gl_context_wgl.h" + +#include "base/logging.h" +#include "ui/gfx/gl/gl_bindings.h" +#include "ui/gfx/gl/gl_implementation.h" + +namespace gfx { + +static HWND g_window; +static int g_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. +}; + +static LRESULT CALLBACK IntermediateWindowProc(HWND window, + UINT message, + WPARAM w_param, + LPARAM l_param) { + return ::DefWindowProc(window, message, w_param, l_param); +} + +GLSurfaceWGL::GLSurfaceWGL() { +} + +GLSurfaceWGL::~GLSurfaceWGL() { +} + +bool GLSurfaceWGL::InitializeOneOff() { + static bool initialized = false; + if (initialized) + return true; + + // We must initialize a GL context before we can bind to extension entry + // points. This requires the device context for a window. + 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)) { + LOG(ERROR) << "GetModuleHandleEx failed."; + 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) { + LOG(ERROR) << "RegisterClass failed."; + return false; + } + + g_window = CreateWindow( + reinterpret_cast<wchar_t*>(class_registration), + L"", + WS_OVERLAPPEDWINDOW, + 0, 0, + 100, 100, + NULL, + NULL, + NULL, + NULL); + + if (!g_window) { + UnregisterClass(reinterpret_cast<wchar_t*>(class_registration), + module_handle); + LOG(ERROR) << "CreateWindow failed."; + return false; + } + + HDC temporary_dc = GetDC(g_window); + + g_pixel_format = ChoosePixelFormat(temporary_dc, + &kPixelFormatDescriptor); + + if (g_pixel_format == 0) { + LOG(ERROR) << "Unable to get the pixel format for GL context."; + ReleaseDC(g_window, temporary_dc); + UnregisterClass(reinterpret_cast<wchar_t*>(class_registration), + module_handle); + return false; + } + + if (!SetPixelFormat(temporary_dc, + g_pixel_format, + &kPixelFormatDescriptor)) { + LOG(ERROR) << "Unable to set the pixel format for temporary GL context."; + ReleaseDC(g_window, temporary_dc); + UnregisterClass(reinterpret_cast<wchar_t*>(class_registration), + module_handle); + return false; + } + + // Create a temporary GL context to bind to extension entry points. + HGLRC gl_context = wglCreateContext(temporary_dc); + if (!gl_context) { + LOG(ERROR) << "Failed to create temporary context."; + ReleaseDC(g_window, temporary_dc); + UnregisterClass(reinterpret_cast<wchar_t*>(class_registration), + module_handle); + return false; + } + + if (!wglMakeCurrent(temporary_dc, gl_context)) { + LOG(ERROR) << "Failed to make temporary GL context current."; + wglDeleteContext(gl_context); + ReleaseDC(g_window, temporary_dc); + UnregisterClass(reinterpret_cast<wchar_t*>(class_registration), + module_handle); + return false; + } + + // Get bindings to extension functions that cannot be acquired without a + // current context. + InitializeGLBindingsGL(); + InitializeGLBindingsWGL(); + + wglMakeCurrent(NULL, NULL); + wglDeleteContext(gl_context); + ReleaseDC(g_window, temporary_dc); + UnregisterClass(reinterpret_cast<wchar_t*>(class_registration), + module_handle); + + initialized = true; + return true; +} + +NativeViewGLSurfaceWGL::NativeViewGLSurfaceWGL(gfx::PluginWindowHandle window) + : window_(window), + device_context_(NULL) { + DCHECK(window); +} + +NativeViewGLSurfaceWGL::~NativeViewGLSurfaceWGL() { + Destroy(); +} + +bool NativeViewGLSurfaceWGL::Initialize() { + DCHECK(!device_context_); + + // The GL context will render to this window. + device_context_ = GetDC(window_); + if (!device_context_) { + LOG(ERROR) << "Unable to get device context for window."; + Destroy(); + return false; + } + + if (!SetPixelFormat(device_context_, + g_pixel_format, + &kPixelFormatDescriptor)) { + LOG(ERROR) << "Unable to set the pixel format for GL context."; + Destroy(); + return false; + } + + return true; +} + +void NativeViewGLSurfaceWGL::Destroy() { + if (window_ && device_context_) + ReleaseDC(window_, device_context_); + + window_ = NULL; + device_context_ = NULL; +} + +bool NativeViewGLSurfaceWGL::IsOffscreen() { + return false; +} + +bool NativeViewGLSurfaceWGL::SwapBuffers() { + DCHECK(device_context_); + return ::SwapBuffers(device_context_) == TRUE; +} + +gfx::Size NativeViewGLSurfaceWGL::GetSize() { + RECT rect; + DCHECK(GetClientRect(window_, &rect)); + return gfx::Size(rect.right - rect.left, rect.bottom - rect.top); +} + +void* NativeViewGLSurfaceWGL::GetHandle() { + return device_context_; +} + +PbufferGLSurfaceWGL::PbufferGLSurfaceWGL(const gfx::Size& size) + : size_(size), + device_context_(NULL), + pbuffer_(NULL) { +} + +PbufferGLSurfaceWGL::~PbufferGLSurfaceWGL() { + Destroy(); +} + +bool PbufferGLSurfaceWGL::Initialize() { + DCHECK(!device_context_); + + if (!wglCreatePbufferARB) { + LOG(ERROR) << "wglCreatePbufferARB not available."; + Destroy(); + return false; + } + + // Create a temporary device context for the display. The pbuffer will be + // compatible with it. + HDC temporary_dc = GetDC(g_window); + if (!temporary_dc) { + LOG(ERROR) << "Unable to get device context."; + return false; + } + + const int kNoAttributes[] = { 0 }; + pbuffer_ = wglCreatePbufferARB(temporary_dc, + g_pixel_format, + size_.width(), size_.height(), + kNoAttributes); + + ReleaseDC(g_window, temporary_dc); + + if (!pbuffer_) { + LOG(ERROR) << "Unable to create pbuffer."; + Destroy(); + return false; + } + + device_context_ = wglGetPbufferDCARB(static_cast<HPBUFFERARB>(pbuffer_)); + if (!device_context_) { + LOG(ERROR) << "Unable to get pbuffer device context."; + Destroy(); + return false; + } + + return true; +} + +void PbufferGLSurfaceWGL::Destroy() { + if (pbuffer_ && device_context_) + wglReleasePbufferDCARB(static_cast<HPBUFFERARB>(pbuffer_), device_context_); + + device_context_ = NULL; + + if (pbuffer_) { + wglDestroyPbufferARB(static_cast<HPBUFFERARB>(pbuffer_)); + pbuffer_ = NULL; + } +} + +bool PbufferGLSurfaceWGL::IsOffscreen() { + return true; +} + +bool PbufferGLSurfaceWGL::SwapBuffers() { + NOTREACHED() << "Attempted to call SwapBuffers on a pbuffer."; + return false; +} + +gfx::Size PbufferGLSurfaceWGL::GetSize() { + return size_; +} + +void* PbufferGLSurfaceWGL::GetHandle() { + return device_context_; +} + +} // namespace gfx diff --git a/ui/gfx/gl/gl_surface_wgl.h b/ui/gfx/gl/gl_surface_wgl.h new file mode 100644 index 0000000..d94c565 --- /dev/null +++ b/ui/gfx/gl/gl_surface_wgl.h @@ -0,0 +1,74 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_GFX_GL_GL_SURFACE_WGL_H_ +#define UI_GFX_GL_GL_SURFACE_WGL_H_ + +#include "ui/gfx/gl/gl_surface.h" +#include "ui/gfx/native_widget_types.h" + +namespace gfx { + +// Base interface for WGL surfaces. +class GLSurfaceWGL : public GLSurface { + public: + GLSurfaceWGL(); + virtual ~GLSurfaceWGL(); + + static bool InitializeOneOff(); + private: + DISALLOW_COPY_AND_ASSIGN(GLSurfaceWGL); +}; + +// A surface used to render to a view. +class NativeViewGLSurfaceWGL : public GLSurfaceWGL { + public: + explicit NativeViewGLSurfaceWGL(gfx::PluginWindowHandle window); + virtual ~NativeViewGLSurfaceWGL(); + + // Initializes the GL context. + bool Initialize(); + + // Implement GLSurface. + virtual void Destroy(); + virtual bool IsOffscreen(); + virtual bool SwapBuffers(); + virtual gfx::Size GetSize(); + virtual void* GetHandle(); + + private: + gfx::PluginWindowHandle window_; + HDC device_context_; + + DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceWGL); +}; + + +// A surface used to render to an offscreen pbuffer. +class PbufferGLSurfaceWGL : public GLSurfaceWGL { + public: + explicit PbufferGLSurfaceWGL(const gfx::Size& size); + virtual ~PbufferGLSurfaceWGL(); + + // Initializes the GL context. + bool Initialize(); + + // Implement GLSurface. + virtual void Destroy(); + virtual bool IsOffscreen(); + virtual bool SwapBuffers(); + virtual gfx::Size GetSize(); + virtual void* GetHandle(); + + private: + gfx::Size size_; + HDC device_context_; + void* pbuffer_; + + DISALLOW_COPY_AND_ASSIGN(PbufferGLSurfaceWGL); +}; + +} // namespace gfx + +#endif // UI_GFX_GL_GL_SURFACE_WGL_H_ |