OLD | NEW |
| (Empty) |
1 // Copyright 2015 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 "content/common/gpu/child_window_surface_win.h" | |
6 | |
7 #include "base/compiler_specific.h" | |
8 #include "base/win/scoped_hdc.h" | |
9 #include "base/win/wrapped_window_proc.h" | |
10 #include "content/common/gpu/gpu_channel_manager.h" | |
11 #include "content/common/gpu/gpu_channel_manager_delegate.h" | |
12 #include "gpu/ipc/common/gpu_messages.h" | |
13 #include "ui/base/win/hidden_window.h" | |
14 #include "ui/gfx/native_widget_types.h" | |
15 #include "ui/gfx/win/hwnd_util.h" | |
16 #include "ui/gl/egl_util.h" | |
17 #include "ui/gl/gl_context.h" | |
18 #include "ui/gl/gl_surface_egl.h" | |
19 #include "ui/gl/scoped_make_current.h" | |
20 | |
21 namespace content { | |
22 | |
23 namespace { | |
24 | |
25 ATOM g_window_class; | |
26 | |
27 LRESULT CALLBACK IntermediateWindowProc(HWND window, | |
28 UINT message, | |
29 WPARAM w_param, | |
30 LPARAM l_param) { | |
31 switch (message) { | |
32 case WM_ERASEBKGND: | |
33 // Prevent windows from erasing the background. | |
34 return 1; | |
35 case WM_PAINT: | |
36 PAINTSTRUCT paint; | |
37 if (BeginPaint(window, &paint)) { | |
38 ChildWindowSurfaceWin* window_surface = | |
39 reinterpret_cast<ChildWindowSurfaceWin*>( | |
40 gfx::GetWindowUserData(window)); | |
41 DCHECK(window_surface); | |
42 | |
43 // Wait to clear the contents until a GL draw occurs, as otherwise an | |
44 // unsightly black flash may happen if the GL contents are still | |
45 // transparent. | |
46 window_surface->InvalidateWindowRect(gfx::Rect(paint.rcPaint)); | |
47 EndPaint(window, &paint); | |
48 } | |
49 return 0; | |
50 default: | |
51 return DefWindowProc(window, message, w_param, l_param); | |
52 } | |
53 } | |
54 | |
55 void InitializeWindowClass() { | |
56 if (g_window_class) | |
57 return; | |
58 | |
59 WNDCLASSEX intermediate_class; | |
60 base::win::InitializeWindowClass( | |
61 L"Intermediate D3D Window", | |
62 &base::win::WrappedWindowProc<IntermediateWindowProc>, CS_OWNDC, 0, 0, | |
63 nullptr, reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)), nullptr, | |
64 nullptr, nullptr, &intermediate_class); | |
65 g_window_class = RegisterClassEx(&intermediate_class); | |
66 if (!g_window_class) { | |
67 LOG(ERROR) << "RegisterClass failed."; | |
68 return; | |
69 } | |
70 } | |
71 } | |
72 | |
73 ChildWindowSurfaceWin::ChildWindowSurfaceWin(GpuChannelManager* manager, | |
74 HWND parent_window) | |
75 : gfx::NativeViewGLSurfaceEGL(0), | |
76 parent_window_(parent_window), | |
77 manager_(manager), | |
78 alpha_(true), | |
79 first_swap_(true) { | |
80 // Don't use EGL_ANGLE_window_fixed_size so that we can avoid recreating the | |
81 // window surface, which can cause flicker on DirectComposition. | |
82 enable_fixed_size_angle_ = false; | |
83 } | |
84 | |
85 EGLConfig ChildWindowSurfaceWin::GetConfig() { | |
86 if (!config_) { | |
87 int alpha_size = alpha_ ? 8 : EGL_DONT_CARE; | |
88 | |
89 EGLint config_attribs[] = {EGL_ALPHA_SIZE, | |
90 alpha_size, | |
91 EGL_BLUE_SIZE, | |
92 8, | |
93 EGL_GREEN_SIZE, | |
94 8, | |
95 EGL_RED_SIZE, | |
96 8, | |
97 EGL_RENDERABLE_TYPE, | |
98 EGL_OPENGL_ES2_BIT, | |
99 EGL_SURFACE_TYPE, | |
100 EGL_WINDOW_BIT | EGL_PBUFFER_BIT, | |
101 EGL_NONE}; | |
102 | |
103 EGLDisplay display = GetHardwareDisplay(); | |
104 EGLint num_configs; | |
105 if (!eglChooseConfig(display, config_attribs, &config_, 1, &num_configs)) { | |
106 LOG(ERROR) << "eglChooseConfig failed with error " | |
107 << ui::GetLastEGLErrorString(); | |
108 return NULL; | |
109 } | |
110 } | |
111 | |
112 return config_; | |
113 } | |
114 | |
115 bool ChildWindowSurfaceWin::InitializeNativeWindow() { | |
116 if (window_) | |
117 return true; | |
118 InitializeWindowClass(); | |
119 DCHECK(g_window_class); | |
120 | |
121 RECT windowRect; | |
122 GetClientRect(parent_window_, &windowRect); | |
123 | |
124 window_ = CreateWindowEx( | |
125 WS_EX_NOPARENTNOTIFY, reinterpret_cast<wchar_t*>(g_window_class), L"", | |
126 WS_CHILDWINDOW | WS_DISABLED | WS_VISIBLE, 0, 0, | |
127 windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, | |
128 ui::GetHiddenWindow(), NULL, NULL, NULL); | |
129 gfx::SetWindowUserData(window_, this); | |
130 manager_->delegate()->SendAcceleratedSurfaceCreatedChildWindow(parent_window_, | |
131 window_); | |
132 return true; | |
133 } | |
134 | |
135 bool ChildWindowSurfaceWin::Resize(const gfx::Size& size, | |
136 float scale_factor, | |
137 bool has_alpha) { | |
138 if (!SupportsPostSubBuffer()) { | |
139 if (!MoveWindow(window_, 0, 0, size.width(), size.height(), FALSE)) { | |
140 return false; | |
141 } | |
142 alpha_ = has_alpha; | |
143 return gfx::NativeViewGLSurfaceEGL::Resize(size, scale_factor, has_alpha); | |
144 } else { | |
145 if (size == GetSize() && has_alpha == alpha_) | |
146 return true; | |
147 | |
148 // Force a resize and redraw (but not a move, activate, etc.). | |
149 if (!SetWindowPos(window_, nullptr, 0, 0, size.width(), size.height(), | |
150 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOCOPYBITS | | |
151 SWP_NOOWNERZORDER | SWP_NOZORDER)) { | |
152 return false; | |
153 } | |
154 size_ = size; | |
155 if (has_alpha == alpha_) { | |
156 // A 0-size PostSubBuffer doesn't swap but forces the swap chain to resize | |
157 // to match the window. | |
158 PostSubBuffer(0, 0, 0, 0); | |
159 } else { | |
160 alpha_ = has_alpha; | |
161 config_ = nullptr; | |
162 | |
163 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current; | |
164 gfx::GLContext* current_context = gfx::GLContext::GetCurrent(); | |
165 bool was_current = current_context && current_context->IsCurrent(this); | |
166 if (was_current) { | |
167 scoped_make_current.reset( | |
168 new ui::ScopedMakeCurrent(current_context, this)); | |
169 current_context->ReleaseCurrent(this); | |
170 } | |
171 | |
172 Destroy(); | |
173 | |
174 if (!Initialize()) { | |
175 LOG(ERROR) << "Failed to resize window."; | |
176 return false; | |
177 } | |
178 } | |
179 return true; | |
180 } | |
181 } | |
182 | |
183 gfx::SwapResult ChildWindowSurfaceWin::SwapBuffers() { | |
184 gfx::SwapResult result = NativeViewGLSurfaceEGL::SwapBuffers(); | |
185 // Force the driver to finish drawing before clearing the contents to | |
186 // transparent, to reduce or eliminate the period of time where the contents | |
187 // have flashed black. | |
188 if (first_swap_) { | |
189 glFinish(); | |
190 first_swap_ = false; | |
191 } | |
192 ClearInvalidContents(); | |
193 return result; | |
194 } | |
195 | |
196 gfx::SwapResult ChildWindowSurfaceWin::PostSubBuffer(int x, | |
197 int y, | |
198 int width, | |
199 int height) { | |
200 gfx::SwapResult result = | |
201 NativeViewGLSurfaceEGL::PostSubBuffer(x, y, width, height); | |
202 ClearInvalidContents(); | |
203 return result; | |
204 } | |
205 | |
206 void ChildWindowSurfaceWin::InvalidateWindowRect(const gfx::Rect& rect) { | |
207 rect_to_clear_.Union(rect); | |
208 } | |
209 | |
210 void ChildWindowSurfaceWin::ClearInvalidContents() { | |
211 if (!rect_to_clear_.IsEmpty()) { | |
212 base::win::ScopedGetDC dc(window_); | |
213 | |
214 RECT rect = rect_to_clear_.ToRECT(); | |
215 | |
216 // DirectComposition composites with the contents under the SwapChain, | |
217 // so ensure that's cleared. GDI treats black as transparent. | |
218 FillRect(dc, &rect, reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH))); | |
219 rect_to_clear_ = gfx::Rect(); | |
220 } | |
221 } | |
222 | |
223 ChildWindowSurfaceWin::~ChildWindowSurfaceWin() { | |
224 gfx::SetWindowUserData(window_, nullptr); | |
225 DestroyWindow(window_); | |
226 } | |
227 | |
228 } // namespace content | |
OLD | NEW |