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.
5 #include "ui/gl/gl_surface_wgl.h"
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"
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.
27 0, // No accumulation buffer.
28 0, 0, 0, 0, // Ignore accumulation bits.
30 0, // no stencil buffer.
32 PFD_MAIN_PLANE
, // Main drawing plane (not overlay).
34 0, 0, 0, // Layer masks ignored.
37 LRESULT CALLBACK
IntermediateWindowProc(HWND window
,
43 // Prevent windows from erasing the background.
46 // Do not paint anything.
48 if (BeginPaint(window
, &paint
))
49 EndPaint(window
, &paint
);
52 return DefWindowProc(window
, message
, w_param
, l_param
);
68 DestroyWindow(window_handle_
);
70 UnregisterClass(reinterpret_cast<wchar_t*>(window_class_
),
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
),
81 LOG(ERROR
) << "GetModuleHandleEx failed.";
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
);
98 LOG(ERROR
) << "RegisterClass failed.";
102 window_handle_
= CreateWindowEx(WS_EX_NOPARENTNOTIFY
,
103 reinterpret_cast<wchar_t*>(window_class_
),
114 if (!window_handle_
) {
115 LOG(ERROR
) << "CreateWindow failed.";
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.";
126 if (!SetPixelFormat(device_context_
,
128 &kPixelFormatDescriptor
)) {
129 LOG(ERROR
) << "Unable to set the pixel format for temporary GL context.";
136 ATOM
window_class() const { return window_class_
; }
137 HDC
device_context() const { return device_context_
; }
138 int pixel_format() const { return pixel_format_
; }
141 HINSTANCE module_handle_
;
147 DisplayWGL
* g_display
;
150 GLSurfaceWGL::GLSurfaceWGL() {
153 GLSurfaceWGL::~GLSurfaceWGL() {
156 void* GLSurfaceWGL::GetDisplay() {
157 return GetDisplayDC();
160 bool GLSurfaceWGL::InitializeOneOff() {
161 static bool initialized
= false;
165 DCHECK(g_display
== NULL
);
166 scoped_ptr
<DisplayWGL
> wgl_display(new DisplayWGL
);
167 if (!wgl_display
->Init())
170 g_display
= wgl_display
.release();
175 void GLSurfaceWGL::InitializeOneOffForTesting() {
176 if (g_display
== NULL
) {
177 g_display
= new DisplayWGL
;
181 HDC
GLSurfaceWGL::GetDisplayDC() {
182 return g_display
->device_context();
185 NativeViewGLSurfaceWGL::NativeViewGLSurfaceWGL(gfx::AcceleratedWidget window
)
186 : window_(window
), child_window_(NULL
), device_context_(NULL
) {
190 NativeViewGLSurfaceWGL::~NativeViewGLSurfaceWGL() {
194 bool NativeViewGLSurfaceWGL::Initialize() {
195 DCHECK(!device_context_
);
198 if (!GetClientRect(window_
, &rect
)) {
199 LOG(ERROR
) << "GetClientRect failed.\n";
204 // Create a child window. WGL has problems using a window handle owned by
207 CreateWindowEx(WS_EX_NOPARENTNOTIFY
,
208 reinterpret_cast<wchar_t*>(g_display
->window_class()),
210 WS_CHILDWINDOW
| WS_DISABLED
| WS_VISIBLE
,
213 rect
.right
- rect
.left
,
214 rect
.bottom
- rect
.top
,
219 if (!child_window_
) {
220 LOG(ERROR
) << "CreateWindow failed.\n";
225 // The GL context will render to this window.
226 device_context_
= GetDC(child_window_
);
227 if (!device_context_
) {
228 LOG(ERROR
) << "Unable to get device context for window.";
233 if (!SetPixelFormat(device_context_
,
234 g_display
->pixel_format(),
235 &kPixelFormatDescriptor
)) {
236 LOG(ERROR
) << "Unable to set the pixel format for GL context.";
244 void NativeViewGLSurfaceWGL::Destroy() {
245 if (child_window_
&& device_context_
)
246 ReleaseDC(child_window_
, device_context_
);
249 DestroyWindow(child_window_
);
251 child_window_
= NULL
;
252 device_context_
= NULL
;
255 bool NativeViewGLSurfaceWGL::IsOffscreen() {
259 gfx::SwapResult
NativeViewGLSurfaceWGL::SwapBuffers() {
260 TRACE_EVENT2("gpu", "NativeViewGLSurfaceWGL:RealSwapBuffers",
261 "width", GetSize().width(),
262 "height", GetSize().height());
264 // Resize the child window to match the parent before swapping. Do not repaint
267 if (!GetClientRect(window_
, &rect
))
268 return gfx::SwapResult::SWAP_FAILED
;
269 if (!MoveWindow(child_window_
,
272 rect
.right
- rect
.left
,
273 rect
.bottom
- rect
.top
,
275 return gfx::SwapResult::SWAP_FAILED
;
278 DCHECK(device_context_
);
279 return ::SwapBuffers(device_context_
) == TRUE
? gfx::SwapResult::SWAP_ACK
280 : gfx::SwapResult::SWAP_FAILED
;
283 gfx::Size
NativeViewGLSurfaceWGL::GetSize() {
285 BOOL result
= GetClientRect(child_window_
, &rect
);
287 return gfx::Size(rect
.right
- rect
.left
, rect
.bottom
- rect
.top
);
290 void* NativeViewGLSurfaceWGL::GetHandle() {
291 return device_context_
;
294 PbufferGLSurfaceWGL::PbufferGLSurfaceWGL(const gfx::Size
& size
)
296 device_context_(NULL
),
298 // Some implementations of Pbuffer do not support having a 0 size. For such
299 // cases use a (1, 1) surface.
300 if (size_
.GetArea() == 0)
304 PbufferGLSurfaceWGL::~PbufferGLSurfaceWGL() {
308 bool PbufferGLSurfaceWGL::Initialize() {
309 DCHECK(!device_context_
);
311 if (!gfx::g_driver_wgl
.fn
.wglCreatePbufferARBFn
) {
312 LOG(ERROR
) << "wglCreatePbufferARB not available.";
317 const int kNoAttributes
[] = { 0 };
318 pbuffer_
= wglCreatePbufferARB(g_display
->device_context(),
319 g_display
->pixel_format(),
320 size_
.width(), size_
.height(),
324 LOG(ERROR
) << "Unable to create pbuffer.";
329 device_context_
= wglGetPbufferDCARB(static_cast<HPBUFFERARB
>(pbuffer_
));
330 if (!device_context_
) {
331 LOG(ERROR
) << "Unable to get pbuffer device context.";
339 void PbufferGLSurfaceWGL::Destroy() {
340 if (pbuffer_
&& device_context_
)
341 wglReleasePbufferDCARB(static_cast<HPBUFFERARB
>(pbuffer_
), device_context_
);
343 device_context_
= NULL
;
346 wglDestroyPbufferARB(static_cast<HPBUFFERARB
>(pbuffer_
));
351 bool PbufferGLSurfaceWGL::IsOffscreen() {
355 gfx::SwapResult
PbufferGLSurfaceWGL::SwapBuffers() {
356 NOTREACHED() << "Attempted to call SwapBuffers on a pbuffer.";
357 return gfx::SwapResult::SWAP_FAILED
;
360 gfx::Size
PbufferGLSurfaceWGL::GetSize() {
364 void* PbufferGLSurfaceWGL::GetHandle() {
365 return device_context_
;