| OLD | NEW |
| (Empty) |
| 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 "base/trace_event/trace_event.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_ = CreateWindowEx(WS_EX_NOPARENTNOTIFY, | |
| 103 reinterpret_cast<wchar_t*>(window_class_), | |
| 104 L"", | |
| 105 WS_OVERLAPPEDWINDOW, | |
| 106 0, | |
| 107 0, | |
| 108 100, | |
| 109 100, | |
| 110 NULL, | |
| 111 NULL, | |
| 112 NULL, | |
| 113 NULL); | |
| 114 if (!window_handle_) { | |
| 115 LOG(ERROR) << "CreateWindow failed."; | |
| 116 return false; | |
| 117 } | |
| 118 | |
| 119 device_context_ = GetDC(window_handle_); | |
| 120 pixel_format_ = ChoosePixelFormat(device_context_, | |
| 121 &kPixelFormatDescriptor); | |
| 122 if (pixel_format_ == 0) { | |
| 123 LOG(ERROR) << "Unable to get the pixel format for GL context."; | |
| 124 return false; | |
| 125 } | |
| 126 if (!SetPixelFormat(device_context_, | |
| 127 pixel_format_, | |
| 128 &kPixelFormatDescriptor)) { | |
| 129 LOG(ERROR) << "Unable to set the pixel format for temporary GL context."; | |
| 130 return false; | |
| 131 } | |
| 132 | |
| 133 return true; | |
| 134 } | |
| 135 | |
| 136 ATOM window_class() const { return window_class_; } | |
| 137 HDC device_context() const { return device_context_; } | |
| 138 int pixel_format() const { return pixel_format_; } | |
| 139 | |
| 140 private: | |
| 141 HINSTANCE module_handle_; | |
| 142 ATOM window_class_; | |
| 143 HWND window_handle_; | |
| 144 HDC device_context_; | |
| 145 int pixel_format_; | |
| 146 }; | |
| 147 DisplayWGL* g_display; | |
| 148 } // namespace | |
| 149 | |
| 150 GLSurfaceWGL::GLSurfaceWGL() { | |
| 151 } | |
| 152 | |
| 153 GLSurfaceWGL::~GLSurfaceWGL() { | |
| 154 } | |
| 155 | |
| 156 void* GLSurfaceWGL::GetDisplay() { | |
| 157 return GetDisplayDC(); | |
| 158 } | |
| 159 | |
| 160 bool GLSurfaceWGL::InitializeOneOff() { | |
| 161 static bool initialized = false; | |
| 162 if (initialized) | |
| 163 return true; | |
| 164 | |
| 165 DCHECK(g_display == NULL); | |
| 166 scoped_ptr<DisplayWGL> wgl_display(new DisplayWGL); | |
| 167 if (!wgl_display->Init()) | |
| 168 return false; | |
| 169 | |
| 170 g_display = wgl_display.release(); | |
| 171 initialized = true; | |
| 172 return true; | |
| 173 } | |
| 174 | |
| 175 HDC GLSurfaceWGL::GetDisplayDC() { | |
| 176 return g_display->device_context(); | |
| 177 } | |
| 178 | |
| 179 NativeViewGLSurfaceWGL::NativeViewGLSurfaceWGL(gfx::AcceleratedWidget window) | |
| 180 : window_(window), child_window_(NULL), 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_ = | |
| 201 CreateWindowEx(WS_EX_NOPARENTNOTIFY, | |
| 202 reinterpret_cast<wchar_t*>(g_display->window_class()), | |
| 203 L"", | |
| 204 WS_CHILDWINDOW | WS_DISABLED | WS_VISIBLE, | |
| 205 0, | |
| 206 0, | |
| 207 rect.right - rect.left, | |
| 208 rect.bottom - rect.top, | |
| 209 window_, | |
| 210 NULL, | |
| 211 NULL, | |
| 212 NULL); | |
| 213 if (!child_window_) { | |
| 214 LOG(ERROR) << "CreateWindow failed.\n"; | |
| 215 Destroy(); | |
| 216 return false; | |
| 217 } | |
| 218 | |
| 219 // The GL context will render to this window. | |
| 220 device_context_ = GetDC(child_window_); | |
| 221 if (!device_context_) { | |
| 222 LOG(ERROR) << "Unable to get device context for window."; | |
| 223 Destroy(); | |
| 224 return false; | |
| 225 } | |
| 226 | |
| 227 if (!SetPixelFormat(device_context_, | |
| 228 g_display->pixel_format(), | |
| 229 &kPixelFormatDescriptor)) { | |
| 230 LOG(ERROR) << "Unable to set the pixel format for GL context."; | |
| 231 Destroy(); | |
| 232 return false; | |
| 233 } | |
| 234 | |
| 235 return true; | |
| 236 } | |
| 237 | |
| 238 void NativeViewGLSurfaceWGL::Destroy() { | |
| 239 if (child_window_ && device_context_) | |
| 240 ReleaseDC(child_window_, device_context_); | |
| 241 | |
| 242 if (child_window_) | |
| 243 DestroyWindow(child_window_); | |
| 244 | |
| 245 child_window_ = NULL; | |
| 246 device_context_ = NULL; | |
| 247 } | |
| 248 | |
| 249 bool NativeViewGLSurfaceWGL::IsOffscreen() { | |
| 250 return false; | |
| 251 } | |
| 252 | |
| 253 bool NativeViewGLSurfaceWGL::SwapBuffers() { | |
| 254 TRACE_EVENT2("gpu", "NativeViewGLSurfaceWGL:RealSwapBuffers", | |
| 255 "width", GetSize().width(), | |
| 256 "height", GetSize().height()); | |
| 257 | |
| 258 // Resize the child window to match the parent before swapping. Do not repaint | |
| 259 // it as it moves. | |
| 260 RECT rect; | |
| 261 if (!GetClientRect(window_, &rect)) | |
| 262 return false; | |
| 263 if (!MoveWindow(child_window_, | |
| 264 0, | |
| 265 0, | |
| 266 rect.right - rect.left, | |
| 267 rect.bottom - rect.top, | |
| 268 FALSE)) { | |
| 269 return false; | |
| 270 } | |
| 271 | |
| 272 DCHECK(device_context_); | |
| 273 return ::SwapBuffers(device_context_) == TRUE; | |
| 274 } | |
| 275 | |
| 276 gfx::Size NativeViewGLSurfaceWGL::GetSize() { | |
| 277 RECT rect; | |
| 278 BOOL result = GetClientRect(child_window_, &rect); | |
| 279 DCHECK(result); | |
| 280 return gfx::Size(rect.right - rect.left, rect.bottom - rect.top); | |
| 281 } | |
| 282 | |
| 283 void* NativeViewGLSurfaceWGL::GetHandle() { | |
| 284 return device_context_; | |
| 285 } | |
| 286 | |
| 287 PbufferGLSurfaceWGL::PbufferGLSurfaceWGL(const gfx::Size& size) | |
| 288 : size_(size), | |
| 289 device_context_(NULL), | |
| 290 pbuffer_(NULL) { | |
| 291 // Some implementations of Pbuffer do not support having a 0 size. For such | |
| 292 // cases use a (1, 1) surface. | |
| 293 if (size_.GetArea() == 0) | |
| 294 size_.SetSize(1, 1); | |
| 295 } | |
| 296 | |
| 297 PbufferGLSurfaceWGL::~PbufferGLSurfaceWGL() { | |
| 298 Destroy(); | |
| 299 } | |
| 300 | |
| 301 bool PbufferGLSurfaceWGL::Initialize() { | |
| 302 DCHECK(!device_context_); | |
| 303 | |
| 304 if (!gfx::g_driver_wgl.fn.wglCreatePbufferARBFn) { | |
| 305 LOG(ERROR) << "wglCreatePbufferARB not available."; | |
| 306 Destroy(); | |
| 307 return false; | |
| 308 } | |
| 309 | |
| 310 const int kNoAttributes[] = { 0 }; | |
| 311 pbuffer_ = wglCreatePbufferARB(g_display->device_context(), | |
| 312 g_display->pixel_format(), | |
| 313 size_.width(), size_.height(), | |
| 314 kNoAttributes); | |
| 315 | |
| 316 if (!pbuffer_) { | |
| 317 LOG(ERROR) << "Unable to create pbuffer."; | |
| 318 Destroy(); | |
| 319 return false; | |
| 320 } | |
| 321 | |
| 322 device_context_ = wglGetPbufferDCARB(static_cast<HPBUFFERARB>(pbuffer_)); | |
| 323 if (!device_context_) { | |
| 324 LOG(ERROR) << "Unable to get pbuffer device context."; | |
| 325 Destroy(); | |
| 326 return false; | |
| 327 } | |
| 328 | |
| 329 return true; | |
| 330 } | |
| 331 | |
| 332 void PbufferGLSurfaceWGL::Destroy() { | |
| 333 if (pbuffer_ && device_context_) | |
| 334 wglReleasePbufferDCARB(static_cast<HPBUFFERARB>(pbuffer_), device_context_); | |
| 335 | |
| 336 device_context_ = NULL; | |
| 337 | |
| 338 if (pbuffer_) { | |
| 339 wglDestroyPbufferARB(static_cast<HPBUFFERARB>(pbuffer_)); | |
| 340 pbuffer_ = NULL; | |
| 341 } | |
| 342 } | |
| 343 | |
| 344 bool PbufferGLSurfaceWGL::IsOffscreen() { | |
| 345 return true; | |
| 346 } | |
| 347 | |
| 348 bool PbufferGLSurfaceWGL::SwapBuffers() { | |
| 349 NOTREACHED() << "Attempted to call SwapBuffers on a pbuffer."; | |
| 350 return false; | |
| 351 } | |
| 352 | |
| 353 gfx::Size PbufferGLSurfaceWGL::GetSize() { | |
| 354 return size_; | |
| 355 } | |
| 356 | |
| 357 void* PbufferGLSurfaceWGL::GetHandle() { | |
| 358 return device_context_; | |
| 359 } | |
| 360 | |
| 361 } // namespace gfx | |
| OLD | NEW |