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