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