Home | History | Annotate | Download | only in gl
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "ui/gl/gl_surface_wgl.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "ui/gl/gl_bindings.h"
     10 #include "ui/gl/gl_gl_api_implementation.h"
     11 #include "ui/gl/gl_wgl_api_implementation.h"
     12 
     13 namespace gfx {
     14 
     15 namespace {
     16 const PIXELFORMATDESCRIPTOR kPixelFormatDescriptor = {
     17   sizeof(kPixelFormatDescriptor),    // Size of structure.
     18   1,                       // Default version.
     19   PFD_DRAW_TO_WINDOW |     // Window drawing support.
     20   PFD_SUPPORT_OPENGL |     // OpenGL support.
     21   PFD_DOUBLEBUFFER,        // Double buffering support (not stereo).
     22   PFD_TYPE_RGBA,           // RGBA color mode (not indexed).
     23   24,                      // 24 bit color mode.
     24   0, 0, 0, 0, 0, 0,        // Don't set RGB bits & shifts.
     25   8, 0,                    // 8 bit alpha
     26   0,                       // No accumulation buffer.
     27   0, 0, 0, 0,              // Ignore accumulation bits.
     28   0,                       // no z-buffer.
     29   0,                       // no stencil buffer.
     30   0,                       // No aux buffer.
     31   PFD_MAIN_PLANE,          // Main drawing plane (not overlay).
     32   0,                       // Reserved.
     33   0, 0, 0,                 // Layer masks ignored.
     34 };
     35 
     36 LRESULT CALLBACK IntermediateWindowProc(HWND window,
     37                                         UINT message,
     38                                         WPARAM w_param,
     39                                         LPARAM l_param) {
     40   switch (message) {
     41     case WM_ERASEBKGND:
     42       // Prevent windows from erasing the background.
     43       return 1;
     44     case WM_PAINT:
     45       // Do not paint anything.
     46       PAINTSTRUCT paint;
     47       if (BeginPaint(window, &paint))
     48         EndPaint(window, &paint);
     49       return 0;
     50     default:
     51       return DefWindowProc(window, message, w_param, l_param);
     52   }
     53 }
     54 
     55 class DisplayWGL {
     56  public:
     57   DisplayWGL()
     58       : module_handle_(0),
     59         window_class_(0),
     60         window_handle_(0),
     61         device_context_(0),
     62         pixel_format_(0) {
     63   }
     64 
     65   ~DisplayWGL() {
     66     if (window_handle_)
     67       DestroyWindow(window_handle_);
     68     if (window_class_)
     69       UnregisterClass(reinterpret_cast<wchar_t*>(window_class_),
     70                       module_handle_);
     71   }
     72 
     73   bool Init() {
     74     // We must initialize a GL context before we can bind to extension entry
     75     // points. This requires the device context for a window.
     76     if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT |
     77                            GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
     78                            reinterpret_cast<wchar_t*>(IntermediateWindowProc),
     79                            &module_handle_)) {
     80       LOG(ERROR) << "GetModuleHandleEx failed.";
     81       return false;
     82     }
     83 
     84     WNDCLASS intermediate_class;
     85     intermediate_class.style = CS_OWNDC;
     86     intermediate_class.lpfnWndProc = IntermediateWindowProc;
     87     intermediate_class.cbClsExtra = 0;
     88     intermediate_class.cbWndExtra = 0;
     89     intermediate_class.hInstance = module_handle_;
     90     intermediate_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
     91     intermediate_class.hCursor = LoadCursor(NULL, IDC_ARROW);
     92     intermediate_class.hbrBackground = NULL;
     93     intermediate_class.lpszMenuName = NULL;
     94     intermediate_class.lpszClassName = L"Intermediate GL Window";
     95     window_class_ = RegisterClass(&intermediate_class);
     96     if (!window_class_) {
     97       LOG(ERROR) << "RegisterClass failed.";
     98       return false;
     99     }
    100 
    101     window_handle_ = CreateWindow(
    102         reinterpret_cast<wchar_t*>(window_class_),
    103         L"",
    104         WS_OVERLAPPEDWINDOW,
    105         0, 0,
    106         100, 100,
    107         NULL,
    108         NULL,
    109         NULL,
    110         NULL);
    111     if (!window_handle_) {
    112       LOG(ERROR) << "CreateWindow failed.";
    113       return false;
    114     }
    115 
    116     device_context_ = GetDC(window_handle_);
    117     pixel_format_ = ChoosePixelFormat(device_context_,
    118                                       &kPixelFormatDescriptor);
    119     if (pixel_format_ == 0) {
    120       LOG(ERROR) << "Unable to get the pixel format for GL context.";
    121       return false;
    122     }
    123     if (!SetPixelFormat(device_context_,
    124                         pixel_format_,
    125                         &kPixelFormatDescriptor)) {
    126       LOG(ERROR) << "Unable to set the pixel format for temporary GL context.";
    127       return false;
    128     }
    129 
    130     return true;
    131   }
    132 
    133   ATOM window_class() const { return window_class_; }
    134   HDC device_context() const { return device_context_; }
    135   int pixel_format() const { return pixel_format_; }
    136 
    137  private:
    138   HINSTANCE module_handle_;
    139   ATOM window_class_;
    140   HWND window_handle_;
    141   HDC device_context_;
    142   int pixel_format_;
    143 };
    144 DisplayWGL* g_display;
    145 }  // namespace
    146 
    147 GLSurfaceWGL::GLSurfaceWGL() {
    148 }
    149 
    150 GLSurfaceWGL::~GLSurfaceWGL() {
    151 }
    152 
    153 void* GLSurfaceWGL::GetDisplay() {
    154   return GetDisplayDC();
    155 }
    156 
    157 bool GLSurfaceWGL::InitializeOneOff() {
    158   static bool initialized = false;
    159   if (initialized)
    160     return true;
    161 
    162   DCHECK(g_display == NULL);
    163   scoped_ptr<DisplayWGL> wgl_display(new DisplayWGL);
    164   if (!wgl_display->Init())
    165     return false;
    166 
    167   // Create a temporary GL context to bind to extension entry points.
    168   HGLRC gl_context = wglCreateContext(wgl_display->device_context());
    169   if (!gl_context) {
    170     LOG(ERROR) << "Failed to create temporary context.";
    171     return false;
    172   }
    173   if (!wglMakeCurrent(wgl_display->device_context(), gl_context)) {
    174     LOG(ERROR) << "Failed to make temporary GL context current.";
    175     wglDeleteContext(gl_context);
    176     return false;
    177   }
    178   // Get bindings to extension functions that cannot be acquired without a
    179   // current context.
    180   InitializeGLBindingsGL();
    181   InitializeGLBindingsWGL();
    182 
    183   wglMakeCurrent(NULL, NULL);
    184   wglDeleteContext(gl_context);
    185 
    186   g_display = wgl_display.release();
    187   initialized = true;
    188   return true;
    189 }
    190 
    191 HDC GLSurfaceWGL::GetDisplayDC() {
    192   return g_display->device_context();
    193 }
    194 
    195 NativeViewGLSurfaceWGL::NativeViewGLSurfaceWGL(gfx::AcceleratedWidget window)
    196     : window_(window),
    197       child_window_(NULL),
    198       device_context_(NULL) {
    199   DCHECK(window);
    200 }
    201 
    202 NativeViewGLSurfaceWGL::~NativeViewGLSurfaceWGL() {
    203   Destroy();
    204 }
    205 
    206 bool NativeViewGLSurfaceWGL::Initialize() {
    207   DCHECK(!device_context_);
    208 
    209   RECT rect;
    210   if (!GetClientRect(window_, &rect)) {
    211     LOG(ERROR) << "GetClientRect failed.\n";
    212     Destroy();
    213     return false;
    214   }
    215 
    216   // Create a child window. WGL has problems using a window handle owned by
    217   // another process.
    218   child_window_ = CreateWindow(
    219       reinterpret_cast<wchar_t*>(g_display->window_class()),
    220       L"",
    221       WS_CHILDWINDOW | WS_DISABLED | WS_VISIBLE,
    222       0, 0,
    223       rect.right - rect.left,
    224       rect.bottom - rect.top,
    225       window_,
    226       NULL,
    227       NULL,
    228       NULL);
    229   if (!child_window_) {
    230     LOG(ERROR) << "CreateWindow failed.\n";
    231     Destroy();
    232     return false;
    233   }
    234 
    235   // The GL context will render to this window.
    236   device_context_ = GetDC(child_window_);
    237   if (!device_context_) {
    238     LOG(ERROR) << "Unable to get device context for window.";
    239     Destroy();
    240     return false;
    241   }
    242 
    243   if (!SetPixelFormat(device_context_,
    244                       g_display->pixel_format(),
    245                       &kPixelFormatDescriptor)) {
    246     LOG(ERROR) << "Unable to set the pixel format for GL context.";
    247     Destroy();
    248     return false;
    249   }
    250 
    251   return true;
    252 }
    253 
    254 void NativeViewGLSurfaceWGL::Destroy() {
    255   if (child_window_ && device_context_)
    256     ReleaseDC(child_window_, device_context_);
    257 
    258   if (child_window_)
    259     DestroyWindow(child_window_);
    260 
    261   child_window_ = NULL;
    262   device_context_ = NULL;
    263 }
    264 
    265 bool NativeViewGLSurfaceWGL::IsOffscreen() {
    266   return false;
    267 }
    268 
    269 bool NativeViewGLSurfaceWGL::SwapBuffers() {
    270   // Resize the child window to match the parent before swapping. Do not repaint
    271   // it as it moves.
    272   RECT rect;
    273   if (!GetClientRect(window_, &rect))
    274     return false;
    275   if (!MoveWindow(child_window_,
    276                   0, 0,
    277                   rect.right - rect.left,
    278                   rect.bottom - rect.top,
    279                   FALSE)) {
    280     return false;
    281   }
    282 
    283   DCHECK(device_context_);
    284   return ::SwapBuffers(device_context_) == TRUE;
    285 }
    286 
    287 gfx::Size NativeViewGLSurfaceWGL::GetSize() {
    288   RECT rect;
    289   BOOL result = GetClientRect(child_window_, &rect);
    290   DCHECK(result);
    291   return gfx::Size(rect.right - rect.left, rect.bottom - rect.top);
    292 }
    293 
    294 void* NativeViewGLSurfaceWGL::GetHandle() {
    295   return device_context_;
    296 }
    297 
    298 PbufferGLSurfaceWGL::PbufferGLSurfaceWGL(const gfx::Size& size)
    299     : size_(size),
    300       device_context_(NULL),
    301       pbuffer_(NULL) {
    302 }
    303 
    304 PbufferGLSurfaceWGL::~PbufferGLSurfaceWGL() {
    305   Destroy();
    306 }
    307 
    308 bool PbufferGLSurfaceWGL::Initialize() {
    309   DCHECK(!device_context_);
    310 
    311   if (!gfx::g_driver_wgl.fn.wglCreatePbufferARBFn) {
    312     LOG(ERROR) << "wglCreatePbufferARB not available.";
    313     Destroy();
    314     return false;
    315   }
    316 
    317   const int kNoAttributes[] = { 0 };
    318   pbuffer_ = wglCreatePbufferARB(g_display->device_context(),
    319                                  g_display->pixel_format(),
    320                                  size_.width(), size_.height(),
    321                                  kNoAttributes);
    322 
    323   if (!pbuffer_) {
    324     LOG(ERROR) << "Unable to create pbuffer.";
    325     Destroy();
    326     return false;
    327   }
    328 
    329   device_context_ = wglGetPbufferDCARB(static_cast<HPBUFFERARB>(pbuffer_));
    330   if (!device_context_) {
    331     LOG(ERROR) << "Unable to get pbuffer device context.";
    332     Destroy();
    333     return false;
    334   }
    335 
    336   return true;
    337 }
    338 
    339 void PbufferGLSurfaceWGL::Destroy() {
    340   if (pbuffer_ && device_context_)
    341     wglReleasePbufferDCARB(static_cast<HPBUFFERARB>(pbuffer_), device_context_);
    342 
    343   device_context_ = NULL;
    344 
    345   if (pbuffer_) {
    346     wglDestroyPbufferARB(static_cast<HPBUFFERARB>(pbuffer_));
    347     pbuffer_ = NULL;
    348   }
    349 }
    350 
    351 bool PbufferGLSurfaceWGL::IsOffscreen() {
    352   return true;
    353 }
    354 
    355 bool PbufferGLSurfaceWGL::SwapBuffers() {
    356   NOTREACHED() << "Attempted to call SwapBuffers on a pbuffer.";
    357   return false;
    358 }
    359 
    360 gfx::Size PbufferGLSurfaceWGL::GetSize() {
    361   return size_;
    362 }
    363 
    364 void* PbufferGLSurfaceWGL::GetHandle() {
    365   return device_context_;
    366 }
    367 
    368 }  // namespace gfx
    369