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