diff options
author | nduca@chromium.org <nduca@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-27 19:39:42 +0000 |
---|---|---|
committer | nduca@chromium.org <nduca@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-27 19:39:42 +0000 |
commit | 50bd645cfa2824a22f98096cb6a66bbd7cf757f4 (patch) | |
tree | 3cae036733b722b0ec731363179c5fdec5f7e137 | |
parent | 1bead0713628b2410ffd7ba49700c5901059d07b (diff) | |
download | chromium_src-50bd645cfa2824a22f98096cb6a66bbd7cf757f4.zip chromium_src-50bd645cfa2824a22f98096cb6a66bbd7cf757f4.tar.gz chromium_src-50bd645cfa2824a22f98096cb6a66bbd7cf757f4.tar.bz2 |
When accelerated compositing is enabled, we create a plugin-like pair of windows,
CompositorHostWindow and CompositorWindow inside the RenderWidgetHostView. The host-side
HWND is used to position the compositor output relative to plugins; the GPU process creates the
compositor window as a child of the CompositorHostWindow.
Once we land webkit bugfix 49396, ANGLE issue 3038042, Chromium issue 4671003, this will fix
bugs 54301 and 61516 for windows.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/4815001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@67495 0039d316-1c4b-4281-b951-d872f2087c98
21 files changed, 469 insertions, 48 deletions
diff --git a/chrome/browser/gpu_process_host.cc b/chrome/browser/gpu_process_host.cc index afa904c..c321f97 100644 --- a/chrome/browser/gpu_process_host.cc +++ b/chrome/browser/gpu_process_host.cc @@ -177,6 +177,9 @@ void GpuProcessHost::OnControlMessageReceived(const IPC::Message& message) { OnAcceleratedSurfaceSetIOSurface) IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceBuffersSwapped, OnAcceleratedSurfaceBuffersSwapped) +#elif defined(OS_WIN) + IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuHostMsg_CreateCompositorHostWindow, + OnCreateCompositorHostWindow) #endif // If the IO thread does not handle the message then automatically route it // to the UI thread. The UI thread will report an error if it does not @@ -305,8 +308,8 @@ namespace { class BuffersSwappedDispatcher : public Task { public: BuffersSwappedDispatcher( - int32 renderer_id, - int32 render_view_id, + int renderer_id, + int render_view_id, gfx::PluginWindowHandle window, uint64 surface_id, int32 route_id, @@ -338,8 +341,8 @@ class BuffersSwappedDispatcher : public Task { } private: - int32 renderer_id_; - int32 render_view_id_; + int renderer_id_; + int render_view_id_; gfx::PluginWindowHandle window_; uint64 surface_id_; int32 route_id_; @@ -366,6 +369,47 @@ void GpuProcessHost::OnAcceleratedSurfaceBuffersSwapped( params.route_id, params.swap_buffers_count)); } + +#elif defined(OS_WIN) + +namespace { + +void SendDelayedReply(IPC::Message* reply_msg) { + GpuProcessHost::Get()->Send(reply_msg); +} + +void CreateCompositorHostWindowDispatcher( + int renderer_id, + int render_view_id, + IPC::Message* reply_msg) { + RenderViewHost* host = RenderViewHost::FromID(renderer_id, + render_view_id); + if (!host) { + return; + } + + RenderWidgetHostView* view = host->view(); + gfx::PluginWindowHandle id = view->CreateCompositorHostWindow(); + + + GpuHostMsg_CreateCompositorHostWindow::WriteReplyParams(reply_msg, id); + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + NewRunnableFunction(&SendDelayedReply, reply_msg)); +} + +} // namespace + +void GpuProcessHost::OnCreateCompositorHostWindow( + int renderer_id, + int render_view_id, + IPC::Message* reply_message) { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + NewRunnableFunction(&CreateCompositorHostWindowDispatcher, + renderer_id, render_view_id, reply_message)); +} + #endif void GpuProcessHost::SendEstablishChannelReply( diff --git a/chrome/browser/gpu_process_host.h b/chrome/browser/gpu_process_host.h index 4b40a25..8219355 100644 --- a/chrome/browser/gpu_process_host.h +++ b/chrome/browser/gpu_process_host.h @@ -93,6 +93,10 @@ class GpuProcessHost : public BrowserChildProcessHost, public NonThreadSafe { const GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params& params); void OnAcceleratedSurfaceBuffersSwapped( const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params); +#elif defined(OS_WIN) + void OnCreateCompositorHostWindow(int renderer_id, + int render_view_id, + IPC::Message* reply_message); #endif // Sends the response for establish channel request to the renderer. diff --git a/chrome/browser/gpu_process_host_ui_shim.cc b/chrome/browser/gpu_process_host_ui_shim.cc index 2e3a531..d8257a8 100644 --- a/chrome/browser/gpu_process_host_ui_shim.cc +++ b/chrome/browser/gpu_process_host_ui_shim.cc @@ -6,6 +6,7 @@ #include "chrome/browser/browser_thread.h" #include "chrome/browser/gpu_process_host.h" +#include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/common/child_process_logging.h" #include "chrome/common/gpu_messages.h" @@ -105,6 +106,15 @@ void GpuProcessHostUIShim::OnGraphicsInfoCollected(const GPUInfo& gpu_info) { child_process_logging::SetGpuInfo(gpu_info); } +void GpuProcessHostUIShim::OnScheduleComposite(int renderer_id, + int render_view_id) { + RenderViewHost* host = RenderViewHost::FromID(renderer_id, + render_view_id); + if (!host) { + return; + } + host->ScheduleComposite(); +} void GpuProcessHostUIShim::OnControlMessageReceived( const IPC::Message& message) { DCHECK(CalledOnValidThread()); @@ -112,6 +122,10 @@ void GpuProcessHostUIShim::OnControlMessageReceived( IPC_BEGIN_MESSAGE_MAP(GpuProcessHostUIShim, message) IPC_MESSAGE_HANDLER(GpuHostMsg_GraphicsInfoCollected, OnGraphicsInfoCollected) +#if defined(OS_WIN) + IPC_MESSAGE_HANDLER(GpuHostMsg_ScheduleComposite, + OnScheduleComposite); +#endif IPC_MESSAGE_UNHANDLED_ERROR() IPC_END_MESSAGE_MAP() } diff --git a/chrome/browser/gpu_process_host_ui_shim.h b/chrome/browser/gpu_process_host_ui_shim.h index d77c783..eda33d2 100644 --- a/chrome/browser/gpu_process_host_ui_shim.h +++ b/chrome/browser/gpu_process_host_ui_shim.h @@ -62,7 +62,7 @@ class GpuProcessHostUIShim : public IPC::Channel::Sender, // Message handlers. void OnGraphicsInfoCollected(const GPUInfo& gpu_info); - + void OnScheduleComposite(int32 renderer_id, int32 render_view_id); void OnControlMessageReceived(const IPC::Message& message); int last_routing_id_; diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc index 4482bbd..caf7d14 100644 --- a/chrome/browser/renderer_host/render_widget_host.cc +++ b/chrome/browser/renderer_host/render_widget_host.cc @@ -77,7 +77,7 @@ RenderWidgetHost::RenderWidgetHost(RenderProcessHost* process, routing_id_(routing_id), is_loading_(false), is_hidden_(false), - is_gpu_rendering_active_(false), + is_accelerated_compositing_active_(false), repaint_ack_pending_(false), resize_ack_pending_(false), mouse_move_pending_(false), @@ -157,8 +157,8 @@ void RenderWidgetHost::OnMessageReceived(const IPC::Message &msg) { OnMsgImeUpdateTextInputState) IPC_MESSAGE_HANDLER(ViewHostMsg_ImeCancelComposition, OnMsgImeCancelComposition) - IPC_MESSAGE_HANDLER(ViewHostMsg_GpuRenderingActivated, - OnMsgGpuRenderingActivated) + IPC_MESSAGE_HANDLER(ViewHostMsg_DidActivateAcceleratedCompositing, + OnMsgDidActivateAcceleratedCompositing) #if defined(OS_MACOSX) IPC_MESSAGE_HANDLER(ViewHostMsg_GetScreenInfo, OnMsgGetScreenInfo) IPC_MESSAGE_HANDLER(ViewHostMsg_GetWindowRect, OnMsgGetWindowRect) @@ -232,7 +232,7 @@ void RenderWidgetHost::WasRestored() { // the backing store exists. bool needs_repainting; if (needs_repainting_on_restore_ || !backing_store || - is_gpu_rendering_active()) { + is_accelerated_compositing_active()) { needs_repainting = true; needs_repainting_on_restore_ = false; } else { @@ -402,8 +402,9 @@ void RenderWidgetHost::DonePaintingToBackingStore() { } void RenderWidgetHost::ScheduleComposite() { - DCHECK(!is_hidden_ || !is_gpu_rendering_active_) << - "ScheduleCompositeAndSync called while hidden!"; + if (is_hidden_ || !is_accelerated_compositing_active_) { + return; + } // Send out a request to the renderer to paint the view if required. if (!repaint_ack_pending_ && !resize_ack_pending_ && !view_being_painted_) { @@ -658,7 +659,7 @@ void RenderWidgetHost::RendererExited() { current_size_.SetSize(0, 0); current_reserved_rect_.SetRect(0, 0, 0, 0); is_hidden_ = false; - is_gpu_rendering_active_ = false; + is_accelerated_compositing_active_ = false; if (view_) { view_->RenderViewGone(); @@ -832,7 +833,7 @@ void RenderWidgetHost::OnMsgUpdateRect( DCHECK(!params.bitmap_rect.IsEmpty()); DCHECK(!params.view_size.IsEmpty()); - if (!is_gpu_rendering_active_) { + if (!is_accelerated_compositing_active_) { const size_t size = params.bitmap_rect.height() * params.bitmap_rect.width() * 4; TransportDIB* dib = process_->GetTransportDIB(params.bitmap); @@ -879,7 +880,7 @@ void RenderWidgetHost::OnMsgUpdateRect( // which attempts to move the plugin windows and in the process could // dispatch other window messages which could cause the view to be // destroyed. - if (view_ && !is_gpu_rendering_active_) { + if (view_ && !is_accelerated_compositing_active_) { view_being_painted_ = true; view_->DidUpdateBackingStore(params.scroll_rect, params.dx, params.dy, params.copy_rects); @@ -977,14 +978,16 @@ void RenderWidgetHost::OnMsgImeCancelComposition() { view_->ImeCancelComposition(); } -void RenderWidgetHost::OnMsgGpuRenderingActivated(bool activated) { +void RenderWidgetHost::OnMsgDidActivateAcceleratedCompositing(bool activated) { #if defined(OS_MACOSX) - bool old_state = is_gpu_rendering_active_; + bool old_state = is_accelerated_compositing_active_; #endif - is_gpu_rendering_active_ = activated; + is_accelerated_compositing_active_ = activated; #if defined(OS_MACOSX) - if (old_state != is_gpu_rendering_active_ && view_) + if (old_state != is_accelerated_compositing_active_ && view_) view_->GpuRenderingStateDidChange(); +#elif defined(OS_WIN) + view_->ShowCompositorHostWindow(is_accelerated_compositing_active_); #elif defined(TOOLKIT_USES_GTK) view_->AcceleratedCompositingActivated(activated); #endif @@ -1089,7 +1092,6 @@ void RenderWidgetHost::OnMsgDestroyPluginContainer(gfx::PluginWindowHandle id) { NOTIMPLEMENTED(); } } - #endif void RenderWidgetHost::PaintBackingStoreRect( diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h index 9f2225b..47e4dab 100644 --- a/chrome/browser/renderer_host/render_widget_host.h +++ b/chrome/browser/renderer_host/render_widget_host.h @@ -203,7 +203,9 @@ class RenderWidgetHost : public IPC::Channel::Listener, virtual void LostCapture(); // Tells us whether the page is rendered directly via the GPU process. - bool is_gpu_rendering_active() { return is_gpu_rendering_active_; } + bool is_accelerated_compositing_active() { + return is_accelerated_compositing_active_; + } // Notifies the RenderWidgetHost that the View was destroyed. void ViewDestroyed(); @@ -484,7 +486,7 @@ class RenderWidgetHost : public IPC::Channel::Listener, const gfx::Rect& caret_rect); void OnMsgImeCancelComposition(); - void OnMsgGpuRenderingActivated(bool activated); + void OnMsgDidActivateAcceleratedCompositing(bool activated); #if defined(OS_MACOSX) void OnMsgGetScreenInfo(gfx::NativeViewId view, @@ -564,7 +566,7 @@ class RenderWidgetHost : public IPC::Channel::Listener, bool is_hidden_; // True when a page is rendered directly via the GPU process. - bool is_gpu_rendering_active_; + bool is_accelerated_compositing_active_; // Set if we are waiting for a repaint ack for the view. bool repaint_ack_pending_; diff --git a/chrome/browser/renderer_host/render_widget_host_view.h b/chrome/browser/renderer_host/render_widget_host_view.h index 4ad2c41..8235ebf 100644 --- a/chrome/browser/renderer_host/render_widget_host_view.h +++ b/chrome/browser/renderer_host/render_widget_host_view.h @@ -246,6 +246,12 @@ class RenderWidgetHostView { virtual void AcceleratedCompositingActivated(bool activated) = 0; #endif +#if defined(OS_WIN) + virtual gfx::PluginWindowHandle CreateCompositorHostWindow() = 0; + virtual void WillWmDestroy() = 0; + virtual void ShowCompositorHostWindow(bool show) = 0; +#endif + // Toggles visual muting of the render view area. This is on when a // constrained window is showing. virtual void SetVisuallyDeemphasized(bool deemphasized) = 0; diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc index bf39966..aa43529 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc +++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc @@ -814,7 +814,7 @@ void RenderWidgetHostViewGtk::Paint(const gfx::Rect& damage_rect) { // If the GPU process is rendering directly into the View, // call the compositor directly. RenderWidgetHost* render_widget_host = GetRenderWidgetHost(); - if (render_widget_host->is_gpu_rendering_active()) { + if (render_widget_host->is_accelerated_compositing_active()) { host_->ScheduleComposite(); return; } diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.mm b/chrome/browser/renderer_host/render_widget_host_view_mac.mm index 307eb2e..b0ef7e6 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm @@ -745,7 +745,7 @@ void RenderWidgetHostViewMac::DidUpdateBackingStore( if (!is_hidden_) { std::vector<gfx::Rect> rects(copy_rects); - // Because the findbar might be open, we cannot use scrollRect:by: here. For + // Because the findbar might be open, we cannot use scrollRect:by: here. For // now, simply mark all of scroll rect as dirty. if (!scroll_rect.IsEmpty()) rects.push_back(scroll_rect); @@ -1019,8 +1019,8 @@ void RenderWidgetHostViewMac::UpdateRootGpuViewVisibility( // Plugins are destroyed on page navigate. The compositor layer on the other // hand is created on demand and then stays alive until its renderer process // dies (usually on cross-domain navigation). Instead, only a flag - // |is_gpu_rendering_active()| is flipped when the compositor output should be - // shown/hidden. + // |is_accelerated_compositing_active()| is flipped when the compositor output + // should be shown/hidden. // Show/hide the view belonging to the compositor here. plugin_container_manager_.set_gpu_rendering_active(show_gpu_widget); @@ -1085,9 +1085,9 @@ void RenderWidgetHostViewMac::AcknowledgeSwapBuffers( void RenderWidgetHostViewMac::GpuRenderingStateDidChange() { CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (GetRenderWidgetHost()->is_gpu_rendering_active()) { + if (GetRenderWidgetHost()->is_accelerated_compositing_active()) { UpdateRootGpuViewVisibility( - GetRenderWidgetHost()->is_gpu_rendering_active()); + GetRenderWidgetHost()->is_accelerated_compositing_active()); } else { needs_gpu_visibility_update_after_repaint_ = true; } @@ -1685,7 +1685,8 @@ void RenderWidgetHostViewMac::SetTextInputActive(bool active) { const gfx::Rect damagedRect([self flipNSRectToRect:dirtyRect]); - if (renderWidgetHostView_->render_widget_host_->is_gpu_rendering_active()) { + if (renderWidgetHostView_->render_widget_host_-> + is_accelerated_compositing_active()) { gfx::Rect gpuRect; gfx::PluginWindowHandle root_handle = diff --git a/chrome/browser/renderer_host/render_widget_host_view_views.cc b/chrome/browser/renderer_host/render_widget_host_view_views.cc index 20797ad..b9f386e 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_views.cc +++ b/chrome/browser/renderer_host/render_widget_host_view_views.cc @@ -350,7 +350,7 @@ void RenderWidgetHostViewViews::Paint(gfx::Canvas* canvas) { // Don't do any painting if the GPU process is rendering directly // into the View. RenderWidgetHost* render_widget_host = GetRenderWidgetHost(); - if (render_widget_host->is_gpu_rendering_active()) { + if (render_widget_host->is_accelerated_compositing_active()) { return; } @@ -603,7 +603,8 @@ bool RenderWidgetHostViewViews::ContainsNativeView( return false; } -void RenderWidgetHostViewViews::AcceleratedCompositingActivated(bool activated) { +void RenderWidgetHostViewViews::AcceleratedCompositingActivated( + bool activated) { // TODO(anicolao): figure out if we need something here if (activated) NOTIMPLEMENTED(); diff --git a/chrome/browser/renderer_host/render_widget_host_view_win.cc b/chrome/browser/renderer_host/render_widget_host_view_win.cc index 3f9b9b1..df78d00 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_win.cc +++ b/chrome/browser/renderer_host/render_widget_host_view_win.cc @@ -281,6 +281,7 @@ RenderWidgetHostView* RenderWidgetHostView::CreateViewForWidget( RenderWidgetHostViewWin::RenderWidgetHostViewWin(RenderWidgetHost* widget) : render_widget_host_(widget), + compositor_host_window_(NULL), track_mouse_leave_(false), ime_notification_(false), capture_enter_key_(false), @@ -382,6 +383,13 @@ void RenderWidgetHostViewWin::SetSize(const gfx::Size& size) { UINT swp_flags = SWP_NOSENDCHANGING | SWP_NOOWNERZORDER | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE; SetWindowPos(NULL, 0, 0, size.width(), size.height(), swp_flags); + if (compositor_host_window_) { + ::SetWindowPos(compositor_host_window_, + NULL, + 0, 0, + size.width(), size.height(), + SWP_NOSENDCHANGING | SWP_NOCOPYBITS | SWP_NOZORDER | SWP_NOACTIVATE); + } render_widget_host_->WasResized(); EnsureTooltip(); } @@ -709,6 +717,26 @@ void RenderWidgetHostViewWin::RenderViewGone() { DestroyWindow(); } +static BOOL CALLBACK AddChildWindowToVector(HWND hwnd, LPARAM lparam) { + std::vector<HWND>* vector = reinterpret_cast<std::vector<HWND>*>(lparam); + vector->push_back(hwnd); + return TRUE; +} + +void RenderWidgetHostViewWin::WillWmDestroy() { + if (!compositor_host_window_) + return; + + std::vector<HWND> all_child_windows; + ::EnumChildWindows(compositor_host_window_, AddChildWindowToVector, + reinterpret_cast<LPARAM>(&all_child_windows)); + if (all_child_windows.size()) { + DCHECK(all_child_windows.size() == 1); + ::ShowWindow(all_child_windows[0], SW_HIDE); + ::SetParent(all_child_windows[0], NULL); + } +} + void RenderWidgetHostViewWin::WillDestroyRenderWidget(RenderWidgetHost* rwh) { if (rwh == render_widget_host_) render_widget_host_ = NULL; @@ -722,6 +750,7 @@ void RenderWidgetHostViewWin::Destroy() { // OnFinalMessage(); close_on_deactivate_ = false; being_destroyed_ = true; + WillWmDestroy(); DestroyWindow(); } @@ -849,7 +878,7 @@ void RenderWidgetHostViewWin::OnPaint(HDC unused_dc) { // If the GPU process is rendering directly into the View, // call the compositor directly. RenderWidgetHost* render_widget_host = GetRenderWidgetHost(); - if (render_widget_host->is_gpu_rendering_active()) { + if (render_widget_host->is_accelerated_compositing_active()) { // We initialize paint_dc here so that BeginPaint()/EndPaint() // get called to validate the region. CPaintDC paint_dc(m_hWnd); @@ -1457,6 +1486,136 @@ void RenderWidgetHostViewWin::Observe(NotificationType type, browser_accessibility_manager_.reset(NULL); } +// Looks through the children windows of the CompositorHostWindow. If the +// compositor child window is found, its size is checked against the host +// window's size. If the child is smaller in either dimensions, we fill +// the host window with white to avoid unseemly cracks. +static void PaintCompositorHostWindow(HWND hWnd) { + PAINTSTRUCT paint; + BeginPaint(hWnd, &paint); + + std::vector<HWND> child_windows; + EnumChildWindows(hWnd, AddChildWindowToVector, + reinterpret_cast<LPARAM>(&child_windows)); + + if (child_windows.size()) { + HWND child = child_windows[0]; + + RECT host_rect, child_rect; + GetClientRect(hWnd, &host_rect); + if (GetClientRect(child, &child_rect)) { + if (child_rect.right < host_rect.right || + child_rect.bottom != host_rect.bottom) { + FillRect(paint.hdc, &host_rect, + static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH))); + } + } + } + EndPaint(hWnd, &paint); +} + +// WndProc for the compositor host window. We use this instead of Default so +// we can drop WM_PAINT and WM_ERASEBKGD messages on the floor. +static LRESULT CALLBACK CompositorHostWindowProc(HWND hWnd, UINT message, + WPARAM wParam, LPARAM lParam) { + switch (message) { + case WM_ERASEBKGND: + return 0; + case WM_DESTROY: + return 0; + case WM_PAINT: + PaintCompositorHostWindow(hWnd); + return 0; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } +} + +// Creates a HWND within the RenderWidgetHostView that will serve as a host +// for a HWND that the GPU process will create. The host window is used +// to Z-position the GPU's window relative to other plugin windows. +gfx::PluginWindowHandle RenderWidgetHostViewWin::CreateCompositorHostWindow() { + DCHECK(!compositor_host_window_); + static ATOM window_class = 0; + if (!window_class) { + WNDCLASSEX wcex; + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = 0; + wcex.lpfnWndProc = CompositorHostWindowProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = GetModuleHandle(NULL); + wcex.hIcon = 0; + wcex.hCursor = 0; + wcex.hbrBackground = NULL; + wcex.lpszMenuName = 0; + wcex.lpszClassName = L"CompositorHostWindowClass"; + wcex.hIconSm = 0; + window_class = RegisterClassEx(&wcex); + DCHECK(window_class); + } + + compositor_host_window_ = CreateWindowEx( + WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR, + MAKEINTATOM(window_class), 0, + WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_DISABLED, + 0, 0, 0, 0, m_hWnd, 0, GetModuleHandle(NULL), 0); + DCHECK(compositor_host_window_); + + // We need to not just "WM_SHOW" the new indow, but reparent it + // below any existing plugin existing windows. + ShowCompositorHostWindow(true); + + return static_cast<gfx::PluginWindowHandle>(compositor_host_window_); +} + +void RenderWidgetHostViewWin::ShowCompositorHostWindow(bool show) { + // When we first create the compositor, we will get a show request from + // the renderer before we have gotten the create request from the GPU. In this + // case, simply ignore the show request. + if (compositor_host_window_ == NULL) + return; + + if (show) { + UINT flags = SWP_NOSENDCHANGING | SWP_NOCOPYBITS | SWP_NOZORDER | + SWP_NOACTIVATE | SWP_DEFERERASE | SWP_SHOWWINDOW; + gfx::Rect rect = GetViewBounds(); + ::SetWindowPos(compositor_host_window_, NULL, 0, 0, + rect.width(), rect.height(), + flags); + + // Get all the child windows of this view, including the compositor window. + std::vector<HWND> all_child_windows; + ::EnumChildWindows(m_hWnd, AddChildWindowToVector, + reinterpret_cast<LPARAM>(&all_child_windows)); + + // Build a list of just the plugin window handles + std::vector<HWND> plugin_windows; + bool compositor_host_window_found = false; + for (size_t i = 0; i < all_child_windows.size(); ++i) { + if (all_child_windows[i] != compositor_host_window_) + plugin_windows.push_back(all_child_windows[i]); + else + compositor_host_window_found = true; + } + DCHECK(compositor_host_window_found); + + // Set all the plugin windows to be "after" the compositor window. + // When the compositor window is created, gets placed above plugins. + for (size_t i = 0; i < plugin_windows.size(); ++i) { + HWND next; + if (i + 1 < plugin_windows.size()) + next = plugin_windows[i+1]; + else + next = compositor_host_window_; + ::SetWindowPos(plugin_windows[i], next, 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); + } + } else { + ::ShowWindow(compositor_host_window_, SW_HIDE); + } +} + void RenderWidgetHostViewWin::SetAccessibilityFocus(int acc_obj_id) { if (!browser_accessibility_manager_.get() || !render_widget_host_ || diff --git a/chrome/browser/renderer_host/render_widget_host_view_win.h b/chrome/browser/renderer_host/render_widget_host_view_win.h index 13609e6..7f0a30e 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_win.h +++ b/chrome/browser/renderer_host/render_widget_host_view_win.h @@ -154,6 +154,7 @@ class RenderWidgetHostViewWin const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy, const std::vector<gfx::Rect>& copy_rects); virtual void RenderViewGone(); + virtual void WillWmDestroy(); // called by TabContents before DestroyWindow virtual void WillDestroyRenderWidget(RenderWidgetHost* rwh); virtual void Destroy(); virtual void SetTooltipText(const std::wstring& tooltip_text); @@ -161,6 +162,10 @@ class RenderWidgetHostViewWin virtual void SetBackground(const SkBitmap& background); virtual bool ContainsNativeView(gfx::NativeView native_view) const; virtual void SetVisuallyDeemphasized(bool deemphasized); + + virtual gfx::PluginWindowHandle CreateCompositorHostWindow(); + virtual void ShowCompositorHostWindow(bool show); + virtual void OnAccessibilityNotifications( const std::vector<ViewHostMsg_AccessibilityNotification_Params>& params); @@ -265,6 +270,9 @@ class RenderWidgetHostViewWin // The associated Model. RenderWidgetHost* render_widget_host_; + // When we are doing accelerated compositing + HWND compositor_host_window_; + // The cursor for the page. This is passed up from the renderer. WebCursor current_cursor_; diff --git a/chrome/browser/renderer_host/test/test_render_view_host.cc b/chrome/browser/renderer_host/test/test_render_view_host.cc index 65d82e9..e4dc729 100644 --- a/chrome/browser/renderer_host/test/test_render_view_host.cc +++ b/chrome/browser/renderer_host/test/test_render_view_host.cc @@ -181,6 +181,17 @@ void TestRenderWidgetHostView::AcceleratedSurfaceBuffersSwapped( void TestRenderWidgetHostView::GpuRenderingStateDidChange() { } +#elif defined(OS_WIN) +gfx::PluginWindowHandle TestRenderWidgetHostView::CreateCompositorHostWindow( + ) { + return gfx::kNullPluginWindow; +} + +void TestRenderWidgetHostView::WillWmDestroy() { +} + +void TestRenderWidgetHostView::ShowCompositorHostWindow(bool show) { +} #endif TestRenderViewHostFactory::TestRenderViewHostFactory( diff --git a/chrome/browser/renderer_host/test/test_render_view_host.h b/chrome/browser/renderer_host/test/test_render_view_host.h index fe6daa7..4f5d355 100644 --- a/chrome/browser/renderer_host/test/test_render_view_host.h +++ b/chrome/browser/renderer_host/test/test_render_view_host.h @@ -124,6 +124,10 @@ class TestRenderWidgetHostView : public RenderWidgetHostView { int32 route_id, uint64 swap_buffers_count); virtual void GpuRenderingStateDidChange(); +#elif defined(OS_WIN) + virtual gfx::PluginWindowHandle CreateCompositorHostWindow(); + virtual void WillWmDestroy(); + virtual void ShowCompositorHostWindow(bool show); #endif virtual void SetVisuallyDeemphasized(bool deemphasized) { } diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc index c846d62..4a225b2 100644 --- a/chrome/browser/tab_contents/tab_contents.cc +++ b/chrome/browser/tab_contents/tab_contents.cc @@ -486,8 +486,13 @@ TabContents::~TabContents() { #if defined(OS_WIN) // If we still have a window handle, destroy it. GetNativeView can return // NULL if this contents was part of a window that closed. - if (GetNativeView()) + if (GetNativeView()) { + RenderViewHost* host = render_view_host(); + if (host && host->view()) { + host->view()->WillWmDestroy(); + } ::DestroyWindow(GetNativeView()); + } #endif // OnCloseStarted isn't called in unit tests. diff --git a/chrome/common/gpu_messages_internal.h b/chrome/common/gpu_messages_internal.h index c124530..10b0961 100644 --- a/chrome/common/gpu_messages_internal.h +++ b/chrome/common/gpu_messages_internal.h @@ -113,6 +113,16 @@ IPC_BEGIN_MESSAGES(GpuHost) // should cause the browser to redraw the compositor's contents. IPC_MESSAGE_CONTROL1(GpuHostMsg_AcceleratedSurfaceBuffersSwapped, GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params) +#elif defined(OS_WIN) + // Create and get the HWND for the compositor window + IPC_SYNC_MESSAGE_CONTROL2_1(GpuHostMsg_CreateCompositorHostWindow, + int32, /* renderer_id */ + int32, /* render_view_id */ + gfx::PluginWindowHandle /* compositor_host_id */) + + IPC_MESSAGE_CONTROL2(GpuHostMsg_ScheduleComposite, + int32, /* renderer_id */ + int32 /* render_view_id */) #endif IPC_END_MESSAGES(GpuHost) diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 41b9dca..2d82061 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -1315,10 +1315,10 @@ IPC_BEGIN_MESSAGES(ViewHost) IPC_MESSAGE_ROUTED1(ViewHostMsg_UpdateRect, ViewHostMsg_UpdateRect_Params) - // Sent by the renderer when GPU compositing is enabled or disabled to notify - // the browser whether or not is should do paiting. - IPC_MESSAGE_ROUTED1(ViewHostMsg_GpuRenderingActivated, - bool /* true if the GPU process renders to window */) + // Sent by the renderer when accelerated compositing is enabled or disabled to + // notify the browser whether or not is should do painting. + IPC_MESSAGE_ROUTED1(ViewHostMsg_DidActivateAcceleratedCompositing, + bool /* true if the accelerated compositor is actve */) // Acknowledges receipt of a ViewMsg_HandleInputEvent message. // Payload is a WebInputEvent::Type which is the type of the event, followed diff --git a/chrome/gpu/gpu_channel.cc b/chrome/gpu/gpu_channel.cc index 7cd06d2..6d97a3d 100644 --- a/chrome/gpu/gpu_channel.cc +++ b/chrome/gpu/gpu_channel.cc @@ -133,6 +133,10 @@ void GpuChannel::OnCreateViewCommandBuffer( GetProp(view, chrome::kChromiumRendererIdProperty)); if (view_renderer_id != renderer_id_) return; + + // Note, we don't actually render into the view HWND. Instead, inside + // the GpuCommandBufferStub, we will create a child window within the view + // HWND into which we will render. handle = view; #elif defined(OS_LINUX) ChildThread* gpu_thread = ChildThread::current(); diff --git a/chrome/gpu/gpu_command_buffer_stub.cc b/chrome/gpu/gpu_command_buffer_stub.cc index 1872246..3c87c99 100644 --- a/chrome/gpu/gpu_command_buffer_stub.cc +++ b/chrome/gpu/gpu_command_buffer_stub.cc @@ -14,6 +14,10 @@ using gpu::Buffer; +#if defined(OS_WIN) +#define kCompositorWindowOwner L"CompositorWindowOwner" +#endif + GpuCommandBufferStub::GpuCommandBufferStub( GpuChannel* channel, gfx::PluginWindowHandle handle, @@ -38,10 +42,124 @@ GpuCommandBufferStub::GpuCommandBufferStub( render_view_id_(render_view_id) { } +#if defined(OS_WIN) +static LRESULT CALLBACK CompositorWindowProc( + HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam) { + switch (message) { + case WM_ERASEBKGND: + return 0; + case WM_DESTROY: + RemoveProp(hwnd, kCompositorWindowOwner); + return 0; + case WM_PAINT: { + PAINTSTRUCT paint; + HDC dc = BeginPaint(hwnd, &paint); + if (dc) { + HANDLE h = GetProp(hwnd, kCompositorWindowOwner); + if (h) { + GpuCommandBufferStub* stub = + reinterpret_cast<GpuCommandBufferStub*>(h); + stub->OnCompositorWindowPainted(); + } + EndPaint(hwnd, &paint); + } + break; + } + default: + return DefWindowProc(hwnd, message, wparam, lparam); + } + return 0; +} + +bool GpuCommandBufferStub::CreateCompositorWindow() { + DCHECK(handle_ != gfx::kNullPluginWindow); + + // Ask the browser to create the the host window. + ChildThread* gpu_thread = ChildThread::current(); + gfx::PluginWindowHandle host_window_id = gfx::kNullPluginWindow; + gpu_thread->Send(new GpuHostMsg_CreateCompositorHostWindow( + renderer_id_, + render_view_id_, + &host_window_id)); + if (host_window_id == gfx::kNullPluginWindow) + return false; + HWND host_window = static_cast<HWND>(host_window_id); + + // Create the compositor window itself. + DCHECK(host_window); + static ATOM window_class = 0; + if (!window_class) { + WNDCLASSEX wcex; + wcex.cbSize = sizeof(wcex); + wcex.style = 0; + wcex.lpfnWndProc = CompositorWindowProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = GetModuleHandle(NULL); + wcex.hIcon = 0; + wcex.hCursor = 0; + wcex.hbrBackground = NULL; + wcex.lpszMenuName = 0; + wcex.lpszClassName = L"CompositorWindowClass"; + wcex.hIconSm = 0; + window_class = RegisterClassEx(&wcex); + DCHECK(window_class); + } + + HWND compositor_window = CreateWindowEx( + WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR, + MAKEINTATOM(window_class), + 0, + WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_DISABLED, + 0, 0, + 0, 0, + host_window, + 0, + GetModuleHandle(NULL), + 0); + if (!compositor_window) { + compositor_window_ = gfx::kNullPluginWindow; + return false; + } + SetProp(compositor_window, kCompositorWindowOwner, + reinterpret_cast<HANDLE>(this)); + + RECT parent_rect; + GetClientRect(host_window, &parent_rect); + + UINT flags = SWP_NOSENDCHANGING | SWP_NOCOPYBITS | SWP_NOZORDER | + SWP_NOACTIVATE | SWP_DEFERERASE | SWP_SHOWWINDOW; + SetWindowPos(compositor_window, + NULL, + 0, 0, + parent_rect.right - parent_rect.left, + parent_rect.bottom - parent_rect.top, + flags); + compositor_window_ = static_cast<gfx::PluginWindowHandle>(compositor_window); + return true; +} + +void GpuCommandBufferStub::OnCompositorWindowPainted() { + ChildThread* gpu_thread = ChildThread::current(); + gpu_thread->Send(new GpuHostMsg_ScheduleComposite( + renderer_id_, render_view_id_)); +} +#endif // defined(OS_WIN) + + GpuCommandBufferStub::~GpuCommandBufferStub() { if (processor_.get()) { processor_->Destroy(); } +#if defined(OS_WIN) + if (compositor_window_) { + DestroyWindow(static_cast<HWND>(compositor_window_)); + compositor_window_ = NULL; + } +#endif } void GpuCommandBufferStub::OnMessageReceived(const IPC::Message& message) { @@ -79,6 +197,21 @@ void GpuCommandBufferStub::OnInitialize( command_buffer_.reset(new gpu::CommandBufferService); + // Create the child window, if needed +#if defined(OS_WIN) + gfx::PluginWindowHandle output_window_handle; + if (handle_) { + if (!CreateCompositorWindow()) { + return; + } + output_window_handle = compositor_window_; + } else { + output_window_handle = handle_; + } +#else + gfx::PluginWindowHandle output_window_handle = handle_; +#endif + // Initialize the CommandBufferService and GPUProcessor. if (command_buffer_->Initialize(size)) { Buffer buffer = command_buffer_->GetRingBuffer(); @@ -87,7 +220,7 @@ void GpuCommandBufferStub::OnInitialize( parent_ ? parent_->processor_.get() : NULL; processor_.reset(new gpu::GPUProcessor(command_buffer_.get(), NULL)); if (processor_->Initialize( - handle_, + output_window_handle, initial_size_, allowed_extensions_.c_str(), requested_attribs_, @@ -113,10 +246,10 @@ void GpuCommandBufferStub::OnInitialize( NewCallback(this, &GpuCommandBufferStub::SwapBuffersCallback)); } -#elif defined(OS_LINUX) +#elif defined(OS_LINUX) || defined(OS_WIN) if (handle_) { - // Set up a pathway to allow the Gpu process to ask the browser - // for a window resize. + // Set up a pathway for resizing the output window at the right time + // relative to other GL commands. processor_->SetResizeCallback( NewCallback(this, &GpuCommandBufferStub::ResizeCallback)); @@ -227,13 +360,21 @@ void GpuCommandBufferStub::AcceleratedSurfaceBuffersSwapped( } #endif // defined(OS_MACOSX) -#if defined(OS_LINUX) void GpuCommandBufferStub::ResizeCallback(gfx::Size size) { + if (handle_ == gfx::kNullPluginWindow) + return; + +#if defined(OS_LINUX) ChildThread* gpu_thread = ChildThread::current(); bool result = false; gpu_thread->Send( new GpuHostMsg_ResizeXID(handle_, size, &result)); +#elif defined(OS_WIN) + HWND hwnd = static_cast<HWND>(compositor_window_); + UINT swp_flags = SWP_NOSENDCHANGING | SWP_NOOWNERZORDER | SWP_NOCOPYBITS | + SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE; + SetWindowPos(hwnd, NULL, 0, 0, size.width(), size.height(), swp_flags); +#endif } -#endif // defined(OS_LINUX) #endif // ENABLE_GPU diff --git a/chrome/gpu/gpu_command_buffer_stub.h b/chrome/gpu/gpu_command_buffer_stub.h index ef57715..6d888aa 100644 --- a/chrome/gpu/gpu_command_buffer_stub.h +++ b/chrome/gpu/gpu_command_buffer_stub.h @@ -51,6 +51,11 @@ class GpuCommandBufferStub int32 route_id() const { return route_id_; } +#if defined(OS_WIN) + // Called only by the compositor window's window proc + void OnCompositorWindowPainted(); +#endif + #if defined(OS_MACOSX) // Called only by the GpuChannel. void AcceleratedSurfaceBuffersSwapped(uint64 swap_buffers_count); @@ -75,11 +80,12 @@ class GpuCommandBufferStub #if defined(OS_MACOSX) void OnSetWindowSize(const gfx::Size& size); void SwapBuffersCallback(); +#elif defined(OS_WIN) + bool CreateCompositorWindow(); + HWND compositor_window_; #endif -#if defined(OS_LINUX) void ResizeCallback(gfx::Size size); -#endif // The lifetime of objects of this class is managed by a GpuChannel. The // GpuChannels destroy all the GpuCommandBufferStubs that they own when they diff --git a/chrome/renderer/render_widget.cc b/chrome/renderer/render_widget.cc index bcf58b0..ee1ccd9 100644 --- a/chrome/renderer/render_widget.cc +++ b/chrome/renderer/render_widget.cc @@ -523,8 +523,7 @@ void RenderWidget::DoDeferredUpdate() { dib_id = current_paint_buf_->id(); } else { // Accelerated compositing path // Begin painting. - bool finish = next_paint_is_resize_ack(); - webwidget_->composite(finish); + webwidget_->composite(false); } // sending an ack to browser process that the paint is complete... @@ -628,7 +627,7 @@ void RenderWidget::didScrollRect(int dx, int dy, const WebRect& clip_rect) { void RenderWidget::didActivateAcceleratedCompositing(bool active) { is_accelerated_compositing_active_ = active; - Send(new ViewHostMsg_GpuRenderingActivated( + Send(new ViewHostMsg_DidActivateAcceleratedCompositing( routing_id_, is_accelerated_compositing_active_)); } |