diff options
Diffstat (limited to 'ui/gl/gl_surface_win.cc')
-rw-r--r-- | ui/gl/gl_surface_win.cc | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/ui/gl/gl_surface_win.cc b/ui/gl/gl_surface_win.cc new file mode 100644 index 0000000..ae55568 --- /dev/null +++ b/ui/gl/gl_surface_win.cc @@ -0,0 +1,248 @@ +// Copyright (c) 2012 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/gl/gl_surface.h" + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "third_party/mesa/MesaLib/include/GL/osmesa.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_implementation.h" +#include "ui/gl/gl_surface_egl.h" +#include "ui/gl/gl_surface_osmesa.h" +#include "ui/gl/gl_surface_stub.h" +#include "ui/gl/gl_surface_wgl.h" + +namespace gfx { + +// This OSMesa GL surface can use GDI to swap the contents of the buffer to a +// view. +class NativeViewGLSurfaceOSMesa : public GLSurfaceOSMesa { + public: + explicit NativeViewGLSurfaceOSMesa(gfx::AcceleratedWidget window); + virtual ~NativeViewGLSurfaceOSMesa(); + + // Implement subset of GLSurface. + virtual bool Initialize() OVERRIDE; + virtual void Destroy() OVERRIDE; + virtual bool IsOffscreen() OVERRIDE; + virtual bool SwapBuffers() OVERRIDE; + virtual std::string GetExtensions() OVERRIDE; + virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE; + + private: + gfx::AcceleratedWidget window_; + HDC device_context_; + + DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceOSMesa); +}; + +// Helper routine that does one-off initialization like determining the +// pixel format and initializing the GL bindings. +bool GLSurface::InitializeOneOffInternal() { + switch (GetGLImplementation()) { + case kGLImplementationDesktopGL: + if (!GLSurfaceWGL::InitializeOneOff()) { + LOG(ERROR) << "GLSurfaceWGL::InitializeOneOff failed."; + return false; + } + break; + case kGLImplementationEGLGLES2: + if (!GLSurfaceEGL::InitializeOneOff()) { + LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed."; + return false; + } + break; + } + return true; +} + +NativeViewGLSurfaceOSMesa::NativeViewGLSurfaceOSMesa( + gfx::AcceleratedWidget window) + : GLSurfaceOSMesa(OSMESA_RGBA, gfx::Size(1, 1)), + window_(window), + device_context_(NULL) { + DCHECK(window); +} + +NativeViewGLSurfaceOSMesa::~NativeViewGLSurfaceOSMesa() { + Destroy(); +} + +bool NativeViewGLSurfaceOSMesa::Initialize() { + if (!GLSurfaceOSMesa::Initialize()) + return false; + + device_context_ = GetDC(window_); + return true; +} + +void NativeViewGLSurfaceOSMesa::Destroy() { + if (window_ && device_context_) + ReleaseDC(window_, device_context_); + + device_context_ = NULL; + + GLSurfaceOSMesa::Destroy(); +} + +bool NativeViewGLSurfaceOSMesa::IsOffscreen() { + return false; +} + +bool NativeViewGLSurfaceOSMesa::SwapBuffers() { + DCHECK(device_context_); + + gfx::Size size = GetSize(); + + // Note: negating the height below causes GDI to treat the bitmap data as row + // 0 being at the top. + BITMAPV4HEADER info = { sizeof(BITMAPV4HEADER) }; + info.bV4Width = size.width(); + info.bV4Height = -size.height(); + info.bV4Planes = 1; + info.bV4BitCount = 32; + info.bV4V4Compression = BI_BITFIELDS; + info.bV4RedMask = 0x000000FF; + info.bV4GreenMask = 0x0000FF00; + info.bV4BlueMask = 0x00FF0000; + info.bV4AlphaMask = 0xFF000000; + + // Copy the back buffer to the window's device context. Do not check whether + // StretchDIBits succeeds or not. It will fail if the window has been + // destroyed but it is preferable to allow rendering to silently fail if the + // window is destroyed. This is because the primary application of this + // class of GLContext is for testing and we do not want every GL related ui / + // browser test to become flaky if there is a race condition between GL + // context destruction and window destruction. + StretchDIBits(device_context_, + 0, 0, size.width(), size.height(), + 0, 0, size.width(), size.height(), + GetHandle(), + reinterpret_cast<BITMAPINFO*>(&info), + DIB_RGB_COLORS, + SRCCOPY); + + return true; +} + +std::string NativeViewGLSurfaceOSMesa::GetExtensions() { + std::string extensions = gfx::GLSurfaceOSMesa::GetExtensions(); + extensions += extensions.empty() ? "" : " "; + extensions += "GL_CHROMIUM_post_sub_buffer"; + return extensions; +} + +bool NativeViewGLSurfaceOSMesa::PostSubBuffer( + int x, int y, int width, int height) { + DCHECK(device_context_); + + gfx::Size size = GetSize(); + + // Note: negating the height below causes GDI to treat the bitmap data as row + // 0 being at the top. + BITMAPV4HEADER info = { sizeof(BITMAPV4HEADER) }; + info.bV4Width = size.width(); + info.bV4Height = -size.height(); + info.bV4Planes = 1; + info.bV4BitCount = 32; + info.bV4V4Compression = BI_BITFIELDS; + info.bV4RedMask = 0x000000FF; + info.bV4GreenMask = 0x0000FF00; + info.bV4BlueMask = 0x00FF0000; + info.bV4AlphaMask = 0xFF000000; + + // Copy the back buffer to the window's device context. Do not check whether + // StretchDIBits succeeds or not. It will fail if the window has been + // destroyed but it is preferable to allow rendering to silently fail if the + // window is destroyed. This is because the primary application of this + // class of GLContext is for testing and we do not want every GL related ui / + // browser test to become flaky if there is a race condition between GL + // context destruction and window destruction. + StretchDIBits(device_context_, + x, size.height() - y - height, width, height, + x, y, width, height, + GetHandle(), + reinterpret_cast<BITMAPINFO*>(&info), + DIB_RGB_COLORS, + SRCCOPY); + + return true; +} + +scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface( + bool software, + gfx::AcceleratedWidget window) { + switch (GetGLImplementation()) { + case kGLImplementationOSMesaGL: { + scoped_refptr<GLSurface> surface( + new NativeViewGLSurfaceOSMesa(window)); + if (!surface->Initialize()) + return NULL; + + return surface; + } + case kGLImplementationEGLGLES2: { + scoped_refptr<GLSurface> surface(new NativeViewGLSurfaceEGL(software, + window)); + if (!surface->Initialize()) + return NULL; + + return surface; + } + case kGLImplementationDesktopGL: { + if (software) + return NULL; + scoped_refptr<GLSurface> surface(new NativeViewGLSurfaceWGL( + window)); + if (!surface->Initialize()) + return NULL; + + return surface; + } + case kGLImplementationMockGL: + return new GLSurfaceStub; + default: + NOTREACHED(); + return NULL; + } +} + +scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface( + bool software, + const gfx::Size& size) { + switch (GetGLImplementation()) { + case kGLImplementationOSMesaGL: { + scoped_refptr<GLSurface> surface(new GLSurfaceOSMesa(OSMESA_RGBA, + size)); + if (!surface->Initialize()) + return NULL; + + return surface; + } + case kGLImplementationEGLGLES2: { + scoped_refptr<GLSurface> surface(new PbufferGLSurfaceEGL(software, size)); + if (!surface->Initialize()) + return NULL; + + return surface; + } + case kGLImplementationDesktopGL: { + if (software) + return NULL; + scoped_refptr<GLSurface> surface(new PbufferGLSurfaceWGL(size)); + if (!surface->Initialize()) + return NULL; + + return surface; + } + case kGLImplementationMockGL: + return new GLSurfaceStub; + default: + NOTREACHED(); + return NULL; + } +} + +} // namespace gfx |