Index: gpu/ipc/service/child_window_surface_win.cc |
diff --git a/gpu/ipc/service/child_window_surface_win.cc b/gpu/ipc/service/child_window_surface_win.cc |
index 762fbd117391233704e07375d64474912e305e1c..682489619c150e631d84ff6b2a1e96143f8c78fd 100644 |
--- a/gpu/ipc/service/child_window_surface_win.cc |
+++ b/gpu/ipc/service/child_window_surface_win.cc |
@@ -7,6 +7,8 @@ |
#include <memory> |
#include "base/compiler_specific.h" |
+#include "base/memory/ptr_util.h" |
+#include "base/threading/thread.h" |
#include "base/win/scoped_hdc.h" |
#include "base/win/wrapped_window_proc.h" |
#include "gpu/ipc/common/gpu_messages.h" |
@@ -22,10 +24,21 @@ |
namespace gpu { |
+// This owns the thread and contains data that's shared between the threads. |
+struct SharedData { |
+ SharedData() : thread("Window owner thread") {} |
+ |
+ base::Lock rect_lock; |
+ gfx::Rect rect_to_clear; |
+ |
+ base::Thread thread; |
+}; |
+ |
namespace { |
ATOM g_window_class; |
+// This runs on the window owner thread. |
LRESULT CALLBACK IntermediateWindowProc(HWND window, |
UINT message, |
WPARAM w_param, |
@@ -37,15 +50,14 @@ LRESULT CALLBACK IntermediateWindowProc(HWND window, |
case WM_PAINT: |
PAINTSTRUCT paint; |
if (BeginPaint(window, &paint)) { |
- ChildWindowSurfaceWin* window_surface = |
- reinterpret_cast<ChildWindowSurfaceWin*>( |
- gfx::GetWindowUserData(window)); |
- DCHECK(window_surface); |
- |
- // Wait to clear the contents until a GL draw occurs, as otherwise an |
- // unsightly black flash may happen if the GL contents are still |
- // transparent. |
- window_surface->InvalidateWindowRect(gfx::Rect(paint.rcPaint)); |
+ SharedData* shared_data = |
+ reinterpret_cast<SharedData*>(gfx::GetWindowUserData(window)); |
+ DCHECK(shared_data); |
+ { |
+ base::AutoLock lock(shared_data->rect_lock); |
+ shared_data->rect_to_clear.Union(gfx::Rect(paint.rcPaint)); |
+ } |
+ |
EndPaint(window, &paint); |
} |
return 0; |
@@ -54,6 +66,7 @@ LRESULT CALLBACK IntermediateWindowProc(HWND window, |
} |
} |
+// This runs on the window owner thread. |
void InitializeWindowClass() { |
if (g_window_class) |
return; |
@@ -70,8 +83,39 @@ void InitializeWindowClass() { |
return; |
} |
} |
+ |
+// This runs on the window owner thread. |
+void CreateChildWindow(HWND hidden_window, |
+ const gfx::Size& size, |
+ base::WaitableEvent* event, |
+ SharedData* shared_data, |
+ HWND* result) { |
+ InitializeWindowClass(); |
+ DCHECK(g_window_class); |
+ |
+ HWND window = CreateWindowEx( |
+ WS_EX_NOPARENTNOTIFY, reinterpret_cast<wchar_t*>(g_window_class), L"", |
+ WS_CHILDWINDOW | WS_DISABLED | WS_VISIBLE, 0, 0, size.width(), |
+ size.height(), hidden_window, NULL, NULL, NULL); |
+ CHECK(window); |
+ *result = window; |
+ gfx::SetWindowUserData(window, shared_data); |
+ event->Signal(); |
+} |
+ |
+// This runs on the main thread after the window was destroyed on window owner |
+// thread. |
+void DestroySharedData(std::unique_ptr<SharedData> shared_data) { |
+ shared_data->thread.Stop(); |
+} |
+ |
+// This runs on the window owner thread. |
+void DestroyWindowOnThread(HWND window) { |
+ DestroyWindow(window); |
} |
+} // namespace |
+ |
ChildWindowSurfaceWin::ChildWindowSurfaceWin(GpuChannelManager* manager, |
HWND parent_window) |
: gl::NativeViewGLSurfaceEGL(0), |
@@ -117,18 +161,24 @@ EGLConfig ChildWindowSurfaceWin::GetConfig() { |
bool ChildWindowSurfaceWin::InitializeNativeWindow() { |
if (window_) |
return true; |
- InitializeWindowClass(); |
- DCHECK(g_window_class); |
- RECT windowRect; |
- GetClientRect(parent_window_, &windowRect); |
+ shared_data_ = base::MakeUnique<SharedData>(); |
+ |
+ base::Thread::Options options(base::MessageLoop::TYPE_UI, 0); |
+ shared_data_->thread.StartWithOptions(options); |
+ |
+ base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC, |
+ base::WaitableEvent::InitialState::NOT_SIGNALED); |
+ |
+ RECT window_rect; |
+ GetClientRect(parent_window_, &window_rect); |
+ |
+ shared_data_->thread.task_runner()->PostTask( |
+ FROM_HERE, base::Bind(&CreateChildWindow, ui::GetHiddenWindow(), |
+ gfx::Rect(window_rect).size(), &event, |
+ shared_data_.get(), &window_)); |
+ event.Wait(); |
- window_ = CreateWindowEx( |
- WS_EX_NOPARENTNOTIFY, reinterpret_cast<wchar_t*>(g_window_class), L"", |
- WS_CHILDWINDOW | WS_DISABLED | WS_VISIBLE, 0, 0, |
- windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, |
- ui::GetHiddenWindow(), NULL, NULL, NULL); |
- gfx::SetWindowUserData(window_, this); |
manager_->delegate()->SendAcceleratedSurfaceCreatedChildWindow(parent_window_, |
window_); |
return true; |
@@ -205,26 +255,28 @@ gfx::SwapResult ChildWindowSurfaceWin::PostSubBuffer(int x, |
return result; |
} |
-void ChildWindowSurfaceWin::InvalidateWindowRect(const gfx::Rect& rect) { |
- rect_to_clear_.Union(rect); |
-} |
- |
void ChildWindowSurfaceWin::ClearInvalidContents() { |
- if (!rect_to_clear_.IsEmpty()) { |
+ base::AutoLock lock(shared_data_->rect_lock); |
+ if (!shared_data_->rect_to_clear.IsEmpty()) { |
base::win::ScopedGetDC dc(window_); |
- RECT rect = rect_to_clear_.ToRECT(); |
+ RECT rect = shared_data_->rect_to_clear.ToRECT(); |
// DirectComposition composites with the contents under the SwapChain, |
// so ensure that's cleared. GDI treats black as transparent. |
FillRect(dc, &rect, reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH))); |
- rect_to_clear_ = gfx::Rect(); |
+ shared_data_->rect_to_clear = gfx::Rect(); |
} |
} |
ChildWindowSurfaceWin::~ChildWindowSurfaceWin() { |
- gfx::SetWindowUserData(window_, nullptr); |
- DestroyWindow(window_); |
+ if (shared_data_) { |
+ scoped_refptr<base::TaskRunner> task_runner = |
+ shared_data_->thread.task_runner(); |
+ task_runner->PostTaskAndReply( |
+ FROM_HERE, base::Bind(&DestroyWindowOnThread, window_), |
+ base::Bind(&DestroySharedData, base::Passed(std::move(shared_data_)))); |
+ } |
} |
} // namespace gpu |