OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "gpu/ipc/service/child_window_surface_win.h" | 5 #include "gpu/ipc/service/child_window_surface_win.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 | 8 |
9 #include "base/compiler_specific.h" | 9 #include "base/compiler_specific.h" |
10 #include "base/memory/ptr_util.h" | |
11 #include "base/threading/thread.h" | |
12 #include "base/win/scoped_hdc.h" | 10 #include "base/win/scoped_hdc.h" |
13 #include "base/win/wrapped_window_proc.h" | 11 #include "base/win/wrapped_window_proc.h" |
14 #include "gpu/ipc/common/gpu_messages.h" | 12 #include "gpu/ipc/common/gpu_messages.h" |
15 #include "gpu/ipc/service/gpu_channel_manager.h" | 13 #include "gpu/ipc/service/gpu_channel_manager.h" |
16 #include "gpu/ipc/service/gpu_channel_manager_delegate.h" | 14 #include "gpu/ipc/service/gpu_channel_manager_delegate.h" |
17 #include "ui/base/win/hidden_window.h" | 15 #include "ui/base/win/hidden_window.h" |
18 #include "ui/gfx/native_widget_types.h" | 16 #include "ui/gfx/native_widget_types.h" |
19 #include "ui/gfx/win/hwnd_util.h" | 17 #include "ui/gfx/win/hwnd_util.h" |
20 #include "ui/gl/egl_util.h" | 18 #include "ui/gl/egl_util.h" |
21 #include "ui/gl/gl_context.h" | 19 #include "ui/gl/gl_context.h" |
22 #include "ui/gl/gl_surface_egl.h" | 20 #include "ui/gl/gl_surface_egl.h" |
23 #include "ui/gl/scoped_make_current.h" | 21 #include "ui/gl/scoped_make_current.h" |
24 | 22 |
25 namespace gpu { | 23 namespace gpu { |
26 | 24 |
27 // This owns the thread and contains data that's shared between the threads. | |
28 struct SharedData { | |
29 SharedData() : thread("Window owner thread") {} | |
30 | |
31 base::Lock rect_lock; | |
32 gfx::Rect rect_to_clear; | |
33 | |
34 base::Thread thread; | |
35 }; | |
36 | |
37 namespace { | 25 namespace { |
38 | 26 |
39 ATOM g_window_class; | 27 ATOM g_window_class; |
40 | 28 |
41 // This runs on the window owner thread. | |
42 LRESULT CALLBACK IntermediateWindowProc(HWND window, | 29 LRESULT CALLBACK IntermediateWindowProc(HWND window, |
43 UINT message, | 30 UINT message, |
44 WPARAM w_param, | 31 WPARAM w_param, |
45 LPARAM l_param) { | 32 LPARAM l_param) { |
46 switch (message) { | 33 switch (message) { |
47 case WM_ERASEBKGND: | 34 case WM_ERASEBKGND: |
48 // Prevent windows from erasing the background. | 35 // Prevent windows from erasing the background. |
49 return 1; | 36 return 1; |
50 case WM_PAINT: | 37 case WM_PAINT: |
51 PAINTSTRUCT paint; | 38 PAINTSTRUCT paint; |
52 if (BeginPaint(window, &paint)) { | 39 if (BeginPaint(window, &paint)) { |
53 SharedData* shared_data = | 40 ChildWindowSurfaceWin* window_surface = |
54 reinterpret_cast<SharedData*>(gfx::GetWindowUserData(window)); | 41 reinterpret_cast<ChildWindowSurfaceWin*>( |
55 DCHECK(shared_data); | 42 gfx::GetWindowUserData(window)); |
56 { | 43 DCHECK(window_surface); |
57 base::AutoLock lock(shared_data->rect_lock); | |
58 shared_data->rect_to_clear.Union(gfx::Rect(paint.rcPaint)); | |
59 } | |
60 | 44 |
| 45 // Wait to clear the contents until a GL draw occurs, as otherwise an |
| 46 // unsightly black flash may happen if the GL contents are still |
| 47 // transparent. |
| 48 window_surface->InvalidateWindowRect(gfx::Rect(paint.rcPaint)); |
61 EndPaint(window, &paint); | 49 EndPaint(window, &paint); |
62 } | 50 } |
63 return 0; | 51 return 0; |
64 default: | 52 default: |
65 return DefWindowProc(window, message, w_param, l_param); | 53 return DefWindowProc(window, message, w_param, l_param); |
66 } | 54 } |
67 } | 55 } |
68 | 56 |
69 // This runs on the window owner thread. | |
70 void InitializeWindowClass() { | 57 void InitializeWindowClass() { |
71 if (g_window_class) | 58 if (g_window_class) |
72 return; | 59 return; |
73 | 60 |
74 WNDCLASSEX intermediate_class; | 61 WNDCLASSEX intermediate_class; |
75 base::win::InitializeWindowClass( | 62 base::win::InitializeWindowClass( |
76 L"Intermediate D3D Window", | 63 L"Intermediate D3D Window", |
77 &base::win::WrappedWindowProc<IntermediateWindowProc>, CS_OWNDC, 0, 0, | 64 &base::win::WrappedWindowProc<IntermediateWindowProc>, CS_OWNDC, 0, 0, |
78 nullptr, reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)), nullptr, | 65 nullptr, reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)), nullptr, |
79 nullptr, nullptr, &intermediate_class); | 66 nullptr, nullptr, &intermediate_class); |
80 g_window_class = RegisterClassEx(&intermediate_class); | 67 g_window_class = RegisterClassEx(&intermediate_class); |
81 if (!g_window_class) { | 68 if (!g_window_class) { |
82 LOG(ERROR) << "RegisterClass failed."; | 69 LOG(ERROR) << "RegisterClass failed."; |
83 return; | 70 return; |
84 } | 71 } |
85 } | 72 } |
86 | |
87 // This runs on the window owner thread. | |
88 void CreateChildWindow(HWND parent, | |
89 base::WaitableEvent* event, | |
90 SharedData* shared_data, | |
91 HWND* result) { | |
92 InitializeWindowClass(); | |
93 DCHECK(g_window_class); | |
94 | |
95 RECT windowRect; | |
96 GetClientRect(parent, &windowRect); | |
97 | |
98 HWND window = CreateWindowEx( | |
99 WS_EX_NOPARENTNOTIFY, reinterpret_cast<wchar_t*>(g_window_class), L"", | |
100 WS_CHILDWINDOW | WS_DISABLED | WS_VISIBLE, 0, 0, | |
101 windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, | |
102 ui::GetHiddenWindow(), NULL, NULL, NULL); | |
103 *result = window; | |
104 gfx::SetWindowUserData(window, shared_data); | |
105 event->Signal(); | |
106 } | 73 } |
107 | 74 |
108 // This runs on the main thread after the window was destroyed on window owner | |
109 // thread. | |
110 void DestroySharedData(std::unique_ptr<SharedData> shared_data) { | |
111 shared_data->thread.Stop(); | |
112 } | |
113 | |
114 // This runs on the window owner thread. | |
115 void DestroyWindowOnThread(HWND window) { | |
116 DestroyWindow(window); | |
117 } | |
118 | |
119 } // namespace | |
120 | |
121 ChildWindowSurfaceWin::ChildWindowSurfaceWin(GpuChannelManager* manager, | 75 ChildWindowSurfaceWin::ChildWindowSurfaceWin(GpuChannelManager* manager, |
122 HWND parent_window) | 76 HWND parent_window) |
123 : gl::NativeViewGLSurfaceEGL(0), | 77 : gl::NativeViewGLSurfaceEGL(0), |
124 parent_window_(parent_window), | 78 parent_window_(parent_window), |
125 manager_(manager), | 79 manager_(manager), |
126 alpha_(true), | 80 alpha_(true), |
127 first_swap_(true) { | 81 first_swap_(true) { |
128 // Don't use EGL_ANGLE_window_fixed_size so that we can avoid recreating the | 82 // Don't use EGL_ANGLE_window_fixed_size so that we can avoid recreating the |
129 // window surface, which can cause flicker on DirectComposition. | 83 // window surface, which can cause flicker on DirectComposition. |
130 enable_fixed_size_angle_ = false; | 84 enable_fixed_size_angle_ = false; |
(...skipping 25 matching lines...) Expand all Loading... |
156 return NULL; | 110 return NULL; |
157 } | 111 } |
158 } | 112 } |
159 | 113 |
160 return config_; | 114 return config_; |
161 } | 115 } |
162 | 116 |
163 bool ChildWindowSurfaceWin::InitializeNativeWindow() { | 117 bool ChildWindowSurfaceWin::InitializeNativeWindow() { |
164 if (window_) | 118 if (window_) |
165 return true; | 119 return true; |
| 120 InitializeWindowClass(); |
| 121 DCHECK(g_window_class); |
166 | 122 |
167 shared_data_ = base::MakeUnique<SharedData>(); | 123 RECT windowRect; |
| 124 GetClientRect(parent_window_, &windowRect); |
168 | 125 |
169 base::Thread::Options options(base::MessageLoop::TYPE_UI, 0); | 126 window_ = CreateWindowEx( |
170 shared_data_->thread.StartWithOptions(options); | 127 WS_EX_NOPARENTNOTIFY, reinterpret_cast<wchar_t*>(g_window_class), L"", |
171 | 128 WS_CHILDWINDOW | WS_DISABLED | WS_VISIBLE, 0, 0, |
172 base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC, | 129 windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, |
173 base::WaitableEvent::InitialState::NOT_SIGNALED); | 130 ui::GetHiddenWindow(), NULL, NULL, NULL); |
174 shared_data_->thread.task_runner()->PostTask( | 131 gfx::SetWindowUserData(window_, this); |
175 FROM_HERE, base::Bind(&CreateChildWindow, parent_window_, &event, | |
176 shared_data_.get(), &window_)); | |
177 event.Wait(); | |
178 | |
179 manager_->delegate()->SendAcceleratedSurfaceCreatedChildWindow(parent_window_, | 132 manager_->delegate()->SendAcceleratedSurfaceCreatedChildWindow(parent_window_, |
180 window_); | 133 window_); |
181 return true; | 134 return true; |
182 } | 135 } |
183 | 136 |
184 bool ChildWindowSurfaceWin::Resize(const gfx::Size& size, | 137 bool ChildWindowSurfaceWin::Resize(const gfx::Size& size, |
185 float scale_factor, | 138 float scale_factor, |
186 bool has_alpha) { | 139 bool has_alpha) { |
187 if (!SupportsPostSubBuffer()) { | 140 if (!SupportsPostSubBuffer()) { |
188 if (!MoveWindow(window_, 0, 0, size.width(), size.height(), FALSE)) { | 141 if (!MoveWindow(window_, 0, 0, size.width(), size.height(), FALSE)) { |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
245 gfx::SwapResult ChildWindowSurfaceWin::PostSubBuffer(int x, | 198 gfx::SwapResult ChildWindowSurfaceWin::PostSubBuffer(int x, |
246 int y, | 199 int y, |
247 int width, | 200 int width, |
248 int height) { | 201 int height) { |
249 gfx::SwapResult result = | 202 gfx::SwapResult result = |
250 NativeViewGLSurfaceEGL::PostSubBuffer(x, y, width, height); | 203 NativeViewGLSurfaceEGL::PostSubBuffer(x, y, width, height); |
251 ClearInvalidContents(); | 204 ClearInvalidContents(); |
252 return result; | 205 return result; |
253 } | 206 } |
254 | 207 |
| 208 void ChildWindowSurfaceWin::InvalidateWindowRect(const gfx::Rect& rect) { |
| 209 rect_to_clear_.Union(rect); |
| 210 } |
| 211 |
255 void ChildWindowSurfaceWin::ClearInvalidContents() { | 212 void ChildWindowSurfaceWin::ClearInvalidContents() { |
256 base::AutoLock lock(shared_data_->rect_lock); | 213 if (!rect_to_clear_.IsEmpty()) { |
257 if (!shared_data_->rect_to_clear.IsEmpty()) { | |
258 base::win::ScopedGetDC dc(window_); | 214 base::win::ScopedGetDC dc(window_); |
259 | 215 |
260 RECT rect = shared_data_->rect_to_clear.ToRECT(); | 216 RECT rect = rect_to_clear_.ToRECT(); |
261 | 217 |
262 // DirectComposition composites with the contents under the SwapChain, | 218 // DirectComposition composites with the contents under the SwapChain, |
263 // so ensure that's cleared. GDI treats black as transparent. | 219 // so ensure that's cleared. GDI treats black as transparent. |
264 FillRect(dc, &rect, reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH))); | 220 FillRect(dc, &rect, reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH))); |
265 shared_data_->rect_to_clear = gfx::Rect(); | 221 rect_to_clear_ = gfx::Rect(); |
266 } | 222 } |
267 } | 223 } |
268 | 224 |
269 ChildWindowSurfaceWin::~ChildWindowSurfaceWin() { | 225 ChildWindowSurfaceWin::~ChildWindowSurfaceWin() { |
270 if (shared_data_) { | 226 gfx::SetWindowUserData(window_, nullptr); |
271 scoped_refptr<base::TaskRunner> task_runner = | 227 DestroyWindow(window_); |
272 shared_data_->thread.task_runner(); | |
273 task_runner->PostTaskAndReply( | |
274 FROM_HERE, base::Bind(&DestroyWindowOnThread, window_), | |
275 base::Bind(&DestroySharedData, base::Passed(std::move(shared_data_)))); | |
276 } | |
277 } | 228 } |
278 | 229 |
279 } // namespace gpu | 230 } // namespace gpu |
OLD | NEW |