Commit 267fd834 authored by jbauman's avatar jbauman Committed by Commit bot

Split out ChildWindowWin

This will allow other GL Surface implementations than
ChildWindowSurfaceWin to create a child window on a new thread.
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel

Review-Url: https://codereview.chromium.org/2623763003
Cr-Commit-Position: refs/heads/master@{#442749}
parent 1d1bf1cb
......@@ -81,6 +81,8 @@ target(link_target_type, "ipc_service_sources") {
sources += [
"child_window_surface_win.cc",
"child_window_surface_win.h",
"child_window_win.cc",
"child_window_win.h",
"image_transport_surface_win.cc",
]
}
......
......@@ -8,15 +8,10 @@
#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"
#include "gpu/ipc/service/gpu_channel_manager.h"
#include "gpu/ipc/service/gpu_channel_manager_delegate.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/win/hwnd_util.h"
#include "ui/gfx/win/window_impl.h"
#include "ui/gl/egl_util.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_surface_egl.h"
......@@ -24,144 +19,11 @@
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,
LPARAM l_param) {
switch (message) {
case WM_ERASEBKGND:
// Prevent windows from erasing the background.
return 1;
case WM_PAINT:
PAINTSTRUCT paint;
if (BeginPaint(window, &paint)) {
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;
default:
return DefWindowProc(window, message, w_param, l_param);
}
}
// This runs on the window owner thread.
void InitializeWindowClass() {
if (g_window_class)
return;
WNDCLASSEX intermediate_class;
base::win::InitializeWindowClass(
L"Intermediate D3D Window",
&base::win::WrappedWindowProc<IntermediateWindowProc>, CS_OWNDC, 0, 0,
nullptr, reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)), nullptr,
nullptr, nullptr, &intermediate_class);
g_window_class = RegisterClassEx(&intermediate_class);
if (!g_window_class) {
LOG(ERROR) << "RegisterClass failed.";
return;
}
}
// Hidden popup window used as a parent for the child surface window.
// Must be created and destroyed on the thread.
class HiddenPopupWindow : public gfx::WindowImpl {
public:
static HWND Create() {
gfx::WindowImpl* window = new HiddenPopupWindow;
window->set_window_style(WS_POPUP);
window->set_window_ex_style(WS_EX_TOOLWINDOW);
window->Init(GetDesktopWindow(), gfx::Rect());
EnableWindow(window->hwnd(), FALSE);
// The |window| instance is now owned by the window user data.
DCHECK_EQ(window, gfx::GetWindowUserData(window->hwnd()));
return window->hwnd();
}
static void Destroy(HWND window) {
// This uses the fact that the window user data contains a pointer
// to gfx::WindowImpl instance.
gfx::WindowImpl* window_data =
reinterpret_cast<gfx::WindowImpl*>(gfx::GetWindowUserData(window));
DCHECK_EQ(window, window_data->hwnd());
DestroyWindow(window);
delete window_data;
}
private:
// Explicitly do nothing in Close. We do this as some external apps may get a
// handle to this window and attempt to close it.
void OnClose() {}
CR_BEGIN_MSG_MAP_EX(HiddenPopupWindow)
CR_MSG_WM_CLOSE(OnClose)
CR_END_MSG_MAP()
};
// This runs on the window owner thread.
void CreateWindowsOnThread(const gfx::Size& size,
base::WaitableEvent* event,
SharedData* shared_data,
HWND* child_window,
HWND* parent_window) {
InitializeWindowClass();
DCHECK(g_window_class);
// Create hidden parent window on the current thread.
*parent_window = HiddenPopupWindow::Create();
// Create child window.
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(), *parent_window, NULL, NULL, NULL);
CHECK(window);
*child_window = 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 DestroyWindowsOnThread(HWND child_window, HWND hidden_popup_window) {
DestroyWindow(child_window);
HiddenPopupWindow::Destroy(hidden_popup_window);
}
} // namespace
ChildWindowSurfaceWin::ChildWindowSurfaceWin(
base::WeakPtr<ImageTransportSurfaceDelegate> delegate,
HWND parent_window)
: gl::NativeViewGLSurfaceEGL(0),
parent_window_(parent_window),
delegate_(delegate),
child_window_(delegate, parent_window),
alpha_(true),
first_swap_(true) {
// Don't use EGL_ANGLE_window_fixed_size so that we can avoid recreating the
......@@ -203,25 +65,9 @@ bool ChildWindowSurfaceWin::InitializeNativeWindow() {
if (window_)
return true;
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(&CreateWindowsOnThread, gfx::Rect(window_rect).size(), &event,
shared_data_.get(), &window_, &initial_parent_window_));
event.Wait();
delegate_->DidCreateAcceleratedSurfaceChildWindow(parent_window_, window_);
return true;
bool result = child_window_.Initialize();
window_ = child_window_.window();
return result;
}
bool ChildWindowSurfaceWin::Resize(const gfx::Size& size,
......@@ -281,7 +127,7 @@ gfx::SwapResult ChildWindowSurfaceWin::SwapBuffers() {
glFinish();
first_swap_ = false;
}
ClearInvalidContents();
child_window_.ClearInvalidContents();
return result;
}
......@@ -291,33 +137,11 @@ gfx::SwapResult ChildWindowSurfaceWin::PostSubBuffer(int x,
int height) {
gfx::SwapResult result =
NativeViewGLSurfaceEGL::PostSubBuffer(x, y, width, height);
ClearInvalidContents();
child_window_.ClearInvalidContents();
return result;
}
void ChildWindowSurfaceWin::ClearInvalidContents() {
base::AutoLock lock(shared_data_->rect_lock);
if (!shared_data_->rect_to_clear.IsEmpty()) {
base::win::ScopedGetDC dc(window_);
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)));
shared_data_->rect_to_clear = gfx::Rect();
}
}
ChildWindowSurfaceWin::~ChildWindowSurfaceWin() {
if (shared_data_) {
scoped_refptr<base::TaskRunner> task_runner =
shared_data_->thread.task_runner();
task_runner->PostTaskAndReply(
FROM_HERE,
base::Bind(&DestroyWindowsOnThread, window_, initial_parent_window_),
base::Bind(&DestroySharedData, base::Passed(std::move(shared_data_))));
}
}
} // namespace gpu
......@@ -6,6 +6,7 @@
#define GPU_IPC_SERVICE_CHILD_WINDOW_SURFACE_WIN_H_
#include "base/memory/weak_ptr.h"
#include "gpu/ipc/service/child_window_win.h"
#include "gpu/ipc/service/image_transport_surface_delegate.h"
#include "ui/gl/gl_surface_egl.h"
......@@ -13,8 +14,6 @@
namespace gpu {
struct SharedData;
class ChildWindowSurfaceWin : public gl::NativeViewGLSurfaceEGL {
public:
ChildWindowSurfaceWin(base::WeakPtr<ImageTransportSurfaceDelegate> delegate,
......@@ -33,17 +32,7 @@ class ChildWindowSurfaceWin : public gl::NativeViewGLSurfaceEGL {
~ChildWindowSurfaceWin() override;
private:
void ClearInvalidContents();
// This member contains all the data that can be accessed from the main or
// window owner threads.
std::unique_ptr<SharedData> shared_data_;
// The eventual parent of the window living in the browser process.
HWND parent_window_;
// The window is initially created with this parent window. We need to keep it
// around so that we can destroy it at the end.
HWND initial_parent_window_;
base::WeakPtr<ImageTransportSurfaceDelegate> delegate_;
ChildWindowWin child_window_;
bool alpha_;
bool first_swap_;
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gpu/ipc/service/child_window_win.h"
#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"
#include "gpu/ipc/service/gpu_channel_manager.h"
#include "gpu/ipc/service/gpu_channel_manager_delegate.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/win/hwnd_util.h"
#include "ui/gfx/win/window_impl.h"
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,
LPARAM l_param) {
switch (message) {
case WM_ERASEBKGND:
// Prevent windows from erasing the background.
return 1;
case WM_PAINT:
PAINTSTRUCT paint;
if (BeginPaint(window, &paint)) {
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;
default:
return DefWindowProc(window, message, w_param, l_param);
}
}
// This runs on the window owner thread.
void InitializeWindowClass() {
if (g_window_class)
return;
WNDCLASSEX intermediate_class;
base::win::InitializeWindowClass(
L"Intermediate D3D Window",
&base::win::WrappedWindowProc<IntermediateWindowProc>, CS_OWNDC, 0, 0,
nullptr, reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)), nullptr,
nullptr, nullptr, &intermediate_class);
g_window_class = RegisterClassEx(&intermediate_class);
if (!g_window_class) {
LOG(ERROR) << "RegisterClass failed.";
return;
}
}
// Hidden popup window used as a parent for the child surface window.
// Must be created and destroyed on the thread.
class HiddenPopupWindow : public gfx::WindowImpl {
public:
static HWND Create() {
gfx::WindowImpl* window = new HiddenPopupWindow;
window->set_window_style(WS_POPUP);
window->set_window_ex_style(WS_EX_TOOLWINDOW);
window->Init(GetDesktopWindow(), gfx::Rect());
EnableWindow(window->hwnd(), FALSE);
// The |window| instance is now owned by the window user data.
DCHECK_EQ(window, gfx::GetWindowUserData(window->hwnd()));
return window->hwnd();
}
static void Destroy(HWND window) {
// This uses the fact that the window user data contains a pointer
// to gfx::WindowImpl instance.
gfx::WindowImpl* window_data =
reinterpret_cast<gfx::WindowImpl*>(gfx::GetWindowUserData(window));
DCHECK_EQ(window, window_data->hwnd());
DestroyWindow(window);
delete window_data;
}
private:
// Explicitly do nothing in Close. We do this as some external apps may get a
// handle to this window and attempt to close it.
void OnClose() {}
CR_BEGIN_MSG_MAP_EX(HiddenPopupWindow)
CR_MSG_WM_CLOSE(OnClose)
CR_END_MSG_MAP()
};
// This runs on the window owner thread.
void CreateWindowsOnThread(const gfx::Size& size,
base::WaitableEvent* event,
SharedData* shared_data,
HWND* child_window,
HWND* parent_window) {
InitializeWindowClass();
DCHECK(g_window_class);
// Create hidden parent window on the current thread.
*parent_window = HiddenPopupWindow::Create();
// Create child window.
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(), *parent_window, NULL, NULL, NULL);
CHECK(window);
*child_window = 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 DestroyWindowsOnThread(HWND child_window, HWND hidden_popup_window) {
DestroyWindow(child_window);
HiddenPopupWindow::Destroy(hidden_popup_window);
}
} // namespace
ChildWindowWin::ChildWindowWin(
base::WeakPtr<ImageTransportSurfaceDelegate> delegate,
HWND parent_window)
: parent_window_(parent_window), window_(nullptr), delegate_(delegate) {}
bool ChildWindowWin::Initialize() {
if (window_)
return true;
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(&CreateWindowsOnThread, gfx::Rect(window_rect).size(), &event,
shared_data_.get(), &window_, &initial_parent_window_));
event.Wait();
delegate_->DidCreateAcceleratedSurfaceChildWindow(parent_window_, window_);
return true;
}
void ChildWindowWin::ClearInvalidContents() {
base::AutoLock lock(shared_data_->rect_lock);
if (!shared_data_->rect_to_clear.IsEmpty()) {
base::win::ScopedGetDC dc(window_);
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)));
shared_data_->rect_to_clear = gfx::Rect();
}
}
ChildWindowWin::~ChildWindowWin() {
if (shared_data_) {
scoped_refptr<base::TaskRunner> task_runner =
shared_data_->thread.task_runner();
task_runner->PostTaskAndReply(
FROM_HERE,
base::Bind(&DestroyWindowsOnThread, window_, initial_parent_window_),
base::Bind(&DestroySharedData, base::Passed(std::move(shared_data_))));
}
}
} // namespace gpu
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef GPU_IPC_SERVICE_CHILD_WINDOW_WIN_H_
#define GPU_IPC_SERVICE_CHILD_WINDOW_WIN_H_
#include "base/memory/weak_ptr.h"
#include "gpu/ipc/service/image_transport_surface_delegate.h"
#include <windows.h>
namespace gpu {
struct SharedData;
// The window DirectComposition renders into needs to be owned by the process
// that's currently doing the rendering. The class creates and owns a window
// which is reparented by the browser to be a child of its window.
class ChildWindowWin {
public:
ChildWindowWin(base::WeakPtr<ImageTransportSurfaceDelegate> delegate,
HWND parent_window);
~ChildWindowWin();
bool Initialize();
void ClearInvalidContents();
HWND window() const { return window_; }
private:
// This member contains all the data that can be accessed from the main or
// window owner threads.
std::unique_ptr<SharedData> shared_data_;
// The eventual parent of the window living in the browser process.
HWND parent_window_;
HWND window_;
// The window is initially created with this parent window. We need to keep it
// around so that we can destroy it at the end.
HWND initial_parent_window_;
base::WeakPtr<ImageTransportSurfaceDelegate> delegate_;
DISALLOW_COPY_AND_ASSIGN(ChildWindowWin);
};
} // namespace gpu
#endif // GPU_IPC_SERVICE_CHILD_WINDOW_WIN_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment