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