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