• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
IntermediateWindowProc(HWND window,UINT message,WPARAM w_param,LPARAM l_param)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:
DisplayWGL()58   DisplayWGL()
59       : module_handle_(0),
60         window_class_(0),
61         window_handle_(0),
62         device_context_(0),
63         pixel_format_(0) {
64   }
65 
~DisplayWGL()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 
Init()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 
window_class() const134   ATOM window_class() const { return window_class_; }
device_context() const135   HDC device_context() const { return device_context_; }
pixel_format() const136   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 
GLSurfaceWGL()148 GLSurfaceWGL::GLSurfaceWGL() {
149 }
150 
~GLSurfaceWGL()151 GLSurfaceWGL::~GLSurfaceWGL() {
152 }
153 
GetDisplay()154 void* GLSurfaceWGL::GetDisplay() {
155   return GetDisplayDC();
156 }
157 
InitializeOneOff()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 
GetDisplayDC()173 HDC GLSurfaceWGL::GetDisplayDC() {
174   return g_display->device_context();
175 }
176 
NativeViewGLSurfaceWGL(gfx::AcceleratedWidget window)177 NativeViewGLSurfaceWGL::NativeViewGLSurfaceWGL(gfx::AcceleratedWidget window)
178     : window_(window),
179       child_window_(NULL),
180       device_context_(NULL) {
181   DCHECK(window);
182 }
183 
~NativeViewGLSurfaceWGL()184 NativeViewGLSurfaceWGL::~NativeViewGLSurfaceWGL() {
185   Destroy();
186 }
187 
Initialize()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 
Destroy()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 
IsOffscreen()247 bool NativeViewGLSurfaceWGL::IsOffscreen() {
248   return false;
249 }
250 
SwapBuffers()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 
GetSize()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 
GetHandle()280 void* NativeViewGLSurfaceWGL::GetHandle() {
281   return device_context_;
282 }
283 
PbufferGLSurfaceWGL(const gfx::Size & size)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 
~PbufferGLSurfaceWGL()294 PbufferGLSurfaceWGL::~PbufferGLSurfaceWGL() {
295   Destroy();
296 }
297 
Initialize()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 
Destroy()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 
IsOffscreen()341 bool PbufferGLSurfaceWGL::IsOffscreen() {
342   return true;
343 }
344 
SwapBuffers()345 bool PbufferGLSurfaceWGL::SwapBuffers() {
346   NOTREACHED() << "Attempted to call SwapBuffers on a pbuffer.";
347   return false;
348 }
349 
GetSize()350 gfx::Size PbufferGLSurfaceWGL::GetSize() {
351   return size_;
352 }
353 
GetHandle()354 void* PbufferGLSurfaceWGL::GetHandle() {
355   return device_context_;
356 }
357 
358 }  // namespace gfx
359