diff options
Diffstat (limited to 'src/core/compositor/compositor.cpp')
-rw-r--r-- | src/core/compositor/compositor.cpp | 252 |
1 files changed, 113 insertions, 139 deletions
diff --git a/src/core/compositor/compositor.cpp b/src/core/compositor/compositor.cpp index 56693961c..4c0bd4c0d 100644 --- a/src/core/compositor/compositor.cpp +++ b/src/core/compositor/compositor.cpp @@ -1,188 +1,162 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "compositor.h" -#include "compositor_resource_tracker.h" -#include "delegated_frame_node.h" +#include "base/memory/ref_counted.h" +#include "components/viz/common/surfaces/frame_sink_id.h" -#include "base/task/post_task.h" -#include "components/viz/common/resources/returned_resource.h" -#include "content/public/browser/browser_task_traits.h" -#include "content/public/browser/browser_thread.h" -#include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom.h" +#include <QHash> +#include <QMutex> +#include <QQuickWindow> namespace QtWebEngineCore { -Compositor::Compositor(content::RenderWidgetHost *host) - : m_resourceTracker(new CompositorResourceTracker) - , m_host(host) -{ - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); +// Compositor::Id - m_taskRunner = base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::UI, base::TaskPriority::USER_VISIBLE}); - m_beginFrameSource = - std::make_unique<viz::DelayBasedBeginFrameSource>( - std::make_unique<viz::DelayBasedTimeSource>(m_taskRunner.get()), - viz::BeginFrameSource::kNotRestartableId); -} +Compositor::Id::Id(viz::FrameSinkId fid) : client_id(fid.client_id()), sink_id(fid.sink_id()) { } -Compositor::~Compositor() +static size_t qHash(Compositor::Id id, size_t seed = 0) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + QtPrivate::QHashCombine hasher; + seed = hasher(seed, id.client_id); + seed = hasher(seed, id.sink_id); + return seed; } -void Compositor::setFrameSinkClient(viz::mojom::CompositorFrameSinkClient *frameSinkClient) +static bool operator==(Compositor::Id id1, Compositor::Id id2) { - 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_resourceTracker->returnResources(); - m_frameSinkClient = frameSinkClient; + return id1.client_id == id2.client_id && id1.sink_id == id2.sink_id; } -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); +// Compositor::Binding and Compositor::Bindings - m_needsBeginFrames = needsBeginFrames; -} - -void Compositor::submitFrame(viz::CompositorFrame frame, base::OnceClosure callback) +struct Compositor::Binding { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - DCHECK(!m_submitCallback); + const Id id; + Compositor *compositor = nullptr; + Observer *observer = nullptr; - m_pendingFrame = std::move(frame); - m_submitCallback = std::move(callback); - m_resourceTracker->submitResources( - m_pendingFrame, - base::BindOnce(&Compositor::runSubmitCallback, base::Unretained(this))); -} + Binding(Id id) : id(id) { } + ~Binding(); +}; -QSGNode *Compositor::updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *viewDelegate) +class Compositor::BindingMap { - // 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. +public: + void lock() { m_mutex.lock(); } - DelegatedFrameNode *frameNode = static_cast<DelegatedFrameNode *>(oldNode); - if (!frameNode) - frameNode = new DelegatedFrameNode; + void unlock() { m_mutex.unlock(); } - if (!m_updatePaintNodeShouldCommit) { - frameNode->commit(m_committedFrame, viz::CompositorFrame(), m_resourceTracker.get(), viewDelegate); - return frameNode; + Binding *findOrCreate(Id id) + { + auto it = m_map.find(id); + if (it == m_map.end()) + it = m_map.insert(id, new Binding(id)); + return *it; } - m_updatePaintNodeShouldCommit = false; - gfx::PresentationFeedback dummyFeedback(base::TimeTicks::Now(), base::TimeDelta(), gfx::PresentationFeedback::Flags::kVSync); - m_presentations.insert({m_committedFrame.metadata.frame_token, dummyFeedback}); + void remove(Id id) { m_map.remove(id); } - m_resourceTracker->commitResources(); - frameNode->commit(m_pendingFrame, m_committedFrame, m_resourceTracker.get(), viewDelegate); - m_committedFrame = std::move(m_pendingFrame); - m_pendingFrame = viz::CompositorFrame(); +private: + QMutex m_mutex; + QHash<Id, Binding *> m_map; +} static g_bindings; - m_taskRunner->PostTask(FROM_HERE, - base::BindOnce(&Compositor::notifyFrameCommitted, m_weakPtrFactory.GetWeakPtr())); +Compositor::Binding::~Binding() +{ + g_bindings.remove(id); +} + +// Compositor::Observer - return frameNode; +void Compositor::Observer::bind(Id id) +{ + DCHECK(!m_binding); + g_bindings.lock(); + m_binding = g_bindings.findOrCreate(id); + DCHECK(!m_binding->observer); + m_binding->observer = this; + g_bindings.unlock(); } -void Compositor::runSubmitCallback() +void Compositor::Observer::unbind() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(m_binding); + g_bindings.lock(); + m_binding->observer = nullptr; + if (m_binding->compositor == nullptr) + delete m_binding; + m_binding = nullptr; + g_bindings.unlock(); +} - m_updatePaintNodeShouldCommit = true; - std::move(m_submitCallback).Run(); +Compositor::Handle<Compositor> Compositor::Observer::compositor() +{ + g_bindings.lock(); + if (m_binding && m_binding->compositor) + return m_binding->compositor; // delay unlock + g_bindings.unlock(); + return nullptr; } -void Compositor::notifyFrameCommitted() +// Compositor + +void Compositor::bind(Id id) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(!m_binding); + g_bindings.lock(); + m_binding = g_bindings.findOrCreate(id); + DCHECK(!m_binding->compositor); + m_binding->compositor = this; + g_bindings.unlock(); +} - m_beginFrameSource->DidFinishFrame(this); - if (m_frameSinkClient) - m_frameSinkClient->DidReceiveCompositorFrameAck(m_resourceTracker->returnResources()); +void Compositor::unbind() +{ + DCHECK(m_binding); + g_bindings.lock(); + m_binding->compositor = nullptr; + if (m_binding->observer == nullptr) + delete m_binding; + m_binding = nullptr; + g_bindings.unlock(); } -void Compositor::sendPresentationFeedback(uint frame_token) +Compositor::Handle<Compositor::Observer> Compositor::observer() { - gfx::PresentationFeedback dummyFeedback(base::TimeTicks::Now(), base::TimeDelta(), gfx::PresentationFeedback::Flags::kVSync); - m_presentations.insert({frame_token, dummyFeedback}); + g_bindings.lock(); + if (m_binding && m_binding->observer) + return m_binding->observer; // delay unlock + g_bindings.unlock(); + return nullptr; } -bool Compositor::OnBeginFrameDerivedImpl(const viz::BeginFrameArgs &args) +void Compositor::waitForTexture() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); +} - ProgressFlingIfNeeded(m_host, args.frame_time); - m_beginFrameSource->OnUpdateVSyncParameters(args.frame_time, args.interval); - if (m_frameSinkClient) { - m_frameSinkClient->OnBeginFrame(args, m_presentations); - m_presentations.clear(); - } +void Compositor::releaseTexture() +{ +} - return true; +QSGTexture *Compositor::texture(QQuickWindow *, uint32_t textureOptions) +{ + Q_UNREACHABLE(); + return nullptr; } -void Compositor::OnBeginFrameSourcePausedChanged(bool) +bool Compositor::textureIsFlipped() { - // 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. + Q_UNREACHABLE(); + return false; } +void Compositor::releaseResources() { } + +// static +void Compositor::unlockBindings() +{ + g_bindings.unlock(); +} } // namespace QtWebEngineCore |