Run Surface draw callback after aggregation and before draw.
[chromium-blink-merge.git] / ui / gl / gl_surface_wgl.cc
blob66cef266fcf09895c051a5ed2013b8f2db6a796c
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/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"
14 namespace gfx {
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.
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);
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) {
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_);
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;
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;
102 window_handle_ = CreateWindowEx(WS_EX_NOPARENTNOTIFY,
103 reinterpret_cast<wchar_t*>(window_class_),
104 L"",
105 WS_OVERLAPPEDWINDOW,
108 100,
109 100,
110 NULL,
111 NULL,
112 NULL,
113 NULL);
114 if (!window_handle_) {
115 LOG(ERROR) << "CreateWindow failed.";
116 return false;
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;
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;
133 return true;
136 ATOM window_class() const { return window_class_; }
137 HDC device_context() const { return device_context_; }
138 int pixel_format() const { return pixel_format_; }
140 private:
141 HINSTANCE module_handle_;
142 ATOM window_class_;
143 HWND window_handle_;
144 HDC device_context_;
145 int pixel_format_;
147 DisplayWGL* g_display;
148 } // namespace
150 GLSurfaceWGL::GLSurfaceWGL() {
153 GLSurfaceWGL::~GLSurfaceWGL() {
156 void* GLSurfaceWGL::GetDisplay() {
157 return GetDisplayDC();
160 bool GLSurfaceWGL::InitializeOneOff() {
161 static bool initialized = false;
162 if (initialized)
163 return true;
165 DCHECK(g_display == NULL);
166 scoped_ptr<DisplayWGL> wgl_display(new DisplayWGL);
167 if (!wgl_display->Init())
168 return false;
170 g_display = wgl_display.release();
171 initialized = true;
172 return true;
175 HDC GLSurfaceWGL::GetDisplayDC() {
176 return g_display->device_context();
179 NativeViewGLSurfaceWGL::NativeViewGLSurfaceWGL(gfx::AcceleratedWidget window)
180 : window_(window), child_window_(NULL), device_context_(NULL) {
181 DCHECK(window);
184 NativeViewGLSurfaceWGL::~NativeViewGLSurfaceWGL() {
185 Destroy();
188 bool NativeViewGLSurfaceWGL::Initialize() {
189 DCHECK(!device_context_);
191 RECT rect;
192 if (!GetClientRect(window_, &rect)) {
193 LOG(ERROR) << "GetClientRect failed.\n";
194 Destroy();
195 return false;
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,
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;
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;
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;
235 return true;
238 void NativeViewGLSurfaceWGL::Destroy() {
239 if (child_window_ && device_context_)
240 ReleaseDC(child_window_, device_context_);
242 if (child_window_)
243 DestroyWindow(child_window_);
245 child_window_ = NULL;
246 device_context_ = NULL;
249 bool NativeViewGLSurfaceWGL::IsOffscreen() {
250 return false;
253 bool NativeViewGLSurfaceWGL::SwapBuffers() {
254 TRACE_EVENT2("gpu", "NativeViewGLSurfaceWGL:RealSwapBuffers",
255 "width", GetSize().width(),
256 "height", GetSize().height());
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_,
266 rect.right - rect.left,
267 rect.bottom - rect.top,
268 FALSE)) {
269 return false;
272 DCHECK(device_context_);
273 return ::SwapBuffers(device_context_) == TRUE;
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);
283 void* NativeViewGLSurfaceWGL::GetHandle() {
284 return device_context_;
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);
297 PbufferGLSurfaceWGL::~PbufferGLSurfaceWGL() {
298 Destroy();
301 bool PbufferGLSurfaceWGL::Initialize() {
302 DCHECK(!device_context_);
304 if (!gfx::g_driver_wgl.fn.wglCreatePbufferARBFn) {
305 LOG(ERROR) << "wglCreatePbufferARB not available.";
306 Destroy();
307 return false;
310 const int kNoAttributes[] = { 0 };
311 pbuffer_ = wglCreatePbufferARB(g_display->device_context(),
312 g_display->pixel_format(),
313 size_.width(), size_.height(),
314 kNoAttributes);
316 if (!pbuffer_) {
317 LOG(ERROR) << "Unable to create pbuffer.";
318 Destroy();
319 return false;
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;
329 return true;
332 void PbufferGLSurfaceWGL::Destroy() {
333 if (pbuffer_ && device_context_)
334 wglReleasePbufferDCARB(static_cast<HPBUFFERARB>(pbuffer_), device_context_);
336 device_context_ = NULL;
338 if (pbuffer_) {
339 wglDestroyPbufferARB(static_cast<HPBUFFERARB>(pbuffer_));
340 pbuffer_ = NULL;
344 bool PbufferGLSurfaceWGL::IsOffscreen() {
345 return true;
348 bool PbufferGLSurfaceWGL::SwapBuffers() {
349 NOTREACHED() << "Attempted to call SwapBuffers on a pbuffer.";
350 return false;
353 gfx::Size PbufferGLSurfaceWGL::GetSize() {
354 return size_;
357 void* PbufferGLSurfaceWGL::GetHandle() {
358 return device_context_;
361 } // namespace gfx