| 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 |