From c91bba7af3215107916a135733dcf428f57a564f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCri=20Valdmann?= Date: Thu, 16 Aug 2018 11:10:33 +0200 Subject: Extract Compositor from RenderWidgetHostViewQt Split compositing-related functionality from RenderWidgetHostViewQt into a new class Compositor. Change-Id: I97b26a6057734cd8ce8c1df29b373888f7a07c1c Reviewed-by: Allan Sandfeld Jensen --- src/core/compositor.cpp | 170 ++++++++++++++++++++++++++++++++ src/core/compositor.h | 120 ++++++++++++++++++++++ src/core/core_chromium.pri | 2 + src/core/render_widget_host_view_qt.cpp | 85 ++-------------- src/core/render_widget_host_view_qt.h | 19 +--- 5 files changed, 303 insertions(+), 93 deletions(-) create mode 100644 src/core/compositor.cpp create mode 100644 src/core/compositor.h diff --git a/src/core/compositor.cpp b/src/core/compositor.cpp new file mode 100644 index 000000000..20d956ab4 --- /dev/null +++ b/src/core/compositor.cpp @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "compositor.h" + +#include "delegated_frame_node.h" + +#include +#include +#include + +namespace QtWebEngineCore { + +Compositor::Compositor() + : m_chromiumCompositorData(new ChromiumCompositorData) +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + base::SingleThreadTaskRunner *taskRunner = + content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI).get(); + m_beginFrameSource = + std::make_unique( + std::make_unique(taskRunner), + viz::BeginFrameSource::kNotRestartableId); +} + +Compositor::~Compositor() +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); +} + +void Compositor::setViewDelegate(RenderWidgetHostViewQtDelegate *viewDelegate) +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + m_viewDelegate = viewDelegate; +} + +void Compositor::setFrameSinkClient(viz::mojom::CompositorFrameSinkClient *frameSinkClient) +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + if (m_frameSinkClient == frameSinkClient) + return; + + // Accumulated resources belong to the old RendererCompositorFrameSink and + // should not be returned. + // + // TODO(juvaldma): Can there be a pending frame from the old client? + m_resourcesToRelease.clear(); + m_frameSinkClient = frameSinkClient; +} + +void Compositor::setNeedsBeginFrames(bool needsBeginFrames) +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + if (m_needsBeginFrames == needsBeginFrames) + return; + + if (needsBeginFrames) + m_beginFrameSource->AddObserver(this); + else + m_beginFrameSource->RemoveObserver(this); + + m_needsBeginFrames = needsBeginFrames; +} + +void Compositor::submitFrame(viz::CompositorFrame frame) +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(!m_havePendingFrame); + + m_chromiumCompositorData->frameDevicePixelRatio = frame.metadata.device_scale_factor; + m_chromiumCompositorData->previousFrameData = std::move(m_chromiumCompositorData->frameData); + m_chromiumCompositorData->frameData = std::move(frame); + m_havePendingFrame = true; + + // Tell viewDelegate to call updatePaintNode() soon. + m_viewDelegate->update(); +} + +QSGNode *Compositor::updatePaintNode(QSGNode *oldNode) +{ + // DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + // + // This might be called from a Qt Quick render thread, but the UI thread + // will still be blocked for the duration of this call. + + DelegatedFrameNode *frameNode = static_cast(oldNode); + if (!frameNode) + frameNode = new DelegatedFrameNode; + + frameNode->commit(m_chromiumCompositorData.data(), &m_resourcesToRelease, m_viewDelegate); + + if (m_havePendingFrame) { + m_havePendingFrame = false; + content::BrowserThread::PostTask( + content::BrowserThread::UI, FROM_HERE, + base::BindOnce(&Compositor::notifyFrameCommitted, m_weakPtrFactory.GetWeakPtr())); + } + + return frameNode; +} + +void Compositor::notifyFrameCommitted() +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + m_beginFrameSource->DidFinishFrame(this); + if (m_frameSinkClient) + m_frameSinkClient->DidReceiveCompositorFrameAck(m_resourcesToRelease); + m_resourcesToRelease.clear(); +} + +bool Compositor::OnBeginFrameDerivedImpl(const viz::BeginFrameArgs &args) +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + m_beginFrameSource->OnUpdateVSyncParameters(args.frame_time, args.interval); + if (m_frameSinkClient) + m_frameSinkClient->OnBeginFrame(args); + + return true; +} + +void Compositor::OnBeginFrameSourcePausedChanged(bool) +{ + // Ignored for now. If the begin frame source is paused, the renderer + // doesn't need to be informed about it and will just not receive more + // begin frames. +} + +} // namespace QtWebEngineCore diff --git a/src/core/compositor.h b/src/core/compositor.h new file mode 100644 index 000000000..4456c648b --- /dev/null +++ b/src/core/compositor.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef COMPOSITOR_H +#define COMPOSITOR_H + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE +class QSGNode; +QT_END_NAMESPACE + +namespace viz { +class CompositorFrame; +struct ReturnedResource; +namespace mojom { +class CompositorFrameSinkClient; +} // namespace mojom +} // namespace viz + +namespace QtWebEngineCore { + +class RenderWidgetHostViewQtDelegate; +class ChromiumCompositorData; + +// Receives viz::CompositorFrames from child compositors and provides QSGNodes +// to the Qt Quick renderer. +// +// The life cycle of a frame: +// +// Step 1. A new CompositorFrame is received from child compositors and handed +// off to submitFrame(). The new frame will start off in a pending state. +// +// Step 2. Once the new frame is ready to be rendered, Compositor will call +// update() on the delegate. +// +// Step 3. Once the delegate is ready to render, updatePaintNode() should be +// called to receive the scene graph for the new frame. This call will commit +// the pending frame. Until the next frame is ready, all subsequent calls to +// updatePaintNode() will keep using this same committed frame. +// +// Step 4. The Compositor will return unneeded resources back to the child +// compositors. Go to step 1. +class Compositor final : private viz::BeginFrameObserverBase +{ +public: + explicit Compositor(); + ~Compositor() override; + + void setViewDelegate(RenderWidgetHostViewQtDelegate *viewDelegate); + void setFrameSinkClient(viz::mojom::CompositorFrameSinkClient *frameSinkClient); + void setNeedsBeginFrames(bool needsBeginFrames); + + void submitFrame(viz::CompositorFrame frame); + + QSGNode *updatePaintNode(QSGNode *oldNode); + +private: + void notifyFrameCommitted(); + + // viz::BeginFrameObserverBase + bool OnBeginFrameDerivedImpl(const viz::BeginFrameArgs &args) override; + void OnBeginFrameSourcePausedChanged(bool paused) override; + + std::vector m_resourcesToRelease; + QExplicitlySharedDataPointer m_chromiumCompositorData; + RenderWidgetHostViewQtDelegate *m_viewDelegate = nullptr; + std::unique_ptr m_beginFrameSource; + viz::mojom::CompositorFrameSinkClient *m_frameSinkClient = nullptr; + bool m_havePendingFrame = false; + bool m_needsBeginFrames = false; + + base::WeakPtrFactory m_weakPtrFactory{this}; + + DISALLOW_COPY_AND_ASSIGN(Compositor); +}; + +} // namespace QtWebEngineCore + +#endif // !COMPOSITOR_H diff --git a/src/core/core_chromium.pri b/src/core/core_chromium.pri index a3f9f5c80..92ab80c6c 100644 --- a/src/core/core_chromium.pri +++ b/src/core/core_chromium.pri @@ -53,6 +53,7 @@ SOURCES = \ common/qt_ipc_logging.cpp \ common/qt_messages.cpp \ common/user_script_data.cpp \ + compositor.cpp \ content_client_qt.cpp \ content_browser_client_qt.cpp \ content_main_delegate_qt.cpp \ @@ -139,6 +140,7 @@ HEADERS = \ color_chooser_controller.h \ common/qt_messages.h \ common/user_script_data.h \ + compositor.h \ content_client_qt.h \ content_browser_client_qt.h \ content_main_delegate_qt.h \ diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index 7d70da9ec..a3c5b06d1 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -43,7 +43,7 @@ #include "browser_accessibility_manager_qt.h" #include "browser_accessibility_qt.h" #include "chromium_overrides.h" -#include "delegated_frame_node.h" +#include "compositor.h" #include "qtwebenginecoreglobal_p.h" #include "render_widget_host_view_qt_delegate.h" #include "type_conversion.h" @@ -324,17 +324,12 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost *widget , m_gestureProvider(QtGestureProviderConfig(), this) , m_sendMotionActionDown(false) , m_touchMotionStarted(false) - , m_chromiumCompositorData(new ChromiumCompositorData) - , m_needsDelegatedFrameAck(false) + , m_compositor(new Compositor) , m_loadVisuallyCommittedState(NotCommitted) , m_adapterClient(0) - , m_rendererCompositorFrameSink(0) , m_imeInProgress(false) , m_receivedEmptyImeEvent(false) , m_initPending(false) - , m_beginFrameSource(nullptr) - , m_needsBeginFrames(false) - , m_addedFrameObserver(false) , m_backgroundColor(SK_ColorWHITE) , m_imState(0) , m_anchorPositionWithinSelection(-1) @@ -343,10 +338,6 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost *widget , m_emptyPreviousSelection(true) , m_wheelAckPending(false) { - auto* task_runner = base::ThreadTaskRunnerHandle::Get().get(); - m_beginFrameSource.reset(new viz::DelayBasedBeginFrameSource( - std::make_unique(task_runner), 0)); - host()->SetView(this); #ifndef QT_NO_ACCESSIBILITY if (isAccessibilityEnabled()) { @@ -377,6 +368,7 @@ RenderWidgetHostViewQt::~RenderWidgetHostViewQt() void RenderWidgetHostViewQt::setDelegate(RenderWidgetHostViewQtDelegate* delegate) { m_delegate.reset(delegate); + m_compositor->setViewDelegate(delegate); } void RenderWidgetHostViewQt::setAdapterClient(WebContentsAdapterClient *adapterClient) @@ -751,10 +743,7 @@ void RenderWidgetHostViewQt::DisplayTooltipText(const base::string16 &tooltip_te void RenderWidgetHostViewQt::DidCreateNewRendererCompositorFrameSink(viz::mojom::CompositorFrameSinkClient *frameSink) { - // Accumulated resources belong to the old RendererCompositorFrameSink and - // should not be returned. - m_resourcesToRelease.clear(); - m_rendererCompositorFrameSink = frameSink; + m_compositor->setFrameSinkClient(frameSink); } void RenderWidgetHostViewQt::SubmitCompositorFrame(const viz::LocalSurfaceId &local_surface_id, viz::CompositorFrame frame, viz::mojom::HitTestRegionListPtr) @@ -769,11 +758,6 @@ void RenderWidgetHostViewQt::SubmitCompositorFrame(const viz::LocalSurfaceId &lo // FIXME: update frame_size and device_scale_factor? // FIXME: showPrimarySurface()? } - Q_ASSERT(!m_needsDelegatedFrameAck); - m_needsDelegatedFrameAck = true; - m_chromiumCompositorData->previousFrameData = std::move(m_chromiumCompositorData->frameData); - m_chromiumCompositorData->frameDevicePixelRatio = frame.metadata.device_scale_factor; - m_chromiumCompositorData->frameData = std::move(frame); // Force to process swap messages uint32_t frame_token = frame.metadata.frame_token; @@ -783,9 +767,9 @@ void RenderWidgetHostViewQt::SubmitCompositorFrame(const viz::LocalSurfaceId &lo // Support experimental.viewport.devicePixelRatio, see GetScreenInfo implementation below. float dpiScale = this->dpiScale(); if (dpiScale != 0 && dpiScale != 1) - m_chromiumCompositorData->frameDevicePixelRatio /= dpiScale; + frame.metadata.device_scale_factor /= dpiScale; - m_delegate->update(); + m_compositor->submitFrame(std::move(frame)); if (m_loadVisuallyCommittedState == NotCommitted) { m_loadVisuallyCommittedState = DidFirstCompositorFrameSwap; @@ -977,21 +961,7 @@ void RenderWidgetHostViewQt::OnGestureEvent(const ui::GestureEventData& gesture) QSGNode *RenderWidgetHostViewQt::updatePaintNode(QSGNode *oldNode) { - DelegatedFrameNode *frameNode = static_cast(oldNode); - if (!frameNode) - frameNode = new DelegatedFrameNode; - - frameNode->commit(m_chromiumCompositorData.data(), &m_resourcesToRelease, m_delegate.get()); - - // This is possibly called from the Qt render thread, post the ack back to the UI - // to tell the child compositors to release resources and trigger a new frame. - if (m_needsDelegatedFrameAck) { - m_needsDelegatedFrameAck = false; - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - base::Bind(&RenderWidgetHostViewQt::sendDelegatedFrameAck, AsWeakPtr())); - } - - return frameNode; + return m_compositor->updatePaintNode(oldNode); } void RenderWidgetHostViewQt::notifyResize() @@ -1192,15 +1162,6 @@ void RenderWidgetHostViewQt::ProcessAckedTouchEvent(const content::TouchEventWit m_gestureProvider.OnTouchEventAck(touch.event.unique_touch_event_id, eventConsumed, /*fixme: ?? */false); } -void RenderWidgetHostViewQt::sendDelegatedFrameAck() -{ - m_beginFrameSource->DidFinishFrame(this); - std::vector resources; - m_resourcesToRelease.swap(resources); - if (m_rendererCompositorFrameSink) - m_rendererCompositorFrameSink->DidReceiveCompositorFrameAck(resources); -} - void RenderWidgetHostViewQt::processMotionEvent(const ui::MotionEvent &motionEvent) { auto result = m_gestureProvider.OnTouchEvent(motionEvent); @@ -1713,37 +1674,7 @@ void RenderWidgetHostViewQt::handleFocusEvent(QFocusEvent *ev) void RenderWidgetHostViewQt::SetNeedsBeginFrames(bool needs_begin_frames) { - m_needsBeginFrames = needs_begin_frames; - updateNeedsBeginFramesInternal(); -} - -void RenderWidgetHostViewQt::updateNeedsBeginFramesInternal() -{ - Q_ASSERT(m_beginFrameSource); - - if (m_addedFrameObserver == m_needsBeginFrames) - return; - - if (m_needsBeginFrames) - m_beginFrameSource->AddObserver(this); - else - m_beginFrameSource->RemoveObserver(this); - m_addedFrameObserver = m_needsBeginFrames; -} - -bool RenderWidgetHostViewQt::OnBeginFrameDerivedImpl(const viz::BeginFrameArgs& args) -{ - m_beginFrameSource->OnUpdateVSyncParameters(args.frame_time, args.interval); - if (m_rendererCompositorFrameSink) - m_rendererCompositorFrameSink->OnBeginFrame(args); - return true; -} - -void RenderWidgetHostViewQt::OnBeginFrameSourcePausedChanged(bool paused) -{ - // Ignored for now. If the begin frame source is paused, the renderer - // doesn't need to be informed about it and will just not receive more - // begin frames. + m_compositor->setNeedsBeginFrames(needs_begin_frames); } content::RenderFrameHost *RenderWidgetHostViewQt::getFocusedFrameHost() diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h index 664359eb1..909b3bd84 100644 --- a/src/core/render_widget_host_view_qt.h +++ b/src/core/render_widget_host_view_qt.h @@ -58,8 +58,6 @@ #include #include -#include "delegated_frame_node.h" - QT_BEGIN_NAMESPACE class QAccessibleInterface; QT_END_NAMESPACE @@ -71,6 +69,8 @@ class RenderWidgetHostImpl; namespace QtWebEngineCore { +class Compositor; + struct MultipleMouseClickHelper { QPoint lastPressPosition; @@ -92,7 +92,6 @@ class RenderWidgetHostViewQt , public ui::GestureProviderClient , public RenderWidgetHostViewQtDelegateClient , public base::SupportsWeakPtr - , public viz::BeginFrameObserverBase #ifndef QT_NO_ACCESSIBILITY , public QAccessible::ActivationObserver #endif // QT_NO_ACCESSIBILITY @@ -173,10 +172,6 @@ public: void OnSelectionBoundsChanged(content::TextInputManager *text_input_manager, RenderWidgetHostViewBase *updated_view) override; void OnTextSelectionChanged(content::TextInputManager *text_input_manager, RenderWidgetHostViewBase *updated_view) override; - // cc::BeginFrameObserverBase implementation. - bool OnBeginFrameDerivedImpl(const viz::BeginFrameArgs& args) override; - void OnBeginFrameSourcePausedChanged(bool paused) override; - void handleMouseEvent(QMouseEvent*); void handleKeyEvent(QKeyEvent*); void handleWheelEvent(QWheelEvent*); @@ -213,7 +208,6 @@ public: gfx::Vector2dF lastScrollOffset() const { return m_lastScrollOffset; } private: - void sendDelegatedFrameAck(); void processMotionEvent(const ui::MotionEvent &motionEvent); void clearPreviousTouchMotionState(); QList mapTouchPointIds(const QList &inputPoints); @@ -234,15 +228,12 @@ private: QList m_previousTouchPoints; std::unique_ptr m_delegate; - QExplicitlySharedDataPointer m_chromiumCompositorData; - std::vector m_resourcesToRelease; - bool m_needsDelegatedFrameAck; + std::unique_ptr m_compositor; LoadVisuallyCommittedState m_loadVisuallyCommittedState; QMetaObject::Connection m_adapterClientDestroyedConnection; WebContentsAdapterClient *m_adapterClient; MultipleMouseClickHelper m_clickHelper; - viz::mojom::CompositorFrameSinkClient *m_rendererCompositorFrameSink; bool m_imeInProgress; bool m_receivedEmptyImeEvent; @@ -250,10 +241,6 @@ private: bool m_initPending; - std::unique_ptr m_beginFrameSource; - bool m_needsBeginFrames; - bool m_addedFrameObserver; - gfx::Vector2dF m_lastScrollOffset; gfx::SizeF m_lastContentsSize; SkColor m_backgroundColor; -- cgit v1.2.3