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