diff options
Diffstat (limited to 'src/core/compositor')
42 files changed, 2352 insertions, 4213 deletions
diff --git a/src/core/compositor/chromium_gpu_helper.cpp b/src/core/compositor/chromium_gpu_helper.cpp deleted file mode 100644 index 71d0f3687..000000000 --- a/src/core/compositor/chromium_gpu_helper.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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) 2012 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.Chromium file. - -#include "chromium_gpu_helper.h" - -// Some headers include the namespace ws, and can not coexist with -// Qt headers that include QTextStream, which includes most QSG headers -// via QMatrix4x4. -#include "content/browser/renderer_host/render_widget_host_impl.h" - -// Including gpu/command_buffer headers before content/gpu headers makes sure that -// guards are defined to prevent duplicate definition errors with forward declared -// GL typedefs cascading through content header includes. -#include "gpu/command_buffer/service/mailbox_manager.h" -#include "gpu/command_buffer/service/texture_base.h" - -#include "content/gpu/gpu_child_thread.h" -#include "gpu/ipc/service/gpu_channel_manager.h" - -#ifdef Q_OS_QNX -#include "content/common/gpu/stream_texture_qnx.h" -#endif - -scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner() -{ - return content::GpuChildThread::instance()->main_thread_runner(); -} - -gpu::MailboxManager *mailbox_manager() -{ - gpu::GpuChannelManager *gpuChannelManager = content::GpuChildThread::instance()->gpu_channel_manager(); - return gpuChannelManager->mailbox_manager(); -} - -gpu::TextureBase* ConsumeTexture(gpu::MailboxManager *mailboxManager, unsigned target, const gpu::Mailbox& mailbox) -{ - Q_UNUSED(target); - return mailboxManager->ConsumeTexture(mailbox); -} - -unsigned int service_id(gpu::TextureBase *tex) -{ - return tex->service_id(); -} - -void ProgressFlingIfNeeded(content::RenderWidgetHost *host, const base::TimeTicks ¤t_time) -{ - content::RenderWidgetHostImpl::From(host)->ProgressFlingIfNeeded(current_time); -} - -#ifdef Q_OS_QNX -EGLStreamData eglstream_connect_consumer(gpu::Texture *tex) -{ - EGLStreamData egl_stream; - content::StreamTexture* image = static_cast<content::StreamTexture *>(tex->GetLevelImage(GL_TEXTURE_EXTERNAL_OES, 0)); - if (image) { - image->ConnectConsumerIfNeeded(&egl_stream.egl_display, &egl_stream.egl_str_handle); - } - return egl_stream; -} -#endif diff --git a/src/core/compositor/chromium_gpu_helper.h b/src/core/compositor/chromium_gpu_helper.h deleted file mode 100644 index 4086d12ab..000000000 --- a/src/core/compositor/chromium_gpu_helper.h +++ /dev/null @@ -1,89 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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 CHROMIUM_GPU_HELPER_H -#define CHROMIUM_GPU_HELPER_H - -#include <QtGlobal> // We need this for the Q_OS_QNX define. - -#include "base/memory/scoped_refptr.h" - -namespace base { -class SingleThreadTaskRunner; -class TimeTicks; -} - -namespace content { -class RenderWidgetHost; -} - -namespace gpu { -struct Mailbox; -class MailboxManager; -class TextureBase; -} - -// These functions wrap code that needs to include headers that are -// incompatible with Qt GL headers. -// From the outside, types from incompatible headers referenced in these -// functions should only be forward-declared and considered as opaque types. - -scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner(); -gpu::MailboxManager *mailbox_manager(); - -gpu::TextureBase* ConsumeTexture(gpu::MailboxManager *mailboxManager, unsigned target, const gpu::Mailbox& mailbox); -unsigned int service_id(gpu::TextureBase *tex); - -void ProgressFlingIfNeeded(content::RenderWidgetHost *host, const base::TimeTicks ¤t_time); - -#ifdef Q_OS_QNX -typedef void* EGLDisplay; -typedef void* EGLStreamKHR; - -struct EGLStreamData { - EGLDisplay egl_display; - EGLStreamKHR egl_str_handle; - - EGLStreamData(): egl_display(NULL), egl_str_handle(NULL) {} -}; - -EGLStreamData eglstream_connect_consumer(gpu::Texture *tex); -#endif - -#endif // CHROMIUM_GPU_HELPER_H 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 diff --git a/src/core/compositor/compositor.h b/src/core/compositor/compositor.h index 6d88dc054..501559060 100644 --- a/src/core/compositor/compositor.h +++ b/src/core/compositor/compositor.h @@ -1,129 +1,153 @@ -/**************************************************************************** -** -** 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 #ifndef COMPOSITOR_H #define COMPOSITOR_H -#include "base/memory/weak_ptr.h" -#include "components/viz/common/frame_sinks/begin_frame_source.h" -#include "components/viz/common/quads/compositor_frame.h" -#include "ui/gfx/presentation_feedback.h" - -#include <QtCore/qglobal.h> -#include <QtCore/qshareddata.h> - -#include <QtCore/qglobal.h> -#include <QtCore/qshareddata.h> +#include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h> QT_BEGIN_NAMESPACE -class QSGNode; +class QQuickWindow; +class QSize; +class QSGTexture; QT_END_NAMESPACE -namespace content { -class RenderWidgetHost; -} namespace viz { -struct ReturnedResource; -namespace mojom { -class CompositorFrameSinkClient; -} // namespace mojom +class FrameSinkId; } // namespace viz namespace QtWebEngineCore { -class CompositorResourceTracker; -class RenderWidgetHostViewQtDelegate; - -// 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. +// Produces composited frames for display. // -// Step 2. Once the new frame is ready to be rendered, Compositor will notify -// the client by running the callback given to submitFrame(). -// -// Step 3. Once the client 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 +// Used by quick/widgets libraries for accessing the frames and +// controlling frame swapping. +class Q_WEBENGINECORE_EXPORT Compositor { + struct Binding; + public: - explicit Compositor(content::RenderWidgetHost *host); - ~Compositor() override; + // Identifies the implementation type. + enum class Type { + Software, + OpenGL, // TODO: Legacy, remove it with DisplaySkiaOutputDevice! + Native + }; + + // Identifies a compositor. + // + // The purpose of assigning ids to compositors is to allow the + // corresponding observer to be registered before the compositor + // itself is created, which is necessary since the creation + // happens on a different thread in the depths of viz. + // + // (Maps to viz::FrameSinkId internally). + struct Id + { + quint32 client_id; + quint32 sink_id; + + Id(viz::FrameSinkId); + }; + + // Pointer to Compositor or Observer that holds a lock to prevent + // either from being unbound and destroyed. + template<typename T> + class Handle + { + public: + Handle(std::nullptr_t) : m_data(nullptr) { } + Handle(T *data) : m_data(data) { } + Handle(Handle &&that) : m_data(that.m_data) { that.m_data = nullptr; } + ~Handle() + { + if (m_data) + Compositor::unlockBindings(); + } + T *operator->() const { return m_data; } + T &operator*() const { return *m_data; } + explicit operator bool() const { return m_data; } + + private: + T *m_data; + }; + + // Observes the compositor corresponding to the given id. + // + // Only one observer can exist per compositor. + class Q_WEBENGINECORE_EXPORT Observer + { + public: + // Binding to compositor + void bind(Id id); + void unbind(); + + // Compositor if bound + Handle<Compositor> compositor(); + + // There's a new frame ready, time to swapFrame(). + virtual void readyToSwap() = 0; + + protected: + Observer() = default; + ~Observer() { if (m_binding) unbind(); } + + private: + Binding *m_binding = nullptr; + }; + + // Type determines which methods can be called. + Type type() const { return m_type; } + + // Binding to observer. + void bind(Id id); + void unbind(); + + // Observer if bound. + Handle<Observer> observer(); + + // Update to next frame if possible. + virtual void swapFrame() = 0; + + // Ratio of pixels to DIPs. + // + // Don't use the devicePixelRatio of QImage, it's always 1. + virtual float devicePixelRatio() = 0; + + // Size of frame in pixels. + virtual QSize size() = 0; + + // Whether frame needs an alpha channel. + virtual bool requiresAlphaChannel() = 0; + + // Wait on texture to be ready aka. sync. + virtual void waitForTexture(); + + // Release any held texture resources + virtual void releaseTexture(); + + // QSGTexture of the frame. + virtual QSGTexture *texture(QQuickWindow *win, uint32_t textureOptions); + + // Is the texture produced upside down? + virtual bool textureIsFlipped(); + + // Release resources created in texture() + virtual void releaseResources(); + +protected: + Compositor(Type type) : m_type(type) { } + virtual ~Compositor() { if (m_binding) unbind(); } - void setFrameSinkClient(viz::mojom::CompositorFrameSinkClient *frameSinkClient); - void setNeedsBeginFrames(bool needsBeginFrames); +private: + template<typename T> + friend class Handle; - void submitFrame(viz::CompositorFrame frame, base::OnceClosure callback); - QSGNode *updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *viewDelegate); + class BindingMap; + static void unlockBindings(); -private: - void runSubmitCallback(); - void notifyFrameCommitted(); - void sendPresentationFeedback(uint frame_token); - - // viz::BeginFrameObserverBase - bool OnBeginFrameDerivedImpl(const viz::BeginFrameArgs &args) override; - void OnBeginFrameSourcePausedChanged(bool paused) override; - - viz::CompositorFrame m_committedFrame; - viz::CompositorFrame m_pendingFrame; - base::OnceClosure m_submitCallback; - std::unique_ptr<CompositorResourceTracker> m_resourceTracker; - content::RenderWidgetHost *m_host; - std::unique_ptr<viz::SyntheticBeginFrameSource> m_beginFrameSource; - base::flat_map<uint32_t, gfx::PresentationFeedback> m_presentations; - viz::mojom::CompositorFrameSinkClient *m_frameSinkClient = nullptr; - bool m_updatePaintNodeShouldCommit = false; - bool m_needsBeginFrames = false; - - scoped_refptr<base::SingleThreadTaskRunner> m_taskRunner; - base::WeakPtrFactory<Compositor> m_weakPtrFactory{this}; - - DISALLOW_COPY_AND_ASSIGN(Compositor); + const Type m_type; + Binding *m_binding = nullptr; }; } // namespace QtWebEngineCore diff --git a/src/core/compositor/compositor_resource.h b/src/core/compositor/compositor_resource.h deleted file mode 100644 index f7df2ab59..000000000 --- a/src/core/compositor/compositor_resource.h +++ /dev/null @@ -1,123 +0,0 @@ -/**************************************************************************** -** -** 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_RESOURCE_H -#define COMPOSITOR_RESOURCE_H - -#include <base/memory/ref_counted.h> -#include <components/viz/common/resources/transferable_resource.h> - -#include <QtCore/qglobal.h> -#include <QtGui/qtgui-config.h> - -#if QT_CONFIG(opengl) -# include "compositor_resource_fence.h" -#endif - -namespace viz { -class SharedBitmap; -} // namespace viz - -namespace QtWebEngineCore { - -using CompositorResourceId = quint32; - -// A resource (OpenGL texture or software shared bitmap). -// -// - Created by the CompositorResourceTracker from a newly submitted -// CompositorFrame's resource_list. -// -// - Until the frame is committed, its resources are in a 'pending' state and -// are inaccessible from outside the CompositorResourceTracker. -// -// - Once the frame is committed, its resources can be found via -// CompositorResourceTracker::findResource. -// -// - A committed resource's fields may not be updated and are safe to use from -// other threads without synchronization (unless noted otherwise). -class CompositorResource : public viz::TransferableResource -{ -public: - CompositorResource(const viz::TransferableResource &tr) : viz::TransferableResource(tr) {} - - // Counts the number of times this resource has been encountered in - // CompositorFrames' resource lists. - // - // Corresponds to viz::ReturnedResource::count. - // - // Updated by CompositorResourceTracker on UI thread. - int import_count = 1; - - // Identifies the last frame that needed this resource. Used by - // CompositorResourceTracker to return unused resources back to child - // compositors. - // - // Updated by CompositorResourceTracker on UI thread. - quint32 last_used_for_frame = 0; - - // Bitmap (if is_software). - std::unique_ptr<viz::SharedBitmap> bitmap; - -#if QT_CONFIG(opengl) - // OpenGL texture id (if !is_software). - quint32 texture_id = 0; - - // Should be waited on before using the texture (non-null if !is_software). - scoped_refptr<CompositorResourceFence> texture_fence; -#endif // QT_CONFIG(opengl) -}; - -inline bool operator<(const CompositorResource &r1, const CompositorResource &r2) -{ - return r1.id < r2.id; -} - -inline bool operator<(const CompositorResource &r, CompositorResourceId id) -{ - return r.id < id; -} - -inline bool operator<(CompositorResourceId id, const CompositorResource &r) -{ - return id < r.id; -} - -} // namespace QtWebEngineCore - -#endif // !COMPOSITOR_RESOURCE_H diff --git a/src/core/compositor/compositor_resource_fence.cpp b/src/core/compositor/compositor_resource_fence.cpp index 4179395d6..bd1c95cd9 100644 --- a/src/core/compositor/compositor_resource_fence.cpp +++ b/src/core/compositor/compositor_resource_fence.cpp @@ -1,44 +1,8 @@ -/**************************************************************************** -** -** 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) 2018 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_resource_fence.h" - +#include "ozone/gl_surface_qt.h" #include "ui/gl/gl_context.h" #include <QtGui/qopenglcontext.h> @@ -47,6 +11,12 @@ #define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull #endif + +#if QT_CONFIG(egl) +#include <EGL/egl.h> +#include <EGL/eglext.h> +#endif + namespace QtWebEngineCore { void CompositorResourceFence::wait() @@ -55,7 +25,8 @@ void CompositorResourceFence::wait() return; QOpenGLContext *context = QOpenGLContext::currentContext(); - Q_ASSERT(context); + if (!context) + return; // Chromium uses its own GL bindings and stores in in thread local storage. // For that reason, let chromium_gpu_helper.cpp contain the producing code that will run in the Chromium diff --git a/src/core/compositor/compositor_resource_fence.h b/src/core/compositor/compositor_resource_fence.h index 196297f78..ab92ca5c7 100644 --- a/src/core/compositor/compositor_resource_fence.h +++ b/src/core/compositor/compositor_resource_fence.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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) 2018 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 #ifndef COMPOSITOR_RESOURCE_FENCE_H #define COMPOSITOR_RESOURCE_FENCE_H @@ -52,7 +16,7 @@ public: REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE(); CompositorResourceFence() {} - CompositorResourceFence(const gl::TransferableFence &sync) : m_sync(sync) {}; + CompositorResourceFence(const gl::TransferableFence &sync) : m_sync(sync) {} ~CompositorResourceFence() { release(); } // May be used only by Qt Quick render thread. diff --git a/src/core/compositor/compositor_resource_tracker.cpp b/src/core/compositor/compositor_resource_tracker.cpp deleted file mode 100644 index 741c2717c..000000000 --- a/src/core/compositor/compositor_resource_tracker.cpp +++ /dev/null @@ -1,266 +0,0 @@ -/**************************************************************************** -** -** 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_resource_tracker.h" - -#include "chromium_gpu_helper.h" -#include "render_widget_host_view_qt_delegate.h" -#include "web_engine_context.h" - -#include "base/message_loop/message_loop.h" -#include "base/task/post_task.h" -#include "components/viz/common/quads/compositor_frame.h" -#include "components/viz/common/resources/returned_resource.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" -#include "content/browser/browser_main_loop.h" -#include "content/public/browser/browser_task_traits.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/gpu/content_gpu_client.h" -#include "gpu/command_buffer/service/mailbox_manager.h" -#include "gpu/command_buffer/service/sync_point_manager.h" - -namespace QtWebEngineCore { - -CompositorResourceTracker::CompositorResourceTracker() -{} - -CompositorResourceTracker::~CompositorResourceTracker() -{} - -void CompositorResourceTracker::submitResources(const viz::CompositorFrame &frame, base::OnceClosure callback) -{ - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - DCHECK(!m_submitCallback); - DCHECK(m_pendingResources.empty()); - DCHECK(m_pendingImports.empty()); - DCHECK(m_pendingResourceUpdates == 0); - - m_submitCallback = std::move(callback); - - m_pendingResources.reserve(frame.resource_list.size()); - m_pendingImports.reserve(frame.resource_list.size()); - - for (const viz::TransferableResource &transferableResource : frame.resource_list) { - auto it = m_committedResources.find(transferableResource.id); - if (it != m_committedResources.end()) - m_pendingImports.push_back(&*it); - else - m_pendingResources.emplace_back(transferableResource); - } - - if (m_pendingResources.empty()) { - scheduleRunSubmitCallback(); - return; - } - - m_pendingResourceUpdates = m_pendingResources.size(); - - std::vector<CompositorResource *> batch; - batch.reserve(m_pendingResources.size()); - - for (CompositorResource &resource : m_pendingResources) { - if (resource.is_software) - updateBitmap(&resource); - else if (!scheduleUpdateMailbox(&resource)) - batch.push_back(&resource); - } - - if (!batch.empty()) - scheduleUpdateMailboxes(std::move(batch)); -} - -void CompositorResourceTracker::commitResources() -{ - // 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. - - DCHECK(m_pendingResourceUpdates == 0); - - for (CompositorResource *resource : m_pendingImports) - resource->import_count++; - m_pendingImports.clear(); - - m_committedResources.insert(std::make_move_iterator(m_pendingResources.begin()), - std::make_move_iterator(m_pendingResources.end())); - m_pendingResources.clear(); - - ++m_committedFrameId; -} - -std::vector<viz::ReturnedResource> CompositorResourceTracker::returnResources() -{ - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - - std::vector<viz::ReturnedResource> returnedResources; - base::EraseIf(m_committedResources, [&](const CompositorResource &resource) { - if (resource.last_used_for_frame != m_committedFrameId) { - viz::ReturnedResource returnedResource; - returnedResource.id = resource.id; - returnedResource.count = resource.import_count; - returnedResources.push_back(std::move(returnedResource)); - return true; - } - return false; - }); - return returnedResources; -} - -const CompositorResource *CompositorResourceTracker::findResource(CompositorResourceId id) const -{ - auto it = m_committedResources.find(id); - DCHECK(it != m_committedResources.end()); - - const_cast<CompositorResource &>(*it).last_used_for_frame = m_committedFrameId; - - return &*it; -} - -void CompositorResourceTracker::updateBitmap(CompositorResource *resource) -{ - content::BrowserMainLoop *browserMainLoop = content::BrowserMainLoop::GetInstance(); - viz::ServerSharedBitmapManager *bitmapManager = browserMainLoop->GetServerSharedBitmapManager(); - - resource->bitmap = bitmapManager->GetSharedBitmapFromId( - resource->size, - viz::BGRA_8888, - resource->mailbox_holder.mailbox); - - if (--m_pendingResourceUpdates == 0) - scheduleRunSubmitCallback(); -} - -quint32 CompositorResourceTracker::consumeMailbox(const gpu::MailboxHolder &mailboxHolder) -{ -#if QT_CONFIG(opengl) - gpu::MailboxManager *mailboxManager = mailbox_manager(); - DCHECK(mailboxManager); - if (mailboxHolder.sync_token.HasData()) - mailboxManager->PullTextureUpdates(mailboxHolder.sync_token); - gpu::TextureBase *tex = mailboxManager->ConsumeTexture(mailboxHolder.mailbox); - return tex ? service_id(tex) : 0; -#else - NOTREACHED(); -#endif // QT_CONFIG(OPENGL) -} - -bool CompositorResourceTracker::scheduleUpdateMailbox(CompositorResource *resource) -{ -#if QT_CONFIG(opengl) - gpu::SyncPointManager *syncPointManager = WebEngineContext::syncPointManager(); - DCHECK(syncPointManager); - return syncPointManager->WaitOutOfOrder( - resource->mailbox_holder.sync_token, - base::BindOnce(&CompositorResourceTracker::updateMailbox, - m_weakPtrFactory.GetWeakPtr(), - resource)); -#else - NOTREACHED(); -#endif // QT_CONFIG(OPENGL) -} - -void CompositorResourceTracker::updateMailbox(CompositorResource *resource) -{ -#if QT_CONFIG(opengl) - resource->texture_id = consumeMailbox(resource->mailbox_holder); - resource->texture_fence = CompositorResourceFence::create(); - - if (--m_pendingResourceUpdates == 0) - scheduleRunSubmitCallback(); -#else - NOTREACHED(); -#endif // QT_CONFIG(OPENGL) -} - -void CompositorResourceTracker::scheduleUpdateMailboxes(std::vector<CompositorResource *> resources) -{ -#if QT_CONFIG(opengl) - scoped_refptr<base::SingleThreadTaskRunner> gpuTaskRunner = gpu_task_runner(); - DCHECK(gpuTaskRunner); - thread_local bool currentThreadIsGpu = gpuTaskRunner->BelongsToCurrentThread(); - if (currentThreadIsGpu) - return updateMailboxes(std::move(resources)); - gpuTaskRunner->PostTask( - FROM_HERE, - base::BindOnce(&CompositorResourceTracker::updateMailboxes, - m_weakPtrFactory.GetWeakPtr(), - std::move(resources))); -#else - NOTREACHED(); -#endif // QT_CONFIG(OPENGL) -} - -void CompositorResourceTracker::updateMailboxes(std::vector<CompositorResource *> resources) -{ -#if QT_CONFIG(opengl) - for (CompositorResource *resource : resources) - resource->texture_id = consumeMailbox(resource->mailbox_holder); - - scoped_refptr<CompositorResourceFence> fence = CompositorResourceFence::create(); - - for (CompositorResource *resource : resources) - resource->texture_fence = fence; - - if ((m_pendingResourceUpdates -= resources.size()) == 0) - scheduleRunSubmitCallback(); -#else - NOTREACHED(); -#endif // QT_CONFIG(OPENGL) -} - -void CompositorResourceTracker::scheduleRunSubmitCallback() -{ - thread_local bool currentThreadIsUi = content::BrowserThread::CurrentlyOn(content::BrowserThread::UI); - if (currentThreadIsUi) - return runSubmitCallback(); - base::PostTaskWithTraits( - FROM_HERE, { content::BrowserThread::UI, base::TaskPriority::USER_VISIBLE }, - base::BindOnce(&CompositorResourceTracker::runSubmitCallback, - m_weakPtrFactory.GetWeakPtr())); -} - -void CompositorResourceTracker::runSubmitCallback() -{ - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - - std::move(m_submitCallback).Run(); -} - -} // namespace QtWebEngineCore diff --git a/src/core/compositor/compositor_resource_tracker.h b/src/core/compositor/compositor_resource_tracker.h deleted file mode 100644 index 080891e5f..000000000 --- a/src/core/compositor/compositor_resource_tracker.h +++ /dev/null @@ -1,127 +0,0 @@ -/**************************************************************************** -** -** 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_RESOURCE_TRACKER_H -#define COMPOSITOR_RESOURCE_TRACKER_H - -#include "base/bind.h" -#include "base/callback.h" -#include "base/containers/flat_set.h" - -#include "compositor_resource.h" -#include "locked_ptr.h" - -#include <atomic> -#include <vector> - -namespace viz { -class CompositorFrame; -struct ReturnedResource; -} // namespace viz - -namespace gpu { -struct MailboxHolder; -} // namespace gpu - -namespace QtWebEngineCore { - -// Ensures resources are not used before they are ready. -// -// The life cycle of a frame's resources: -// -// Step 1. A new CompositorFrame is received and given to submitResources(). -// The frame's resources will extracted and initialized to a pending state. -// -// Step 2. Once the new resources are ready to be committed, -// CompositorResourceTracker will notify the client by running the callback -// given to submitResources(). -// -// Step 3. Once the client is ready to render, commitResources() should be -// called. This will commit all the pending resources, making them available -// via findResource(). -// -// Step 4. Once all the resources have been used (via findResource()), -// returnResources() may be called to return a list of all the resources which -// were *not* used since the last commitResources(). Go to step 1. -class CompositorResourceTracker final -{ -public: - CompositorResourceTracker(); - ~CompositorResourceTracker(); - - void submitResources(const viz::CompositorFrame &frame, base::OnceClosure callback); - void commitResources(); - std::vector<viz::ReturnedResource> returnResources(); - - // The returned pointer is invalidated by the next call to commitFrame() or - // returnResources(). It should therefore not be stored in data structures - // but used immediately. - // - // Do not ask for resources which do not exist. - const CompositorResource *findResource(CompositorResourceId id) const; - -private: - void updateBitmap(CompositorResource *resource); - - quint32 consumeMailbox(const gpu::MailboxHolder &mailboxHolder); - - bool scheduleUpdateMailbox(CompositorResource *resource); - void updateMailbox(CompositorResource *resource); - - void scheduleUpdateMailboxes(std::vector<CompositorResource *> resources); - void updateMailboxes(std::vector<CompositorResource *> resources); - - void scheduleRunSubmitCallback(); - void runSubmitCallback(); - - base::flat_set<CompositorResource> m_committedResources; - std::vector<CompositorResource> m_pendingResources; - std::vector<CompositorResource *> m_pendingImports; - base::OnceClosure m_submitCallback; - std::atomic<size_t> m_pendingResourceUpdates{0}; - quint32 m_committedFrameId = 0; - - base::LockedPtrFactory<CompositorResourceTracker> m_weakPtrFactory{this}; - - DISALLOW_COPY_AND_ASSIGN(CompositorResourceTracker); -}; - -} // namespace QtWebEngineCore - -#endif // !COMPOSITOR_RESOURCE_TRACKER_H diff --git a/src/core/compositor/content_gpu_client_qt.cpp b/src/core/compositor/content_gpu_client_qt.cpp index f934979a0..6ef8048f2 100644 --- a/src/core/compositor/content_gpu_client_qt.cpp +++ b/src/core/compositor/content_gpu_client_qt.cpp @@ -1,45 +1,8 @@ -/**************************************************************************** -** -** 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) 2018 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 "content_gpu_client_qt.h" - -#include "web_engine_context.h" +#include "ozone/gl_share_context_qt.h" namespace QtWebEngineCore { @@ -51,9 +14,11 @@ ContentGpuClientQt::~ContentGpuClientQt() { } -gpu::SyncPointManager *ContentGpuClientQt::GetSyncPointManager() +gl::GLShareGroup *ContentGpuClientQt::GetInProcessGpuShareGroup() { - return WebEngineContext::syncPointManager(); + if (!m_shareGroupQt.get()) + m_shareGroupQt = new ShareGroupQt; + return m_shareGroupQt.get(); } } // namespace diff --git a/src/core/compositor/content_gpu_client_qt.h b/src/core/compositor/content_gpu_client_qt.h index d7ad43881..33314e0bb 100644 --- a/src/core/compositor/content_gpu_client_qt.h +++ b/src/core/compositor/content_gpu_client_qt.h @@ -1,47 +1,16 @@ -/**************************************************************************** -** -** 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) 2018 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 #ifndef CONTENT_GPU_CLIENT_QT_H #define CONTENT_GPU_CLIENT_QT_H #include "content/public/gpu/content_gpu_client.h" +namespace gl { +class GLShareGroup; +} + namespace QtWebEngineCore { +class ShareGroupQt; class ContentGpuClientQt : public content::ContentGpuClient { public: @@ -49,7 +18,10 @@ public: ~ContentGpuClientQt() override; // content::ContentGpuClient implementation. - gpu::SyncPointManager *GetSyncPointManager() override; + gl::GLShareGroup *GetInProcessGpuShareGroup() override; + +private: + scoped_refptr<ShareGroupQt> m_shareGroupQt; }; } diff --git a/src/core/compositor/delegated_frame_node.cpp b/src/core/compositor/delegated_frame_node.cpp deleted file mode 100644 index 19e8d1b82..000000000 --- a/src/core/compositor/delegated_frame_node.cpp +++ /dev/null @@ -1,1123 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ - -// On Mac we need to reset this define in order to prevent definition -// of "check" macros etc. The "check" macro collides with a member function name in QtQuick. -// See AssertMacros.h in the Mac SDK. -#include <QtGlobal> // We need this for the Q_OS_MAC define. -#if defined(Q_OS_MAC) -#undef __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES -#define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0 -#endif - -#include "delegated_frame_node.h" - -#include "chromium_gpu_helper.h" -#include "stream_video_node.h" -#include "type_conversion.h" -#include "yuv_video_node.h" -#include "compositor_resource_tracker.h" - -#include "base/bind.h" -#include "cc/base/math_util.h" -#include "components/viz/common/quads/compositor_frame.h" -#include "components/viz/common/quads/debug_border_draw_quad.h" -#include "components/viz/common/quads/draw_quad.h" -#include "components/viz/common/quads/render_pass_draw_quad.h" -#include "components/viz/common/quads/solid_color_draw_quad.h" -#include "components/viz/common/quads/stream_video_draw_quad.h" -#include "components/viz/common/quads/texture_draw_quad.h" -#include "components/viz/common/quads/tile_draw_quad.h" -#include "components/viz/common/quads/yuv_video_draw_quad.h" -#include "components/viz/service/display/bsp_tree.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" - -#ifndef QT_NO_OPENGL -# include <QOpenGLContext> -# include <QOpenGLFunctions> -# include <QSGFlatColorMaterial> -#endif -#include <QSGTexture> -#include <private/qsgadaptationlayer_p.h> - -#include <QSGImageNode> -#include <QSGRectangleNode> - -#if !defined(QT_NO_EGL) -#include <EGL/egl.h> -#include <EGL/eglext.h> -#endif - -#ifndef GL_TEXTURE_RECTANGLE -#define GL_TEXTURE_RECTANGLE 0x84F5 -#endif - -#ifndef GL_NEAREST -#define GL_NEAREST 0x2600 -#endif - -#ifndef GL_LINEAR -#define GL_LINEAR 0x2601 -#endif - -#ifndef GL_RGBA -#define GL_RGBA 0x1908 -#endif - -#ifndef GL_RGB -#define GL_RGB 0x1907 -#endif - -#ifndef GL_LINE_LOOP -#define GL_LINE_LOOP 0x0002 -#endif - -#ifndef QT_NO_OPENGL -QT_BEGIN_NAMESPACE -Q_GUI_EXPORT QOpenGLContext *qt_gl_global_share_context(); -QT_END_NAMESPACE -#endif - -namespace QtWebEngineCore { -#ifndef QT_NO_OPENGL -class MailboxTexture : public QSGTexture, protected QOpenGLFunctions { -public: - MailboxTexture(const CompositorResource *resource, bool hasAlphaChannel, int target = -1); - ~MailboxTexture(); - // QSGTexture: - int textureId() const override { return m_textureId; } - QSize textureSize() const override { return m_textureSize; } - bool hasAlphaChannel() const override { return m_hasAlpha; } - bool hasMipmaps() const override { return false; } - void bind() override; - -private: - int m_textureId; - scoped_refptr<CompositorResourceFence> m_fence; - QSize m_textureSize; - bool m_hasAlpha; - GLenum m_target; -#if defined(USE_OZONE) - bool m_ownsTexture; -#endif -#ifdef Q_OS_QNX - EGLStreamData m_eglStreamData; -#endif - friend class DelegatedFrameNode; -}; -#endif // QT_NO_OPENGL - -class RectClipNode : public QSGClipNode -{ -public: - RectClipNode(const QRectF &); -private: - QSGGeometry m_geometry; -}; - -class DelegatedNodeTreeHandler -{ -public: - DelegatedNodeTreeHandler(QVector<QSGNode*> *sceneGraphNodes) - : m_sceneGraphNodes(sceneGraphNodes) - { - } - - virtual ~DelegatedNodeTreeHandler(){} - - virtual void setupRenderPassNode(QSGTexture *, const QRect &, const QRectF &, QSGNode *) = 0; - virtual void setupTextureContentNode(QSGTexture *, const QRect &, const QRectF &, - QSGImageNode::TextureCoordinatesTransformMode, - QSGNode *) = 0; - virtual void setupSolidColorNode(const QRect &, const QColor &, QSGNode *) = 0; - -#ifndef QT_NO_OPENGL - virtual void setupDebugBorderNode(QSGGeometry *, QSGFlatColorMaterial *, QSGNode *) = 0; - virtual void setupYUVVideoNode(QSGTexture *, QSGTexture *, QSGTexture *, QSGTexture *, - const QRectF &, const QRectF &, const QSizeF &, const QSizeF &, - gfx::ColorSpace, float, float, const QRectF &, - QSGNode *) = 0; -#ifdef GL_OES_EGL_image_external - virtual void setupStreamVideoNode(MailboxTexture *, const QRectF &, - const QMatrix4x4 &, QSGNode *) = 0; -#endif // GL_OES_EGL_image_external -#endif // QT_NO_OPENGL -protected: - QVector<QSGNode*> *m_sceneGraphNodes; -}; - -class DelegatedNodeTreeUpdater : public DelegatedNodeTreeHandler -{ -public: - DelegatedNodeTreeUpdater(QVector<QSGNode*> *sceneGraphNodes) - : DelegatedNodeTreeHandler(sceneGraphNodes) - , m_nodeIterator(sceneGraphNodes->begin()) - { - } - - void setupRenderPassNode(QSGTexture *layer, const QRect &rect, const QRectF &sourceRect, QSGNode *) override - { - Q_ASSERT(layer); - Q_ASSERT(m_nodeIterator != m_sceneGraphNodes->end()); - QSGImageNode *imageNode = static_cast<QSGImageNode*>(*m_nodeIterator++); - imageNode->setRect(rect); - imageNode->setSourceRect(sourceRect); - imageNode->setTexture(layer); - } - - void setupTextureContentNode(QSGTexture *texture, const QRect &rect, const QRectF &sourceRect, - QSGImageNode::TextureCoordinatesTransformMode texCoordTransForm, - QSGNode *) override - { - Q_ASSERT(m_nodeIterator != m_sceneGraphNodes->end()); - QSGImageNode *textureNode = static_cast<QSGImageNode*>(*m_nodeIterator++); - if (textureNode->texture() != texture) { - // Chromium sometimes uses textures that doesn't completely fit - // in which case the geometry needs to be recalculated even if - // rect and src-rect matches. - if (textureNode->texture()->textureSize() != texture->textureSize()) - textureNode->markDirty(QSGImageNode::DirtyGeometry); - textureNode->setTexture(texture); - } - if (textureNode->textureCoordinatesTransform() != texCoordTransForm) - textureNode->setTextureCoordinatesTransform(texCoordTransForm); - if (textureNode->rect() != rect) - textureNode->setRect(rect); - if (textureNode->sourceRect() != sourceRect) - textureNode->setSourceRect(sourceRect); - if (textureNode->filtering() != texture->filtering()) - textureNode->setFiltering(texture->filtering()); - } - void setupSolidColorNode(const QRect &rect, const QColor &color, QSGNode *) override - { - Q_ASSERT(m_nodeIterator != m_sceneGraphNodes->end()); - QSGRectangleNode *rectangleNode = static_cast<QSGRectangleNode*>(*m_nodeIterator++); - - if (rectangleNode->rect() != rect) - rectangleNode->setRect(rect); - if (rectangleNode->color() != color) - rectangleNode->setColor(color); - } -#ifndef QT_NO_OPENGL - void setupDebugBorderNode(QSGGeometry *geometry, QSGFlatColorMaterial *material, - QSGNode *) override - { - Q_ASSERT(m_nodeIterator != m_sceneGraphNodes->end()); - QSGGeometryNode *geometryNode = static_cast<QSGGeometryNode*>(*m_nodeIterator++); - - geometryNode->setGeometry(geometry); - geometryNode->setMaterial(material); - } - - void setupYUVVideoNode(QSGTexture *, QSGTexture *, QSGTexture *, QSGTexture *, - const QRectF &, const QRectF &, const QSizeF &, const QSizeF &, - gfx::ColorSpace, float, float, const QRectF &, - QSGNode *) override - { - Q_UNREACHABLE(); - } -#ifdef GL_OES_EGL_image_external - void setupStreamVideoNode(MailboxTexture *, const QRectF &, - const QMatrix4x4 &, QSGNode *) override - { - Q_UNREACHABLE(); - } -#endif // GL_OES_EGL_image_external -#endif // QT_NO_OPENGL - -private: - QVector<QSGNode*>::iterator m_nodeIterator; -}; - -class DelegatedNodeTreeCreator : public DelegatedNodeTreeHandler -{ -public: - DelegatedNodeTreeCreator(QVector<QSGNode*> *sceneGraphNodes, - RenderWidgetHostViewQtDelegate *apiDelegate) - : DelegatedNodeTreeHandler(sceneGraphNodes) - , m_apiDelegate(apiDelegate) - { - } - - void setupRenderPassNode(QSGTexture *layer, const QRect &rect, const QRectF &sourceRect, - QSGNode *layerChain) override - { - Q_ASSERT(layer); - QSGImageNode *imageNode = m_apiDelegate->createImageNode(); - imageNode->setRect(rect); - imageNode->setSourceRect(sourceRect); - imageNode->setTexture(layer); - - layerChain->appendChildNode(imageNode); - m_sceneGraphNodes->append(imageNode); - } - - void setupTextureContentNode(QSGTexture *texture, const QRect &rect, const QRectF &sourceRect, - QSGImageNode::TextureCoordinatesTransformMode texCoordTransForm, - QSGNode *layerChain) override - { - QSGImageNode *textureNode = m_apiDelegate->createImageNode(); - textureNode->setTextureCoordinatesTransform(texCoordTransForm); - textureNode->setRect(rect); - textureNode->setSourceRect(sourceRect); - textureNode->setTexture(texture); - textureNode->setFiltering(texture->filtering()); - - layerChain->appendChildNode(textureNode); - m_sceneGraphNodes->append(textureNode); - } - - void setupSolidColorNode(const QRect &rect, const QColor &color, - QSGNode *layerChain) override - { - QSGRectangleNode *rectangleNode = m_apiDelegate->createRectangleNode(); - rectangleNode->setRect(rect); - rectangleNode->setColor(color); - - layerChain->appendChildNode(rectangleNode); - m_sceneGraphNodes->append(rectangleNode); - } - -#ifndef QT_NO_OPENGL - void setupDebugBorderNode(QSGGeometry *geometry, QSGFlatColorMaterial *material, - QSGNode *layerChain) override - { - QSGGeometryNode *geometryNode = new QSGGeometryNode; - geometryNode->setFlags(QSGNode::OwnsGeometry | QSGNode::OwnsMaterial); - - geometryNode->setGeometry(geometry); - geometryNode->setMaterial(material); - - layerChain->appendChildNode(geometryNode); - m_sceneGraphNodes->append(geometryNode); - } - - void setupYUVVideoNode(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, - QSGTexture *aTexture, const QRectF &yaTexCoordRect, - const QRectF &uvTexCoordRect, const QSizeF &yaTexSize, - const QSizeF &uvTexSize, gfx::ColorSpace colorspace, - float rMul, float rOff, const QRectF &rect, - QSGNode *layerChain) override - { - YUVVideoNode *videoNode = new YUVVideoNode( - yTexture, - uTexture, - vTexture, - aTexture, - yaTexCoordRect, - uvTexCoordRect, - yaTexSize, - uvTexSize, - colorspace, - rMul, - rOff); - videoNode->setRect(rect); - - layerChain->appendChildNode(videoNode); - m_sceneGraphNodes->append(videoNode); - } -#ifdef GL_OES_EGL_image_external - void setupStreamVideoNode(MailboxTexture *texture, const QRectF &rect, - const QMatrix4x4 &textureMatrix, QSGNode *layerChain) override - { - StreamVideoNode *svideoNode = new StreamVideoNode(texture, false, ExternalTarget); - svideoNode->setRect(rect); - svideoNode->setTextureMatrix(textureMatrix); - layerChain->appendChildNode(svideoNode); - m_sceneGraphNodes->append(svideoNode); - } -#endif // GL_OES_EGL_image_external -#endif // QT_NO_OPENGL - -private: - RenderWidgetHostViewQtDelegate *m_apiDelegate; -}; - - -static inline QSharedPointer<QSGLayer> findRenderPassLayer(const int &id, const QVector<QPair<int, QSharedPointer<QSGLayer> > > &list) -{ - typedef QPair<int, QSharedPointer<QSGLayer> > Pair; - for (const Pair &pair : list) - if (pair.first == id) - return pair.second; - return QSharedPointer<QSGLayer>(); -} - -static QSGNode *buildRenderPassChain(QSGNode *chainParent) -{ - // Chromium already ordered the quads from back to front for us, however the - // Qt scene graph layers individual geometries in their own z-range and uses - // the depth buffer to visually stack nodes according to their item tree order. - - // This gets rid of the z component of all quads, once any x and y perspective - // transformation has been applied to vertices not on the z=0 plane. Qt will - // use an orthographic projection to render them. - QSGTransformNode *zCompressNode = new QSGTransformNode; - QMatrix4x4 zCompressMatrix; - zCompressMatrix.scale(1, 1, 0); - zCompressNode->setMatrix(zCompressMatrix); - chainParent->appendChildNode(zCompressNode); - return zCompressNode; -} - -static QSGNode *buildLayerChain(QSGNode *chainParent, const viz::SharedQuadState *layerState) -{ - QSGNode *layerChain = chainParent; - if (layerState->is_clipped) { - RectClipNode *clipNode = new RectClipNode(toQt(layerState->clip_rect)); - layerChain->appendChildNode(clipNode); - layerChain = clipNode; - } - if (!layerState->quad_to_target_transform.IsIdentity()) { - QSGTransformNode *transformNode = new QSGTransformNode; - QMatrix4x4 qMatrix; - convertToQt(layerState->quad_to_target_transform.matrix(), qMatrix); - transformNode->setMatrix(qMatrix); - layerChain->appendChildNode(transformNode); - layerChain = transformNode; - } - if (layerState->opacity < 1.0) { - QSGOpacityNode *opacityNode = new QSGOpacityNode; - opacityNode->setOpacity(layerState->opacity); - layerChain->appendChildNode(opacityNode); - layerChain = opacityNode; - } - return layerChain; -} - -#ifndef QT_NO_OPENGL -MailboxTexture::MailboxTexture(const CompositorResource *resource, bool hasAlphaChannel, int target) - : m_textureId(resource->texture_id) - , m_fence(resource->texture_fence) - , m_textureSize(toQt(resource->size)) - , m_hasAlpha(hasAlphaChannel) - , m_target(target >= 0 ? target : GL_TEXTURE_2D) -#if defined(USE_OZONE) - , m_ownsTexture(false) -#endif -{ - initializeOpenGLFunctions(); - - // Assume that resources without a size will be used with a full source rect. - // Setting a size of 1x1 will let any texture node compute a normalized source - // rect of (0, 0) to (1, 1) while an empty texture size would set (0, 0) on all corners. - if (m_textureSize.isEmpty()) - m_textureSize = QSize(1, 1); -} - -MailboxTexture::~MailboxTexture() -{ -#if defined(USE_OZONE) - // This is rare case, where context is not shared - // we created extra texture in current context, so - // delete it now - if (m_ownsTexture) { - QOpenGLContext *currentContext = QOpenGLContext::currentContext() ; - QOpenGLFunctions *funcs = currentContext->functions(); - GLuint id(m_textureId); - funcs->glDeleteTextures(1, &id); - } -#endif -} - -void MailboxTexture::bind() -{ - if (m_fence) - m_fence->wait(); - glBindTexture(m_target, m_textureId); -#ifdef Q_OS_QNX - if (m_target == GL_TEXTURE_EXTERNAL_OES) { - static bool resolved = false; - static PFNEGLSTREAMCONSUMERACQUIREKHRPROC eglStreamConsumerAcquire = 0; - - if (!resolved) { - QOpenGLContext *context = QOpenGLContext::currentContext(); - eglStreamConsumerAcquire = (PFNEGLSTREAMCONSUMERACQUIREKHRPROC)context->getProcAddress("eglStreamConsumerAcquireKHR"); - resolved = true; - } - if (eglStreamConsumerAcquire) - eglStreamConsumerAcquire(m_eglStreamData.egl_display, m_eglStreamData.egl_str_handle); - } -#endif -} -#endif // !QT_NO_OPENGL - -RectClipNode::RectClipNode(const QRectF &rect) - : m_geometry(QSGGeometry::defaultAttributes_Point2D(), 4) -{ - QSGGeometry::updateRectGeometry(&m_geometry, rect); - setGeometry(&m_geometry); - setClipRect(rect); - setIsRectangular(true); -} - -DelegatedFrameNode::DelegatedFrameNode() -#if defined(USE_OZONE) && !defined(QT_NO_OPENGL) - : m_contextShared(true) -#endif -{ - setFlag(UsePreprocess); -#if defined(USE_OZONE) && !defined(QT_NO_OPENGL) - QOpenGLContext *currentContext = QOpenGLContext::currentContext() ; - QOpenGLContext *sharedContext = qt_gl_global_share_context(); - if (currentContext && sharedContext && !QOpenGLContext::areSharing(currentContext, sharedContext)) { - static bool allowNotSharedContextWarningShown = true; - if (allowNotSharedContextWarningShown) { - allowNotSharedContextWarningShown = false; - qWarning("Context is not shared, textures will be copied between contexts."); - } - m_offsurface.reset(new QOffscreenSurface); - m_offsurface->create(); - m_contextShared = false; - } -#endif -} - -DelegatedFrameNode::~DelegatedFrameNode() -{ -} - -void DelegatedFrameNode::preprocess() -{ - // Then render any intermediate RenderPass in order. - typedef QPair<int, QSharedPointer<QSGLayer> > Pair; - for (const Pair &pair : qAsConst(m_sgObjects.renderPassLayers)) { - // The layer is non-live, request a one-time update here. - pair.second->scheduleUpdate(); - // Proceed with the actual update. - pair.second->updateTexture(); - } -} - -static bool areSharedQuadStatesEqual(const viz::SharedQuadState *layerState, - const viz::SharedQuadState *prevLayerState) -{ - if (layerState->sorting_context_id != 0 || prevLayerState->sorting_context_id != 0) - return false; - if (layerState->is_clipped != prevLayerState->is_clipped - || layerState->clip_rect != prevLayerState->clip_rect) - return false; - if (layerState->quad_to_target_transform != prevLayerState->quad_to_target_transform) - return false; - return qFuzzyCompare(layerState->opacity, prevLayerState->opacity); -} - -// Compares if the frame data that we got from the Chromium Compositor is -// *structurally* equivalent to the one of the previous frame. -// If it is, we will just reuse and update the old nodes where necessary. -static bool areRenderPassStructuresEqual(const viz::CompositorFrame *frameData, - const viz::CompositorFrame *previousFrameData) -{ - if (!previousFrameData) - return false; - - if (previousFrameData->render_pass_list.size() != frameData->render_pass_list.size()) - return false; - - for (unsigned i = 0; i < frameData->render_pass_list.size(); ++i) { - viz::RenderPass *newPass = frameData->render_pass_list.at(i).get(); - viz::RenderPass *prevPass = previousFrameData->render_pass_list.at(i).get(); - - if (newPass->id != prevPass->id) - return false; - - if (newPass->quad_list.size() != prevPass->quad_list.size()) - return false; - - viz::QuadList::ConstBackToFrontIterator it = newPass->quad_list.BackToFrontBegin(); - viz::QuadList::ConstBackToFrontIterator end = newPass->quad_list.BackToFrontEnd(); - viz::QuadList::ConstBackToFrontIterator prevIt = prevPass->quad_list.BackToFrontBegin(); - viz::QuadList::ConstBackToFrontIterator prevEnd = prevPass->quad_list.BackToFrontEnd(); - for (; it != end && prevIt != prevEnd; ++it, ++prevIt) { - const viz::DrawQuad *quad = *it; - const viz::DrawQuad *prevQuad = *prevIt; - if (quad->material != prevQuad->material) - return false; -#ifndef QT_NO_OPENGL - if (quad->material == viz::DrawQuad::YUV_VIDEO_CONTENT) - return false; -#ifdef GL_OES_EGL_image_external - if (quad->material == viz::DrawQuad::STREAM_VIDEO_CONTENT) - return false; -#endif // GL_OES_EGL_image_external -#endif // QT_NO_OPENGL - if (!areSharedQuadStatesEqual(quad->shared_quad_state, prevQuad->shared_quad_state)) - return false; - if (quad->shared_quad_state->is_clipped && quad->visible_rect != prevQuad->visible_rect) { - gfx::Rect targetRect1 = - cc::MathUtil::MapEnclosingClippedRect(quad->shared_quad_state->quad_to_target_transform, quad->visible_rect); - gfx::Rect targetRect2 = - cc::MathUtil::MapEnclosingClippedRect(quad->shared_quad_state->quad_to_target_transform, prevQuad->visible_rect); - targetRect1.Intersect(quad->shared_quad_state->clip_rect); - targetRect2.Intersect(quad->shared_quad_state->clip_rect); - if (targetRect1.IsEmpty() != targetRect2.IsEmpty()) - return false; - } - } - } - return true; -} - -void DelegatedFrameNode::commit(const viz::CompositorFrame &pendingFrame, - const viz::CompositorFrame &committedFrame, - const CompositorResourceTracker *resourceTracker, - RenderWidgetHostViewQtDelegate *apiDelegate) -{ - const viz::CompositorFrame* frameData = &pendingFrame; - if (frameData->render_pass_list.empty()) - return; - - // DelegatedFrameNode is a transform node only for the purpose of - // countering the scale of devicePixel-scaled tiles when rendering them - // to the final surface. - QMatrix4x4 matrix; - const float devicePixelRatio = frameData->metadata.device_scale_factor; - matrix.scale(1 / devicePixelRatio, 1 / devicePixelRatio); - if (QSGTransformNode::matrix() != matrix) - setMatrix(matrix); - - QScopedPointer<DelegatedNodeTreeHandler> nodeHandler; - - const QSizeF viewportSizeInPt = apiDelegate->viewGeometry().size(); - const QSizeF viewportSizeF = viewportSizeInPt * devicePixelRatio; - const QSize viewportSize(std::ceil(viewportSizeF.width()), std::ceil(viewportSizeF.height())); - - // We first compare if the render passes from the previous frame data are structurally - // equivalent to the render passes in the current frame data. If they are, we are going - // to reuse the old nodes. Otherwise, we will delete the old nodes and build a new tree. - // - // Additionally, because we clip (i.e. don't build scene graph nodes for) quads outside - // of the visible area, we also have to rebuild the tree whenever the window is resized. - const bool buildNewTree = - !areRenderPassStructuresEqual(frameData, &committedFrame) || - m_sceneGraphNodes.empty() || - viewportSize != m_previousViewportSize; - - if (buildNewTree) { - // Keep the old objects in scope to hold a ref on layers, resources and textures - // that we can re-use. Destroy the remaining objects before returning. - qSwap(m_sgObjects, m_previousSGObjects); - // Discard the scene graph nodes from the previous frame. - while (QSGNode *oldChain = firstChild()) - delete oldChain; - m_sceneGraphNodes.clear(); - nodeHandler.reset(new DelegatedNodeTreeCreator(&m_sceneGraphNodes, apiDelegate)); - } else { - qSwap(m_sgObjects.bitmapTextures, m_previousSGObjects.bitmapTextures); - qSwap(m_sgObjects.mailboxTextures, m_previousSGObjects.mailboxTextures); - nodeHandler.reset(new DelegatedNodeTreeUpdater(&m_sceneGraphNodes)); - } - // The RenderPasses list is actually a tree where a parent RenderPass is connected - // to its dependencies through a RenderPassId reference in one or more RenderPassQuads. - // The list is already ordered with intermediate RenderPasses placed before their - // parent, with the last one in the list being the root RenderPass, the one - // that we displayed to the user. - // All RenderPasses except the last one are rendered to an FBO. - viz::RenderPass *rootRenderPass = frameData->render_pass_list.back().get(); - - gfx::Rect viewportRect(toGfx(viewportSize)); - for (unsigned i = 0; i < frameData->render_pass_list.size(); ++i) { - viz::RenderPass *pass = frameData->render_pass_list.at(i).get(); - - QSGNode *renderPassParent = 0; - gfx::Rect scissorRect; - if (pass != rootRenderPass) { - QSharedPointer<QSGLayer> rpLayer; - if (buildNewTree) { - rpLayer = findRenderPassLayer(pass->id, m_previousSGObjects.renderPassLayers); - if (!rpLayer) { - rpLayer = QSharedPointer<QSGLayer>(apiDelegate->createLayer()); - // Avoid any premature texture update since we need to wait - // for the GPU thread to produce the dependent resources first. - rpLayer->setLive(false); - } - QSharedPointer<QSGRootNode> rootNode(new QSGRootNode); - rpLayer->setItem(rootNode.data()); - m_sgObjects.renderPassLayers.append(QPair<int, - QSharedPointer<QSGLayer> >(pass->id, rpLayer)); - m_sgObjects.renderPassRootNodes.append(rootNode); - renderPassParent = rootNode.data(); - } else - rpLayer = findRenderPassLayer(pass->id, m_sgObjects.renderPassLayers); - - rpLayer->setRect(toQt(pass->output_rect)); - rpLayer->setSize(toQt(pass->output_rect.size())); - rpLayer->setFormat(pass->has_transparent_background ? GL_RGBA : GL_RGB); - rpLayer->setHasMipmaps(pass->generate_mipmap); - rpLayer->setMirrorVertical(true); - scissorRect = pass->output_rect; - } else { - renderPassParent = this; - scissorRect = viewportRect; - scissorRect += rootRenderPass->output_rect.OffsetFromOrigin(); - } - - if (scissorRect.IsEmpty()) { - holdResources(pass, resourceTracker); - continue; - } - - QSGNode *renderPassChain = nullptr; - if (buildNewTree) - renderPassChain = buildRenderPassChain(renderPassParent); - - base::circular_deque<std::unique_ptr<viz::DrawPolygon>> polygonQueue; - int nextPolygonId = 0; - int currentSortingContextId = 0; - const viz::SharedQuadState *currentLayerState = nullptr; - QSGNode *currentLayerChain = nullptr; - const auto quadListBegin = pass->quad_list.BackToFrontBegin(); - const auto quadListEnd = pass->quad_list.BackToFrontEnd(); - for (auto it = quadListBegin; it != quadListEnd; ++it) { - const viz::DrawQuad *quad = *it; - const viz::SharedQuadState *quadState = quad->shared_quad_state; - - gfx::Rect targetRect = - cc::MathUtil::MapEnclosingClippedRect(quadState->quad_to_target_transform, - quad->visible_rect); - if (quadState->is_clipped) - targetRect.Intersect(quadState->clip_rect); - targetRect.Intersect(scissorRect); - if (targetRect.IsEmpty()) { - holdResources(quad, resourceTracker); - continue; - } - - if (quadState->sorting_context_id != currentSortingContextId) { - flushPolygons(&polygonQueue, renderPassChain, - nodeHandler.data(), resourceTracker, apiDelegate); - currentSortingContextId = quadState->sorting_context_id; - } - - if (currentSortingContextId != 0) { - std::unique_ptr<viz::DrawPolygon> polygon( - new viz::DrawPolygon( - quad, - gfx::RectF(quad->visible_rect), - quadState->quad_to_target_transform, - nextPolygonId++)); - if (polygon->points().size() > 2u) - polygonQueue.push_back(std::move(polygon)); - continue; - } - - if (renderPassChain && currentLayerState != quadState) { - currentLayerState = quadState; - currentLayerChain = buildLayerChain(renderPassChain, quadState); - } - - handleQuad(quad, currentLayerChain, - nodeHandler.data(), resourceTracker, apiDelegate); - } - flushPolygons(&polygonQueue, renderPassChain, - nodeHandler.data(), resourceTracker, apiDelegate); - } - - copyMailboxTextures(); - - m_previousViewportSize = viewportSize; - m_previousSGObjects = SGObjects(); -} - -void DelegatedFrameNode::flushPolygons( - base::circular_deque<std::unique_ptr<viz::DrawPolygon>> *polygonQueue, - QSGNode *renderPassChain, - DelegatedNodeTreeHandler *nodeHandler, - const CompositorResourceTracker *resourceTracker, - RenderWidgetHostViewQtDelegate *apiDelegate) -{ - if (polygonQueue->empty()) - return; - - const auto actionHandler = [&](viz::DrawPolygon *polygon) { - const viz::DrawQuad *quad = polygon->original_ref(); - const viz::SharedQuadState *quadState = quad->shared_quad_state; - - QSGNode *currentLayerChain = nullptr; - if (renderPassChain) - currentLayerChain = buildLayerChain(renderPassChain, quad->shared_quad_state); - - gfx::Transform inverseTransform; - bool invertible = quadState->quad_to_target_transform.GetInverse(&inverseTransform); - DCHECK(invertible); - polygon->TransformToLayerSpace(inverseTransform); - - handlePolygon(polygon, currentLayerChain, - nodeHandler, resourceTracker, apiDelegate); - }; - - viz::BspTree(polygonQueue).TraverseWithActionHandler(&actionHandler); -} - -void DelegatedFrameNode::handlePolygon( - const viz::DrawPolygon *polygon, - QSGNode *currentLayerChain, - DelegatedNodeTreeHandler *nodeHandler, - const CompositorResourceTracker *resourceTracker, - RenderWidgetHostViewQtDelegate *apiDelegate) -{ - const viz::DrawQuad *quad = polygon->original_ref(); - - if (!polygon->is_split()) { - handleQuad(quad, currentLayerChain, - nodeHandler, resourceTracker, apiDelegate); - } else { - std::vector<gfx::QuadF> clipRegionList; - polygon->ToQuads2D(&clipRegionList); - for (const auto & clipRegion : clipRegionList) - handleClippedQuad(quad, clipRegion, currentLayerChain, - nodeHandler, resourceTracker, apiDelegate); - } -} - -void DelegatedFrameNode::handleClippedQuad( - const viz::DrawQuad *quad, - const gfx::QuadF &clipRegion, - QSGNode *currentLayerChain, - DelegatedNodeTreeHandler *nodeHandler, - const CompositorResourceTracker *resourceTracker, - RenderWidgetHostViewQtDelegate *apiDelegate) -{ - if (currentLayerChain) { - auto clipGeometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 4); - auto clipGeometryVertices = clipGeometry->vertexDataAsPoint2D(); - clipGeometryVertices[0].set(clipRegion.p1().x(), clipRegion.p1().y()); - clipGeometryVertices[1].set(clipRegion.p2().x(), clipRegion.p2().y()); - clipGeometryVertices[2].set(clipRegion.p4().x(), clipRegion.p4().y()); - clipGeometryVertices[3].set(clipRegion.p3().x(), clipRegion.p3().y()); - auto clipNode = new QSGClipNode; - clipNode->setGeometry(clipGeometry); - clipNode->setIsRectangular(false); - clipNode->setFlag(QSGNode::OwnsGeometry); - currentLayerChain->appendChildNode(clipNode); - currentLayerChain = clipNode; - } - handleQuad(quad, currentLayerChain, - nodeHandler, resourceTracker, apiDelegate); -} - -void DelegatedFrameNode::handleQuad( - const viz::DrawQuad *quad, - QSGNode *currentLayerChain, - DelegatedNodeTreeHandler *nodeHandler, - const CompositorResourceTracker *resourceTracker, - RenderWidgetHostViewQtDelegate *apiDelegate) -{ - switch (quad->material) { - case viz::DrawQuad::RENDER_PASS: { - const viz::RenderPassDrawQuad *renderPassQuad = viz::RenderPassDrawQuad::MaterialCast(quad); - if (!renderPassQuad->mask_texture_size.IsEmpty()) { - const CompositorResource *resource = findAndHoldResource(renderPassQuad->mask_resource_id(), resourceTracker); - Q_UNUSED(resource); // FIXME: QTBUG-67652 - } - QSGLayer *layer = - findRenderPassLayer(renderPassQuad->render_pass_id, m_sgObjects.renderPassLayers).data(); - - if (layer) - nodeHandler->setupRenderPassNode(layer, toQt(quad->rect), toQt(renderPassQuad->tex_coord_rect), currentLayerChain); - - break; - } - case viz::DrawQuad::TEXTURE_CONTENT: { - const viz::TextureDrawQuad *tquad = viz::TextureDrawQuad::MaterialCast(quad); - const CompositorResource *resource = findAndHoldResource(tquad->resource_id(), resourceTracker); - QSGTexture *texture = - initAndHoldTexture(resource, quad->ShouldDrawWithBlending(), apiDelegate); - QSizeF textureSize; - if (texture) - textureSize = texture->textureSize(); - gfx::RectF uv_rect = - gfx::ScaleRect(gfx::BoundingRect(tquad->uv_top_left, tquad->uv_bottom_right), - textureSize.width(), textureSize.height()); - - nodeHandler->setupTextureContentNode( - texture, toQt(quad->rect), toQt(uv_rect), - tquad->y_flipped ? QSGImageNode::MirrorVertically : QSGImageNode::NoTransform, - currentLayerChain); - break; - } - case viz::DrawQuad::SOLID_COLOR: { - const viz::SolidColorDrawQuad *scquad = viz::SolidColorDrawQuad::MaterialCast(quad); - // Qt only supports MSAA and this flag shouldn't be needed. - // If we ever want to use QSGRectangleNode::setAntialiasing for this we should - // try to see if we can do something similar for tile quads first. - Q_UNUSED(scquad->force_anti_aliasing_off); - nodeHandler->setupSolidColorNode(toQt(quad->rect), toQt(scquad->color), currentLayerChain); - break; -#ifndef QT_NO_OPENGL - } - case viz::DrawQuad::DEBUG_BORDER: { - const viz::DebugBorderDrawQuad *dbquad = viz::DebugBorderDrawQuad::MaterialCast(quad); - - QSGGeometry *geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 4); - geometry->setDrawingMode(GL_LINE_LOOP); - geometry->setLineWidth(dbquad->width); - // QSGGeometry::updateRectGeometry would actually set the - // corners in the following order: - // top-left, bottom-left, top-right, bottom-right, leading to a nice criss cross, - // instead of having a closed loop. - const gfx::Rect &r(dbquad->rect); - geometry->vertexDataAsPoint2D()[0].set(r.x(), r.y()); - geometry->vertexDataAsPoint2D()[1].set(r.x() + r.width(), r.y()); - geometry->vertexDataAsPoint2D()[2].set(r.x() + r.width(), r.y() + r.height()); - geometry->vertexDataAsPoint2D()[3].set(r.x(), r.y() + r.height()); - - QSGFlatColorMaterial *material = new QSGFlatColorMaterial; - material->setColor(toQt(dbquad->color)); - - nodeHandler->setupDebugBorderNode(geometry, material, currentLayerChain); - break; -#endif - } - case viz::DrawQuad::TILED_CONTENT: { - const viz::TileDrawQuad *tquad = viz::TileDrawQuad::MaterialCast(quad); - const CompositorResource *resource = findAndHoldResource(tquad->resource_id(), resourceTracker); - nodeHandler->setupTextureContentNode( - initAndHoldTexture(resource, quad->ShouldDrawWithBlending(), apiDelegate), - toQt(quad->rect), toQt(tquad->tex_coord_rect), - QSGImageNode::NoTransform, currentLayerChain); - break; -#ifndef QT_NO_OPENGL - } - case viz::DrawQuad::YUV_VIDEO_CONTENT: { - const viz::YUVVideoDrawQuad *vquad = viz::YUVVideoDrawQuad::MaterialCast(quad); - const CompositorResource *yResource = - findAndHoldResource(vquad->y_plane_resource_id(), resourceTracker); - const CompositorResource *uResource = - findAndHoldResource(vquad->u_plane_resource_id(), resourceTracker); - const CompositorResource *vResource = - findAndHoldResource(vquad->v_plane_resource_id(), resourceTracker); - const CompositorResource *aResource = nullptr; - // This currently requires --enable-vp8-alpha-playback and - // needs a video with alpha data to be triggered. - if (vquad->a_plane_resource_id()) - aResource = findAndHoldResource(vquad->a_plane_resource_id(), resourceTracker); - - nodeHandler->setupYUVVideoNode( - initAndHoldTexture(yResource, quad->ShouldDrawWithBlending()), - initAndHoldTexture(uResource, quad->ShouldDrawWithBlending()), - initAndHoldTexture(vResource, quad->ShouldDrawWithBlending()), - aResource ? initAndHoldTexture(aResource, quad->ShouldDrawWithBlending()) : 0, - toQt(vquad->ya_tex_coord_rect), toQt(vquad->uv_tex_coord_rect), - toQt(vquad->ya_tex_size), toQt(vquad->uv_tex_size), vquad->video_color_space, - vquad->resource_multiplier, vquad->resource_offset, toQt(quad->rect), - currentLayerChain); - break; -#ifdef GL_OES_EGL_image_external - } - case viz::DrawQuad::STREAM_VIDEO_CONTENT: { - const viz::StreamVideoDrawQuad *squad = viz::StreamVideoDrawQuad::MaterialCast(quad); - const CompositorResource *resource = findAndHoldResource(squad->resource_id(), resourceTracker); - MailboxTexture *texture = static_cast<MailboxTexture *>( - initAndHoldTexture(resource, quad->ShouldDrawWithBlending(), apiDelegate, GL_TEXTURE_EXTERNAL_OES)); - - QMatrix4x4 qMatrix; -// convertToQt(squad->matrix.matrix(), qMatrix); - nodeHandler->setupStreamVideoNode(texture, toQt(squad->rect), qMatrix, currentLayerChain); - break; -#endif // GL_OES_EGL_image_external -#endif // QT_NO_OPENGL - } - case viz::DrawQuad::SURFACE_CONTENT: - Q_UNREACHABLE(); - default: - qWarning("Unimplemented quad material: %d", quad->material); - } -} - -const CompositorResource *DelegatedFrameNode::findAndHoldResource(unsigned resourceId, const CompositorResourceTracker *resourceTracker) -{ - return resourceTracker->findResource(resourceId); -} - -void DelegatedFrameNode::holdResources(const viz::DrawQuad *quad, const CompositorResourceTracker *resourceTracker) -{ - for (auto resource : quad->resources) - findAndHoldResource(resource, resourceTracker); -} - -void DelegatedFrameNode::holdResources(const viz::RenderPass *pass, const CompositorResourceTracker *resourceTracker) -{ - for (const auto &quad : pass->quad_list) - holdResources(quad, resourceTracker); -} - -template<class Container, class Key> -inline auto &findTexture(Container &map, Container &previousMap, const Key &key) -{ - auto &value = map[key]; - if (value) - return value; - value = previousMap[key]; - return value; -} - -QSGTexture *DelegatedFrameNode::initAndHoldTexture(const CompositorResource *resource, bool hasAlphaChannel, RenderWidgetHostViewQtDelegate *apiDelegate, int target) -{ - QSGTexture::Filtering filtering; - - if (resource->filter == GL_NEAREST) - filtering = QSGTexture::Nearest; - else if (resource->filter == GL_LINEAR) - filtering = QSGTexture::Linear; - else { - // Depends on qtdeclarative fix, see QTBUG-71322 -#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 1) - filtering = QSGTexture::Linear; -#else - filtering = QSGTexture::Nearest; -#endif - } - - if (resource->is_software) { - QSharedPointer<QSGTexture> &texture = - findTexture(m_sgObjects.bitmapTextures, m_previousSGObjects.bitmapTextures, resource->id); - if (texture) - return texture.data(); - texture = createBitmapTexture(resource, hasAlphaChannel, apiDelegate); - texture->setFiltering(filtering); - return texture.data(); - } else { -#if QT_CONFIG(opengl) - QSharedPointer<MailboxTexture> &texture = - findTexture(m_sgObjects.mailboxTextures, m_previousSGObjects.mailboxTextures, resource->id); - if (texture) - return texture.data(); - texture = createMailboxTexture(resource, hasAlphaChannel, target); - texture->setFiltering(filtering); - return texture.data(); -#else - Q_UNREACHABLE(); - return nullptr; -#endif - } -} - -QSharedPointer<QSGTexture> DelegatedFrameNode::createBitmapTexture(const CompositorResource *resource, bool hasAlphaChannel, RenderWidgetHostViewQtDelegate *apiDelegate) -{ - Q_ASSERT(apiDelegate); - viz::SharedBitmap *sharedBitmap = resource->bitmap.get(); - gfx::Size size = resource->size; - - // QSG interprets QImage::hasAlphaChannel meaning that a node should enable blending - // to draw it but Chromium keeps this information in the quads. - // The input format is currently always Format_ARGB32_Premultiplied, so assume that all - // alpha bytes are 0xff if quads aren't requesting blending and avoid the conversion - // from Format_ARGB32_Premultiplied to Format_RGB32 just to get hasAlphaChannel to - // return false. - QImage::Format format = hasAlphaChannel ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; - QImage image = sharedBitmap - ? QImage(sharedBitmap->pixels(), size.width(), size.height(), format) - : QImage(size.width(), size.height(), format); - return QSharedPointer<QSGTexture>(apiDelegate->createTextureFromImage(image.copy())); -} - -QSharedPointer<MailboxTexture> DelegatedFrameNode::createMailboxTexture(const CompositorResource *resource, bool hasAlphaChannel, int target) -{ -#ifndef QT_NO_OPENGL - return QSharedPointer<MailboxTexture>::create(resource, hasAlphaChannel, target); -#else - Q_UNREACHABLE(); -#endif -} - -void DelegatedFrameNode::copyMailboxTextures() -{ -#if !defined(QT_NO_OPENGL) && defined(USE_OZONE) - // Workaround when context is not shared QTBUG-48969 - // Make slow copy between two contexts. - if (!m_contextShared) { - QOpenGLContext *currentContext = QOpenGLContext::currentContext() ; - QOpenGLContext *sharedContext = qt_gl_global_share_context(); - - QSurface *surface = currentContext->surface(); - Q_ASSERT(m_offsurface); - sharedContext->makeCurrent(m_offsurface.data()); - QOpenGLFunctions *funcs = sharedContext->functions(); - - GLuint fbo = 0; - funcs->glGenFramebuffers(1, &fbo); - - for (const QSharedPointer<MailboxTexture> &mailboxTexture : qAsConst(m_sgObjects.mailboxTextures)) { - if (mailboxTexture->m_ownsTexture) - continue; - - // Read texture into QImage from shared context. - // Switch to shared context. - sharedContext->makeCurrent(m_offsurface.data()); - funcs = sharedContext->functions(); - QImage img(mailboxTexture->textureSize(), QImage::Format_RGBA8888_Premultiplied); - funcs->glBindFramebuffer(GL_FRAMEBUFFER, fbo); - mailboxTexture->m_fence->wait(); - funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mailboxTexture->m_textureId, 0); - GLenum status = funcs->glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - qWarning("fbo error, skipping slow copy..."); - continue; - } - funcs->glReadPixels(0, 0, mailboxTexture->textureSize().width(), mailboxTexture->textureSize().height(), - GL_RGBA, GL_UNSIGNED_BYTE, img.bits()); - - // Restore current context. - // Create texture from QImage in current context. - currentContext->makeCurrent(surface); - GLuint texture = 0; - funcs = currentContext->functions(); - funcs->glGenTextures(1, &texture); - funcs->glBindTexture(GL_TEXTURE_2D, texture); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mailboxTexture->textureSize().width(), mailboxTexture->textureSize().height(), 0, - GL_RGBA, GL_UNSIGNED_BYTE, img.bits()); - mailboxTexture->m_textureId = texture; - mailboxTexture->m_ownsTexture = true; - } - // Cleanup allocated resources - sharedContext->makeCurrent(m_offsurface.data()); - funcs = sharedContext->functions(); - funcs->glBindFramebuffer(GL_FRAMEBUFFER, 0); - funcs->glDeleteFramebuffers(1, &fbo); - currentContext->makeCurrent(surface); - } -#endif -} - -} // namespace QtWebEngineCore diff --git a/src/core/compositor/delegated_frame_node.h b/src/core/compositor/delegated_frame_node.h deleted file mode 100644 index 34e4ba029..000000000 --- a/src/core/compositor/delegated_frame_node.h +++ /dev/null @@ -1,133 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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 DELEGATED_FRAME_NODE_H -#define DELEGATED_FRAME_NODE_H - -#include "base/containers/circular_deque.h" -#include "components/viz/common/quads/compositor_frame.h" -#include "components/viz/common/quads/render_pass.h" - -#include <QtCore/QSharedPointer> -#include <QtGui/QOffscreenSurface> -#include <QtQuick/QSGTransformNode> - -#include "chromium_gpu_helper.h" -#include "render_widget_host_view_qt_delegate.h" - -QT_BEGIN_NAMESPACE -class QSGLayer; -QT_END_NAMESPACE - -namespace gfx { -class QuadF; -} - -namespace viz { -class DelegatedFrameData; -class DrawQuad; -class DrawPolygon; -} - -namespace QtWebEngineCore { - -class CompositorResource; -class CompositorResourceTracker; -class DelegatedNodeTreeHandler; -class MailboxTexture; - -class DelegatedFrameNode : public QSGTransformNode { -public: - DelegatedFrameNode(); - ~DelegatedFrameNode(); - void preprocess() override; - void commit(const viz::CompositorFrame &pendingFrame, const viz::CompositorFrame &committedFrame, const CompositorResourceTracker *resourceTracker, RenderWidgetHostViewQtDelegate *apiDelegate); - -private: - void flushPolygons(base::circular_deque<std::unique_ptr<viz::DrawPolygon> > *polygonQueue, - QSGNode *renderPassChain, - DelegatedNodeTreeHandler *nodeHandler, - const CompositorResourceTracker *resourceTracker, - RenderWidgetHostViewQtDelegate *apiDelegate); - void handlePolygon( - const viz::DrawPolygon *polygon, - QSGNode *currentLayerChain, - DelegatedNodeTreeHandler *nodeHandler, - const CompositorResourceTracker *resourceTracker, - RenderWidgetHostViewQtDelegate *apiDelegate); - void handleClippedQuad( - const viz::DrawQuad *quad, - const gfx::QuadF &clipRegion, - QSGNode *currentLayerChain, - DelegatedNodeTreeHandler *nodeHandler, - const CompositorResourceTracker *resourceTracker, - RenderWidgetHostViewQtDelegate *apiDelegate); - void handleQuad( - const viz::DrawQuad *quad, - QSGNode *currentLayerChain, - DelegatedNodeTreeHandler *nodeHandler, - const CompositorResourceTracker *resourceTracker, - RenderWidgetHostViewQtDelegate *apiDelegate); - - const CompositorResource *findAndHoldResource(unsigned resourceId, const CompositorResourceTracker *resourceTracker); - void holdResources(const viz::DrawQuad *quad, const CompositorResourceTracker *resourceTracker); - void holdResources(const viz::RenderPass *pass, const CompositorResourceTracker *resourceTracker); - QSGTexture *initAndHoldTexture(const CompositorResource *resource, bool hasAlphaChannel, RenderWidgetHostViewQtDelegate *apiDelegate = 0, int target = -1); - QSharedPointer<QSGTexture> createBitmapTexture(const CompositorResource *resource, bool hasAlphaChannel, RenderWidgetHostViewQtDelegate *apiDelegate); - QSharedPointer<MailboxTexture> createMailboxTexture(const CompositorResource *resource, bool hasAlphaChannel, int target); - - void copyMailboxTextures(); - - struct SGObjects { - QVector<QPair<int, QSharedPointer<QSGLayer> > > renderPassLayers; - QVector<QSharedPointer<QSGRootNode> > renderPassRootNodes; - QHash<unsigned, QSharedPointer<QSGTexture> > bitmapTextures; - QHash<unsigned, QSharedPointer<MailboxTexture> > mailboxTextures; - } m_sgObjects, m_previousSGObjects; - QVector<QSGNode*> m_sceneGraphNodes; -#if defined(USE_OZONE) - bool m_contextShared; - QScopedPointer<QOffscreenSurface> m_offsurface; -#endif - QSize m_previousViewportSize; -}; - -} // namespace QtWebEngineCore - -#endif // DELEGATED_FRAME_NODE_H diff --git a/src/core/compositor/display_consumer.h b/src/core/compositor/display_consumer.h deleted file mode 100644 index d220088ad..000000000 --- a/src/core/compositor/display_consumer.h +++ /dev/null @@ -1,62 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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 DISPLAY_CONSUMER_H -#define DISPLAY_CONSUMER_H - -#include "qtwebenginecoreglobal_p.h" - -namespace QtWebEngineCore { - -// Receives composited frames for display. -class DisplayConsumer -{ -public: - // Schedule a call to updatePaintNode soon. - // - // Called on the consumer thread. - virtual void scheduleUpdate() = 0; - -protected: - ~DisplayConsumer() {} -}; - -} // namespace QtWebEngineCore - -#endif // !DISPLAY_CONSUMER_H diff --git a/src/core/compositor/display_frame_sink.cpp b/src/core/compositor/display_frame_sink.cpp deleted file mode 100644 index 945600299..000000000 --- a/src/core/compositor/display_frame_sink.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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 "display_frame_sink.h" - -#include <QMap> - -namespace QtWebEngineCore { - -namespace { - -class DisplayFrameSinkMap -{ -public: - static DisplayFrameSinkMap *instance() - { - static DisplayFrameSinkMap map; - return ↦ - } - - scoped_refptr<DisplayFrameSink> findOrCreate(viz::FrameSinkId frameSinkId) - { - QMutexLocker locker(&m_mutex); - auto it = m_map.find(frameSinkId); - if (it == m_map.end()) - it = m_map.insert(frameSinkId, new DisplayFrameSink(frameSinkId)); - return *it; - } - - void remove(viz::FrameSinkId frameSinkId) - { - QMutexLocker locker(&m_mutex); - m_map.remove(frameSinkId); - } - -private: - mutable QMutex m_mutex; - QMap<viz::FrameSinkId, DisplayFrameSink *> m_map; -}; - -} // namespace - -// static -scoped_refptr<DisplayFrameSink> DisplayFrameSink::findOrCreate(viz::FrameSinkId frameSinkId) -{ - return DisplayFrameSinkMap::instance()->findOrCreate(frameSinkId); -} - -DisplayFrameSink::DisplayFrameSink(viz::FrameSinkId frameSinkId) - : m_frameSinkId(frameSinkId) -{ - DCHECK(m_frameSinkId.is_valid()); -} - -DisplayFrameSink::~DisplayFrameSink() -{ - DisplayFrameSinkMap::instance()->remove(m_frameSinkId); -} - -void DisplayFrameSink::connect(DisplayConsumer *consumer) -{ - QMutexLocker locker(&m_mutex); - DCHECK(m_consumer == nullptr); - m_consumer = consumer; -} - -void DisplayFrameSink::connect(DisplayProducer *producer) -{ - QMutexLocker locker(&m_mutex); - DCHECK(m_producer == nullptr); - m_producer = producer; -} - -void DisplayFrameSink::disconnect(DisplayConsumer *consumer) -{ - QMutexLocker locker(&m_mutex); - DCHECK(m_consumer == consumer); - m_consumer = nullptr; -} - -void DisplayFrameSink::disconnect(DisplayProducer *producer) -{ - QMutexLocker locker(&m_mutex); - DCHECK(m_producer == producer); - m_producer = nullptr; -} - -void DisplayFrameSink::scheduleUpdate() -{ - QMutexLocker locker(&m_mutex); - if (m_consumer) - m_consumer->scheduleUpdate(); -} - -QSGNode *DisplayFrameSink::updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *delegate) -{ - QMutexLocker locker(&m_mutex); - QSGNode *newNode = oldNode; - if (m_producer) - newNode = m_producer->updatePaintNode(oldNode, delegate); - return newNode; -} - -} // namespace QtWebEngineCore diff --git a/src/core/compositor/display_frame_sink.h b/src/core/compositor/display_frame_sink.h deleted file mode 100644 index f620dc4f2..000000000 --- a/src/core/compositor/display_frame_sink.h +++ /dev/null @@ -1,77 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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 DISPLAY_FRAME_SINK_H -#define DISPLAY_FRAME_SINK_H - -#include "display_consumer.h" -#include "display_producer.h" - -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_refptr.h" -#include "components/viz/common/surfaces/frame_sink_id.h" - -#include <QMutex> - -namespace QtWebEngineCore { - -// Connects a DisplayConsumer with a DisplayProducer. -class DisplayFrameSink final : public base::RefCountedThreadSafe<DisplayFrameSink> -{ -public: - static scoped_refptr<DisplayFrameSink> findOrCreate(viz::FrameSinkId frameSinkId); - DisplayFrameSink(viz::FrameSinkId frameSinkId); - ~DisplayFrameSink(); - void connect(DisplayConsumer *consumer); - void connect(DisplayProducer *producer); - void disconnect(DisplayConsumer *consumer); - void disconnect(DisplayProducer *producer); - void scheduleUpdate(); - QSGNode *updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *delegate); - -private: - const viz::FrameSinkId m_frameSinkId; - mutable QMutex m_mutex; - DisplayProducer *m_producer = nullptr; - DisplayConsumer *m_consumer = nullptr; -}; - -} // namespace QtWebEngineCore - -#endif // !DISPLAY_FRAME_SINK_H diff --git a/src/core/compositor/display_gl_output_surface.cpp b/src/core/compositor/display_gl_output_surface.cpp deleted file mode 100644 index 5a78b8322..000000000 --- a/src/core/compositor/display_gl_output_surface.cpp +++ /dev/null @@ -1,292 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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 "display_gl_output_surface.h" - -#include "chromium_gpu_helper.h" - -#include "base/threading/thread_task_runner_handle.h" -#include "components/viz/service/display/display.h" -#include "components/viz/service/display/output_surface_frame.h" -#include "gpu/command_buffer/client/gles2_implementation.h" -#include "gpu/command_buffer/client/gles2_interface.h" -#include "gpu/command_buffer/service/mailbox_manager.h" -#include "gpu/command_buffer/service/texture_base.h" -#include "gpu/ipc/in_process_command_buffer.h" -#include "ui/gl/color_space_utils.h" - -namespace QtWebEngineCore { - -DisplayGLOutputSurface::DisplayGLOutputSurface( - scoped_refptr<viz::VizProcessContextProvider> contextProvider, - viz::UpdateVSyncParametersCallback callback) - : OutputSurface(contextProvider) - , m_commandBuffer(contextProvider->command_buffer()) - , m_gl(contextProvider->ContextGL()) -{ - capabilities_.uses_default_gl_framebuffer = false; - m_gl->GenFramebuffers(1, &m_fboId); - contextProvider->SetUpdateVSyncParametersCallback(std::move(callback)); -} - -DisplayGLOutputSurface::~DisplayGLOutputSurface() -{ - m_gl->DeleteFramebuffers(1, &m_fboId); - if (m_sink) - m_sink->disconnect(this); -} - -// Called from viz::Display::Initialize. -void DisplayGLOutputSurface::BindToClient(viz::OutputSurfaceClient *client) -{ - m_display = static_cast<viz::Display *>(client); - m_sink = DisplayFrameSink::findOrCreate(m_display->frame_sink_id()); - m_sink->connect(this); -} - -// Triggered by ui::Compositor::SetVisible(true). -void DisplayGLOutputSurface::EnsureBackbuffer() -{ -} - -// Triggered by ui::Compositor::SetVisible(false). Framebuffer must be cleared. -void DisplayGLOutputSurface::DiscardBackbuffer() -{ - NOTIMPLEMENTED(); - // m_gl->DiscardBackbufferCHROMIUM(); -} - -// Called from viz::DirectRenderer::DrawFrame before rendering starts, but only -// if the parameters differ from the previous Reshape call. -// -// Parameters: -// -// - sizeInPixels comes from ui::Compositor::SetScaleAndSize via -// viz::HostContextFactoryPrivate::ResizeDisplay. -// -// - devicePixelRatio comes from viz::CompositorFrame::device_scale_factor() -// via viz::RootCompositorFrameSinkImpl::SubmitCompositorFrame and -// viz::Display::SetLocalSurfaceId. -// -// - colorSpace and hasAlpha correspond to the color_space and -// has_transparent_background properties of the root viz::RenderPass. -// -// - useStencil should create a stencil buffer, but this is only needed for -// overdraw feedback (--show-overdraw-feedback), so it's safe to ignore. -// Accordingly, capabilities_.supports_stencil should be set to false. -// -void DisplayGLOutputSurface::Reshape(const gfx::Size &sizeInPixels, - float devicePixelRatio, - const gfx::ColorSpace &colorSpace, - bool hasAlpha, - bool /*useStencil*/) -{ - m_currentShape = Shape{sizeInPixels, devicePixelRatio, colorSpace, hasAlpha}; - m_gl->ResizeCHROMIUM(sizeInPixels.width(), sizeInPixels.height(), devicePixelRatio, - gl::ColorSpaceUtils::GetGLColorSpace(colorSpace), hasAlpha); -} - -std::unique_ptr<DisplayGLOutputSurface::Buffer> DisplayGLOutputSurface::makeBuffer(const Shape &shape) -{ - std::unique_ptr<Buffer> buffer = std::make_unique<Buffer>(this); - buffer->shape = shape; - m_gl->GenTextures(1, &buffer->clientId); - m_gl->BindTexture(GL_TEXTURE_2D, buffer->clientId); - m_gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - m_gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - m_gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - m_gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - uint32_t width = shape.sizeInPixels.width(); - uint32_t height = shape.sizeInPixels.height(); - uint32_t format = shape.hasAlpha ? GL_RGBA : GL_RGB; - m_gl->TexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, nullptr); - return buffer; -} - -void DisplayGLOutputSurface::deleteBufferResources(Buffer *buffer) -{ - m_gl->DeleteTextures(1, &buffer->clientId); -} - -// Called by viz::GLRenderer during rendering whenever it switches to the root -// render pass. -void DisplayGLOutputSurface::BindFramebuffer() -{ - if (!m_backBuffer || m_backBuffer->shape != m_currentShape) - m_backBuffer = makeBuffer(m_currentShape); - - m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_fboId); - m_gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_backBuffer->clientId, 0); -} - -// Called from viz::Display::DrawAndSwap after rendering. -// -// Parameters: -// -// - frame.size is the same as the size given to Reshape. -// -// - frame.sub_buffer_rect and frame.content_bounds are never used since these -// are only enabled if gl::GLSurface::SupportsPostSubBuffer() or -// gl::GLSurface::SupportsSwapBuffersWithBounds() are true, respectively, -// but this not the case for any offscreen gl::GLSurface. -// -// - frame.latency_info is viz::CompositorFrame::metadata.latency_info. -void DisplayGLOutputSurface::SwapBuffers(viz::OutputSurfaceFrame frame) -{ - DCHECK(frame.size == m_currentShape.sizeInPixels); - DCHECK(!frame.sub_buffer_rect.has_value()); - DCHECK(frame.content_bounds.empty()); - DCHECK(m_backBuffer); - - m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_fboId); - m_gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); - gpu::SyncToken syncToken; - m_gl->GenSyncTokenCHROMIUM(syncToken.GetData()); - - unsigned int clientId = m_backBuffer->clientId; - - // Now some thread-hopping: - // - // - We start here on the viz thread (client side of command buffer). - // - // - Then we'll jump to the gpu thread (service side of command buffer) to - // get the real OpenGL texture id. - // - // - Then we'll get a call from the Qt Quick Scene Graph thread (could be - // a separate thread or the main thread). - // - // - Finally we'll return to the viz thread to acknowledge the swap. - - { - QMutexLocker locker(&m_mutex); - m_taskRunner = base::ThreadTaskRunnerHandle::Get(); - m_middleBuffer = std::move(m_backBuffer); - m_middleBuffer->serviceId = 0; - } - - m_commandBuffer->GetTextureQt( - clientId, - base::BindOnce(&DisplayGLOutputSurface::swapBuffersOnGpuThread, base::Unretained(this)), - std::vector<gpu::SyncToken>{syncToken}); -} - -void DisplayGLOutputSurface::swapBuffersOnGpuThread(unsigned int id, std::unique_ptr<gl::GLFence> fence) -{ - { - QMutexLocker locker(&m_mutex); - m_middleBuffer->serviceId = id; - m_middleBuffer->fence = CompositorResourceFence::create(std::move(fence)); - } - - m_sink->scheduleUpdate(); -} - -void DisplayGLOutputSurface::swapBuffersOnVizThread() -{ - { - QMutexLocker locker(&m_mutex); - m_backBuffer = std::move(m_middleBuffer); - } - - m_display->DidReceiveSwapBuffersAck(); - m_display->DidReceivePresentationFeedback( - gfx::PresentationFeedback(base::TimeTicks::Now(), base::TimeDelta(), - gfx::PresentationFeedback::Flags::kVSync)); -} - -void DisplayGLOutputSurface::SetDrawRectangle(const gfx::Rect &) -{ -} - -// Returning nullptr here effectively disables viz::OverlayProcessor. -viz::OverlayCandidateValidator *DisplayGLOutputSurface::GetOverlayCandidateValidator() const -{ - return nullptr; -} - -// Returning true here will cause viz::GLRenderer to try to render the output -// surface as an overlay plane (see viz::DirectRenderer::DrawFrame and -// viz::GLRenderer::ScheduleOverlays). -bool DisplayGLOutputSurface::IsDisplayedAsOverlayPlane() const -{ - return false; -} - -// Only used if IsDisplayedAsOverlayPlane was true (called from -// viz::GLRenderer::ScheduleOverlays). -unsigned DisplayGLOutputSurface::GetOverlayTextureId() const -{ - return 0; -} - -// Only used if IsDisplayedAsOverlayPlane was true (called from -// viz::DirectRender::DrawFrame). -gfx::BufferFormat DisplayGLOutputSurface::GetOverlayBufferFormat() const -{ - return gfx::BufferFormat(); -} - -// Called by viz::GLRenderer but always false in all implementations except for -// android_webview::ParentOutputSurface. -bool DisplayGLOutputSurface::HasExternalStencilTest() const -{ - return false; -} - -// Only called if HasExternalStencilTest was true. Dead code? -void DisplayGLOutputSurface::ApplyExternalStencil() -{ - NOTREACHED(); -} - -// Called from GLRenderer::GetFramebufferCopyTextureFormat when using -// glCopyTexSubImage2D on our framebuffer. -uint32_t DisplayGLOutputSurface::GetFramebufferCopyTextureFormat() -{ - return GL_RGBA; -} - -// Called from viz::DirectRenderer::DrawFrame, only used for overlays. -unsigned DisplayGLOutputSurface::UpdateGpuFence() -{ - NOTREACHED(); - return 0; -} - -} // namespace QtWebEngineCore diff --git a/src/core/compositor/display_gl_output_surface.h b/src/core/compositor/display_gl_output_surface.h deleted file mode 100644 index c42a6630a..000000000 --- a/src/core/compositor/display_gl_output_surface.h +++ /dev/null @@ -1,148 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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 DISPLAY_GL_OUTPUT_SURFACE_H -#define DISPLAY_GL_OUTPUT_SURFACE_H - -#include "compositor_resource_fence.h" -#include "display_frame_sink.h" - -#include "components/viz/common/display/update_vsync_parameters_callback.h" -#include "components/viz/service/display/output_surface.h" -#include "components/viz/service/display_embedder/viz_process_context_provider.h" -#include "gpu/command_buffer/common/mailbox.h" -#include "gpu/command_buffer/common/sync_token.h" - -namespace viz { -class Display; -class SyntheticBeginFrameSource; -} // namespace viz - -namespace QtWebEngineCore { - -// NOTE: Some methods are defined in display_gl_output_surface_qsg.cpp due -// to conflicts between Qt & Chromium OpenGL APIs. -class DisplayGLOutputSurface final : public viz::OutputSurface, public DisplayProducer -{ -public: - DisplayGLOutputSurface( - scoped_refptr<viz::VizProcessContextProvider> contextProvider, - viz::UpdateVSyncParametersCallback callback); - ~DisplayGLOutputSurface() override; - - // Overridden from viz::OutputSurface. - void BindToClient(viz::OutputSurfaceClient *client) override; - void EnsureBackbuffer() override; - void DiscardBackbuffer() override; - void BindFramebuffer() override; - void SetDrawRectangle(const gfx::Rect &drawRect) override; - viz::OverlayCandidateValidator *GetOverlayCandidateValidator() const override; - bool IsDisplayedAsOverlayPlane() const override; - unsigned GetOverlayTextureId() const override; - gfx::BufferFormat GetOverlayBufferFormat() const override; - void Reshape(const gfx::Size &size, - float devicePixelRatio, - const gfx::ColorSpace &colorSpace, - bool hasAlpha, - bool useStencil) override; - bool HasExternalStencilTest() const override; - void ApplyExternalStencil() override; - uint32_t GetFramebufferCopyTextureFormat() override; - void SwapBuffers(viz::OutputSurfaceFrame frame) override; - unsigned UpdateGpuFence() override; - - // Overridden from DisplayProducer. - QSGNode *updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *delegate) override; - -private: - struct Shape - { - gfx::Size sizeInPixels; - float devicePixelRatio; - gfx::ColorSpace colorSpace; - bool hasAlpha; - - bool operator==(const Shape &that) const - { - return (sizeInPixels == that.sizeInPixels && - devicePixelRatio == that.devicePixelRatio && - colorSpace == that.colorSpace && - hasAlpha == that.hasAlpha); - } - bool operator!=(const Shape &that) const { return !(*this == that); } - }; - - struct Buffer - { - DisplayGLOutputSurface *parent; - Shape shape; - uint32_t clientId = 0; - uint32_t serviceId = 0; - scoped_refptr<CompositorResourceFence> fence; - - Buffer(DisplayGLOutputSurface *parent) : parent(parent) {} - ~Buffer() { parent->deleteBufferResources(this); } - }; - - class Texture; - - void swapBuffersOnGpuThread(unsigned int id, std::unique_ptr<gl::GLFence> fence); - void swapBuffersOnVizThread(); - - std::unique_ptr<Buffer> makeBuffer(const Shape &shape); - void deleteBufferResources(Buffer *buffer); - void attachBuffer(); - void detachBuffer(); - - gpu::InProcessCommandBuffer *const m_commandBuffer; - gpu::gles2::GLES2Interface *const m_gl; - mutable QMutex m_mutex; - uint32_t m_fboId = 0; - viz::Display *m_display = nullptr; - scoped_refptr<DisplayFrameSink> m_sink; - Shape m_currentShape; - std::unique_ptr<Buffer> m_backBuffer; - std::unique_ptr<Buffer> m_middleBuffer; - std::unique_ptr<Buffer> m_frontBuffer; - scoped_refptr<base::SingleThreadTaskRunner> m_taskRunner; -}; - -} // namespace QtWebEngineCore - -#endif // !DISPLAY_GL_OUTPUT_SURFACE_H diff --git a/src/core/compositor/display_gl_output_surface_qsg.cpp b/src/core/compositor/display_gl_output_surface_qsg.cpp deleted file mode 100644 index 2f7b3de84..000000000 --- a/src/core/compositor/display_gl_output_surface_qsg.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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 "display_gl_output_surface.h" - -#include "compositor_resource_fence.h" -#include "render_widget_host_view_qt_delegate.h" -#include "type_conversion.h" - -#include <QOpenGLFunctions> -#include <QSGImageNode> -#include <QSGTexture> - -namespace QtWebEngineCore { - -class DisplayGLOutputSurface::Texture final : public QSGTexture -{ -public: - Texture(uint32_t id, QSize sizeInPixels, bool hasAlphaChannel, scoped_refptr<CompositorResourceFence> fence) - : m_id(id) - , m_sizeInPixels(sizeInPixels) - , m_hasAlphaChannel(hasAlphaChannel) - , m_fence(std::move(fence)) - { - } - - // QSGTexture: - int textureId() const override { return m_id; } - QSize textureSize() const override { return m_sizeInPixels; } - bool hasAlphaChannel() const override { return m_hasAlphaChannel; } - bool hasMipmaps() const override { return false; } - void bind() override - { - if (m_fence) { - m_fence->wait(); - m_fence.reset(); - } - - QOpenGLContext *context = QOpenGLContext::currentContext(); - QOpenGLFunctions *funcs = context->functions(); - funcs->glBindTexture(GL_TEXTURE_2D, m_id); - } - -private: - uint32_t m_id; - QSize m_sizeInPixels; - bool m_hasAlphaChannel; - scoped_refptr<CompositorResourceFence> m_fence; -}; - -QSGNode *DisplayGLOutputSurface::updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *delegate) -{ - { - QMutexLocker locker(&m_mutex); - if (m_middleBuffer && m_middleBuffer->serviceId) { - std::swap(m_middleBuffer, m_frontBuffer); - m_taskRunner->PostTask( - FROM_HERE, - base::BindOnce(&DisplayGLOutputSurface::swapBuffersOnVizThread, base::Unretained(this))); - m_taskRunner.reset(); - } - } - - if (!m_frontBuffer) - return oldNode; - - auto node = static_cast<QSGImageNode *>(oldNode); - if (!node) - node = delegate->createImageNode(); - - QSize sizeInPixels = toQt(m_frontBuffer->shape.sizeInPixels); - QSizeF sizeInDips = QSizeF(sizeInPixels) / m_frontBuffer->shape.devicePixelRatio; - QRectF rectInDips(QPointF(0, 0), sizeInDips); - node->setRect(rectInDips); - node->setOwnsTexture(true); - node->setTexture(new Texture(m_frontBuffer->serviceId, - sizeInPixels, - m_frontBuffer->shape.hasAlpha, - m_frontBuffer->fence)); - node->setTextureCoordinatesTransform(QSGImageNode::MirrorVertically); - - return node; -} - -} // namespace QtWebEngineCore diff --git a/src/core/compositor/display_overrides.cpp b/src/core/compositor/display_overrides.cpp index 4547bb04b..ebaa96dbb 100644 --- a/src/core/compositor/display_overrides.cpp +++ b/src/core/compositor/display_overrides.cpp @@ -1,80 +1,100 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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 "display_gl_output_surface.h" +// Copyright (C) 2019 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 "display_skia_output_device.h" #include "display_software_output_surface.h" +#include "native_skia_output_device.h" -#include "components/viz/service/display_embedder/gpu_display_provider.h" +#include "components/viz/service/display_embedder/output_surface_provider_impl.h" +#include "components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h" #include "gpu/ipc/in_process_command_buffer.h" -std::unique_ptr<viz::OutputSurface> -viz::GpuDisplayProvider::CreateGLOutputSurface( - scoped_refptr<VizProcessContextProvider> context_provider, - UpdateVSyncParametersCallback update_vsync_callback) -{ - return std::make_unique<QtWebEngineCore::DisplayGLOutputSurface>( - std::move(context_provider), std::move(update_vsync_callback)); -} +#include <qtgui-config.h> +#include <QtQuick/qquickwindow.h> + +#if QT_CONFIG(opengl) +#include "native_skia_output_device_opengl.h" +#endif + +#if BUILDFLAG(ENABLE_VULKAN) +#include "native_skia_output_device_vulkan.h" +#endif + +#if defined(Q_OS_WIN) +#include "native_skia_output_device_direct3d11.h" +#endif + +#if defined(Q_OS_MACOS) +#include "native_skia_output_device_metal.h" +#endif std::unique_ptr<viz::OutputSurface> -viz::GpuDisplayProvider::CreateSoftwareOutputSurface( - UpdateVSyncParametersCallback update_vsync_callback) +viz::OutputSurfaceProviderImpl::CreateSoftwareOutputSurface(const RendererSettings &renderer_settings) { - return std::make_unique<QtWebEngineCore::DisplaySoftwareOutputSurface>(std::move(update_vsync_callback)); + return std::make_unique<QtWebEngineCore::DisplaySoftwareOutputSurface>(renderer_settings.requires_alpha_channel); } -void gpu::InProcessCommandBuffer::GetTextureQt( - unsigned int client_id, - GetTextureCallback callback, - const std::vector<SyncToken>& sync_token_fences) +std::unique_ptr<viz::SkiaOutputDevice> +viz::SkiaOutputSurfaceImplOnGpu::CreateOutputDevice() { - ScheduleGpuTask(base::BindOnce(&InProcessCommandBuffer::GetTextureQtOnGpuThread, - gpu_thread_weak_ptr_factory_.GetWeakPtr(), - client_id, - std::move(callback)), - sync_token_fences); -} + static const auto graphicsApi = QQuickWindow::graphicsApi(); -void gpu::InProcessCommandBuffer::GetTextureQtOnGpuThread( - unsigned int client_id, GetTextureCallback callback) -{ - MakeCurrent(); - gpu::TextureBase *texture = decoder_->GetTextureBase(client_id); - std::move(callback).Run(texture ? texture->service_id() : 0, gl::GLFence::Create()); +#if QT_CONFIG(opengl) + if (graphicsApi == QSGRendererInterface::OpenGL) { + if (gl::GetGLImplementation() != gl::kGLImplementationEGLANGLE) { +#if !defined(Q_OS_MACOS) + return std::make_unique<QtWebEngineCore::DisplaySkiaOutputDevice>( + context_state_, renderer_settings_.requires_alpha_channel, + shared_gpu_deps_->memory_tracker(), GetDidSwapBuffersCompleteCallback()); +#else + qFatal("macOS only supports ANGLE."); +#endif // !defined(Q_OS_MACOS) + } + + return std::make_unique<QtWebEngineCore::NativeSkiaOutputDeviceOpenGL>( + context_state_, renderer_settings_.requires_alpha_channel, + shared_gpu_deps_->memory_tracker(), dependency_.get(), shared_image_factory_.get(), + shared_image_representation_factory_.get(), GetDidSwapBuffersCompleteCallback()); + } +#endif // QT_CONFIG(opengl) + +#if BUILDFLAG(ENABLE_VULKAN) + if (graphicsApi == QSGRendererInterface::Vulkan) { +#if !defined(Q_OS_MACOS) + return std::make_unique<QtWebEngineCore::NativeSkiaOutputDeviceVulkan>( + context_state_, renderer_settings_.requires_alpha_channel, + shared_gpu_deps_->memory_tracker(), dependency_.get(), shared_image_factory_.get(), + shared_image_representation_factory_.get(), GetDidSwapBuffersCompleteCallback()); +#else + qFatal("Vulkan is not supported on macOS."); +#endif // !defined(Q_OS_MACOS) + } +#endif // BUILDFLAG(ENABLE_VULKAN) + +#if defined(Q_OS_WIN) + if (graphicsApi == QSGRendererInterface::Direct3D11) { + if (gl::GetGLImplementation() != gl::kGLImplementationEGLANGLE) + qFatal("Direct3D11 is only supported over ANGLE."); + + return std::make_unique<QtWebEngineCore::NativeSkiaOutputDeviceDirect3D11>( + context_state_, renderer_settings_.requires_alpha_channel, + shared_gpu_deps_->memory_tracker(), dependency_.get(), shared_image_factory_.get(), + shared_image_representation_factory_.get(), GetDidSwapBuffersCompleteCallback()); + } +#endif + +#if defined(Q_OS_MACOS) + if (graphicsApi == QSGRendererInterface::Metal) { + if (gl::GetGLImplementation() != gl::kGLImplementationEGLANGLE) + qFatal("Metal is only supported over ANGLE."); + + return std::make_unique<QtWebEngineCore::NativeSkiaOutputDeviceMetal>( + context_state_, renderer_settings_.requires_alpha_channel, + shared_gpu_deps_->memory_tracker(), dependency_.get(), shared_image_factory_.get(), + shared_image_representation_factory_.get(), GetDidSwapBuffersCompleteCallback()); + } +#endif + + qFatal() << "Unsupported Graphics API:" << graphicsApi; + return nullptr; } diff --git a/src/core/compositor/display_producer.h b/src/core/compositor/display_producer.h deleted file mode 100644 index 5de09d2d2..000000000 --- a/src/core/compositor/display_producer.h +++ /dev/null @@ -1,69 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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 DISPLAY_PRODUCER_H -#define DISPLAY_PRODUCER_H - -#include "qtwebenginecoreglobal_p.h" - -QT_BEGIN_NAMESPACE -class QSGNode; -QT_END_NAMESPACE - -namespace QtWebEngineCore { -class RenderWidgetHostViewQtDelegate; - -// Produces composited frames for display. -class DisplayProducer -{ -public: - // Generate scene graph nodes for the current frame. - // - // If this is a scheduled update (that is, scheduleUpdate was called - // earlier), then updatePaintNode will generate nodes for a new frame. - // Otherwise, it will just regenerate nodes for the old frame. - virtual QSGNode *updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *delegate) = 0; - -protected: - ~DisplayProducer() {} -}; - -} // namespace QtWebEngineCore - -#endif // !DISPLAY_PRODUCER_H diff --git a/src/core/compositor/display_skia_output_device.cpp b/src/core/compositor/display_skia_output_device.cpp new file mode 100644 index 000000000..ab891f814 --- /dev/null +++ b/src/core/compositor/display_skia_output_device.cpp @@ -0,0 +1,240 @@ +// Copyright (C) 2021 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 "display_skia_output_device.h" + +#include "compositor_resource_fence.h" +#include "type_conversion.h" + +#include "gpu/command_buffer/service/skia_utils.h" +#include "third_party/skia/include/core/SkSurface.h" +#include "third_party/skia/include/core/SkSurfaceProps.h" +#include "third_party/skia/include/gpu/ganesh/SkSurfaceGanesh.h" +#include "third_party/skia/include/gpu/ganesh/gl/GrGLBackendSurface.h" + +#include <QSGTexture> + +namespace QtWebEngineCore { + +class DisplaySkiaOutputDevice::Buffer +{ +public: + Buffer(DisplaySkiaOutputDevice *parent) + : m_parent(parent) + , m_shape(m_parent->m_shape) + { + } + void initialize() + { + const auto &colorType = m_shape.imageInfo.colorType(); + DCHECK(colorType != kUnknown_SkColorType); + + m_texture = m_parent->m_contextState->gr_context()->createBackendTexture( + m_shape.imageInfo.width(), m_shape.imageInfo.height(), colorType, + skgpu::Mipmapped::kNo, GrRenderable::kYes); + DCHECK(m_texture.isValid()); + + DCHECK(m_texture.backend() == GrBackendApi::kOpenGL); + auto info = SkImageInfo::Make(m_shape.imageInfo.width(), m_shape.imageInfo.height(), + colorType, kUnpremul_SkAlphaType); + m_estimatedSize = info.computeMinByteSize(); + m_parent->memory_type_tracker_->TrackMemAlloc(m_estimatedSize); + + SkSurfaceProps surfaceProps = SkSurfaceProps{0, kUnknown_SkPixelGeometry}; + m_surface = SkSurfaces::WrapBackendTexture( + m_parent->m_contextState->gr_context(), m_texture, + m_parent->capabilities_.output_surface_origin == gfx::SurfaceOrigin::kTopLeft + ? kTopLeft_GrSurfaceOrigin + : kBottomLeft_GrSurfaceOrigin, + 0 /* sampleCount */, colorType, m_shape.colorSpace.ToSkColorSpace(), + &surfaceProps); + } + + ~Buffer() + { + if (m_texture.isValid()) { + DeleteGrBackendTexture(m_parent->m_contextState.get(), &m_texture); + m_parent->memory_type_tracker_->TrackMemFree(m_estimatedSize); + } + } + + void createFence() + { + m_fence = CompositorResourceFence::create(); + } + + void consumeFence() + { + if (m_fence) { + m_fence->wait(); + m_fence.reset(); + } + } + + const Shape &shape() const { return m_shape; } + const GrBackendTexture &texture() const { return m_texture; } + SkSurface *surface() const { return m_surface.get(); } + +private: + DisplaySkiaOutputDevice *m_parent; + Shape m_shape; + GrBackendTexture m_texture; + sk_sp<SkSurface> m_surface; + uint64_t m_estimatedSize = 0; + scoped_refptr<CompositorResourceFence> m_fence; +}; + +DisplaySkiaOutputDevice::DisplaySkiaOutputDevice( + scoped_refptr<gpu::SharedContextState> contextState, + bool requiresAlpha, + gpu::MemoryTracker *memoryTracker, + DidSwapBufferCompleteCallback didSwapBufferCompleteCallback) + : SkiaOutputDevice(contextState->gr_context(), contextState->graphite_context(), + memoryTracker, didSwapBufferCompleteCallback) + , Compositor(Compositor::Type::OpenGL) + , m_contextState(contextState) + , m_requiresAlpha(requiresAlpha) +{ + capabilities_.uses_default_gl_framebuffer = false; + capabilities_.supports_surfaceless = true; + capabilities_.preserve_buffer_content = true; + capabilities_.only_invalidates_damage_rect = false; + capabilities_.number_of_buffers = 3; + + capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::RGBA_8888)] = + kRGBA_8888_SkColorType; + capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::RGBX_8888)] = + kRGBA_8888_SkColorType; + capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::BGRA_8888)] = + kRGBA_8888_SkColorType; + capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::BGRX_8888)] = + kRGBA_8888_SkColorType; +} + +DisplaySkiaOutputDevice::~DisplaySkiaOutputDevice() +{ +} + +void DisplaySkiaOutputDevice::SetFrameSinkId(const viz::FrameSinkId &id) +{ + bind(id); +} +bool DisplaySkiaOutputDevice::Reshape(const SkImageInfo &image_info, + const gfx::ColorSpace &colorSpace, + int sample_count, + float device_scale_factor, + gfx::OverlayTransform transform) +{ + m_shape = Shape{image_info, device_scale_factor, colorSpace}; + DCHECK_EQ(transform, gfx::OVERLAY_TRANSFORM_NONE); + return true; +} + +void DisplaySkiaOutputDevice::Present(const absl::optional<gfx::Rect> &update_rect, + BufferPresentedCallback feedback, + viz::OutputSurfaceFrame frame) +{ + DCHECK(m_backBuffer); + + StartSwapBuffers(std::move(feedback)); + m_frame = std::move(frame); + m_backBuffer->createFence(); + + { + QMutexLocker locker(&m_mutex); + m_taskRunner = base::SingleThreadTaskRunner::GetCurrentDefault(); + std::swap(m_middleBuffer, m_backBuffer); + m_readyToUpdate = true; + } + + if (auto obs = observer()) + obs->readyToSwap(); +} + +void DisplaySkiaOutputDevice::EnsureBackbuffer() +{ +} + +void DisplaySkiaOutputDevice::DiscardBackbuffer() +{ +} + +SkSurface *DisplaySkiaOutputDevice::BeginPaint(std::vector<GrBackendSemaphore> *end_semaphores) +{ + if (!m_backBuffer || m_backBuffer->shape() != m_shape) { + m_backBuffer = std::make_unique<Buffer>(this); + m_backBuffer->initialize(); + } + return m_backBuffer->surface(); +} + +void DisplaySkiaOutputDevice::EndPaint() +{ +} + +void DisplaySkiaOutputDevice::swapFrame() +{ + QMutexLocker locker(&m_mutex); + if (m_readyToUpdate) { + std::swap(m_middleBuffer, m_frontBuffer); + m_taskRunner->PostTask(FROM_HERE, + base::BindOnce(&DisplaySkiaOutputDevice::SwapBuffersFinished, + base::Unretained(this))); + m_taskRunner.reset(); + m_readyToUpdate = false; + } +} + +void DisplaySkiaOutputDevice::waitForTexture() +{ + if (m_frontBuffer) + m_frontBuffer->consumeFence(); +} + +QSGTexture *DisplaySkiaOutputDevice::texture(QQuickWindow *win, uint32_t textureOptions) +{ + if (!m_frontBuffer) + return nullptr; + + QQuickWindow::CreateTextureOptions texOpts(textureOptions); + + QSGTexture *texture = nullptr; + GrGLTextureInfo info; + if (GrBackendTextures::GetGLTextureInfo(m_frontBuffer->texture(), &info)) + texture = QNativeInterface::QSGOpenGLTexture::fromNative(info.fID, win, size(), texOpts); + return texture; +} + +bool DisplaySkiaOutputDevice::textureIsFlipped() +{ + return true; +} + +QSize DisplaySkiaOutputDevice::size() +{ + return m_frontBuffer ? toQt(m_frontBuffer->shape().imageInfo.dimensions()) : QSize(); +} + +bool DisplaySkiaOutputDevice::requiresAlphaChannel() +{ + return m_requiresAlpha; +} + +float DisplaySkiaOutputDevice::devicePixelRatio() +{ + return m_frontBuffer ? m_frontBuffer->shape().devicePixelRatio : 1; +} + +void DisplaySkiaOutputDevice::SwapBuffersFinished() +{ + { + QMutexLocker locker(&m_mutex); + std::swap(m_backBuffer, m_middleBuffer); + } + + FinishSwapBuffers(gfx::SwapCompletionResult(gfx::SwapResult::SWAP_ACK), + gfx::Size(m_shape.imageInfo.width(), m_shape.imageInfo.height()), + std::move(m_frame)); +} + +} // namespace QtWebEngineCore diff --git a/src/core/compositor/display_skia_output_device.h b/src/core/compositor/display_skia_output_device.h new file mode 100644 index 000000000..e6a97b810 --- /dev/null +++ b/src/core/compositor/display_skia_output_device.h @@ -0,0 +1,89 @@ +// Copyright (C) 2021 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 + +#ifndef DISPLAY_SKIA_OUTPUT_DEVICE_H +#define DISPLAY_SKIA_OUTPUT_DEVICE_H + +#include <QtCore/QMutex> +#include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h> + +#include "compositor.h" + +#include "base/task/single_thread_task_runner.h" +#include "components/viz/service/display_embedder/skia_output_device.h" +#include "gpu/command_buffer/service/shared_context_state.h" + +QT_BEGIN_NAMESPACE +class QQuickWindow; +QT_END_NAMESPACE + +namespace QtWebEngineCore { + +class DisplaySkiaOutputDevice final : public viz::SkiaOutputDevice, public Compositor +{ +public: + DisplaySkiaOutputDevice(scoped_refptr<gpu::SharedContextState> contextState, + bool requiresAlpha, + gpu::MemoryTracker *memoryTracker, + DidSwapBufferCompleteCallback didSwapBufferCompleteCallback); + ~DisplaySkiaOutputDevice() override; + + // Overridden from SkiaOutputDevice. + void SetFrameSinkId(const viz::FrameSinkId &frame_sink_id) override; + bool Reshape(const SkImageInfo &image_info, + const gfx::ColorSpace &color_space, + int sample_count, + float device_scale_factor, + gfx::OverlayTransform transform) override; + void Present(const absl::optional<gfx::Rect>& update_rect, + BufferPresentedCallback feedback, + viz::OutputSurfaceFrame frame) override; + void EnsureBackbuffer() override; + void DiscardBackbuffer() override; + SkSurface *BeginPaint(std::vector<GrBackendSemaphore> *semaphores) override; + void EndPaint() override; + + // Overridden from Compositor. + void swapFrame() override; + void waitForTexture() override; + QSGTexture *texture(QQuickWindow *win, uint32_t texOpts) override; + bool textureIsFlipped() override; + QSize size() override; + bool requiresAlphaChannel() override; + float devicePixelRatio() override; + +private: + struct Shape + { + SkImageInfo imageInfo; + float devicePixelRatio; + gfx::ColorSpace colorSpace; + + bool operator==(const Shape &that) const + { + return (imageInfo == that.imageInfo && + devicePixelRatio == that.devicePixelRatio && + colorSpace == that.colorSpace); + } + bool operator!=(const Shape &that) const { return !(*this == that); } + }; + + class Buffer; + + void SwapBuffersFinished(); + + mutable QMutex m_mutex; + scoped_refptr<gpu::SharedContextState> m_contextState; + Shape m_shape; + std::unique_ptr<Buffer> m_frontBuffer; + std::unique_ptr<Buffer> m_middleBuffer; + std::unique_ptr<Buffer> m_backBuffer; + viz::OutputSurfaceFrame m_frame; + bool m_readyToUpdate = false; + bool m_requiresAlpha; + scoped_refptr<base::SingleThreadTaskRunner> m_taskRunner; +}; + +} // namespace QtWebEngineCore + +#endif // !DISPLAY_SKIA_OUTPUT_DEVICE_H diff --git a/src/core/compositor/display_software_output_surface.cpp b/src/core/compositor/display_software_output_surface.cpp index 13f8e8f38..2c208ca57 100644 --- a/src/core/compositor/display_software_output_surface.cpp +++ b/src/core/compositor/display_software_output_surface.cpp @@ -1,93 +1,53 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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) 2019 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 "display_software_output_surface.h" -#include "display_frame_sink.h" -#include "render_widget_host_view_qt_delegate.h" +#include "compositor.h" #include "type_conversion.h" -#include "base/threading/thread_task_runner_handle.h" +#include "base/task/single_thread_task_runner.h" #include "components/viz/service/display/display.h" #include "components/viz/service/display/output_surface_frame.h" #include <QMutex> #include <QPainter> -#include <QSGImageNode> +#include <QQuickWindow> namespace QtWebEngineCore { -class DisplaySoftwareOutputSurface::Device final : public viz::SoftwareOutputDevice, public DisplayProducer +class DisplaySoftwareOutputSurface::Device final : public viz::SoftwareOutputDevice, + public Compositor { public: - ~Device(); - - // Called from DisplaySoftwareOutputSurface. - void bind(viz::FrameSinkId frameSinkId); + Device(bool requiresAlpha); // Overridden from viz::SoftwareOutputDevice. void Resize(const gfx::Size &sizeInPixels, float devicePixelRatio) override; - void OnSwapBuffers(base::OnceClosure swapCompletionCallback) override; + void OnSwapBuffers(SwapBuffersCallback swap_ack_callback, gfx::FrameData data) override; - // Overridden from DisplayProducer. - QSGNode *updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *delegate) override; + // Overridden from Compositor. + void swapFrame() override; + QSGTexture *texture(QQuickWindow *win, uint32_t) override; + bool textureIsFlipped() override; + float devicePixelRatio() override; + QSize size() override; + bool requiresAlphaChannel() override; private: mutable QMutex m_mutex; - scoped_refptr<DisplayFrameSink> m_sink; float m_devicePixelRatio = 1.0; + bool m_requiresAlpha; scoped_refptr<base::SingleThreadTaskRunner> m_taskRunner; - base::OnceClosure m_swapCompletionCallback; + SwapBuffersCallback m_swapCompletionCallback; QImage m_image; float m_imageDevicePixelRatio = 1.0; }; -DisplaySoftwareOutputSurface::Device::~Device() -{ - if (m_sink) - m_sink->disconnect(this); -} - -void DisplaySoftwareOutputSurface::Device::bind(viz::FrameSinkId frameSinkId) +DisplaySoftwareOutputSurface::Device::Device(bool requiresAlpha) + : Compositor(Type::Software) + , m_requiresAlpha(requiresAlpha) { - m_sink = DisplayFrameSink::findOrCreate(frameSinkId); - m_sink->connect(this); } void DisplaySoftwareOutputSurface::Device::Resize(const gfx::Size &sizeInPixels, float devicePixelRatio) @@ -96,15 +56,19 @@ void DisplaySoftwareOutputSurface::Device::Resize(const gfx::Size &sizeInPixels, return; m_devicePixelRatio = devicePixelRatio; viewport_pixel_size_ = sizeInPixels; - surface_ = SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(sizeInPixels.width(), sizeInPixels.height())); + surface_ = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(sizeInPixels.width(), sizeInPixels.height())); } -void DisplaySoftwareOutputSurface::Device::OnSwapBuffers(base::OnceClosure swapCompletionCallback) +void DisplaySoftwareOutputSurface::Device::OnSwapBuffers(SwapBuffersCallback swap_ack_callback, gfx::FrameData data) { - QMutexLocker locker(&m_mutex); - m_taskRunner = base::ThreadTaskRunnerHandle::Get(); - m_swapCompletionCallback = std::move(swapCompletionCallback); - m_sink->scheduleUpdate(); + { // MEMO don't hold a lock together with an 'observer', as the call from Qt's scene graph may come at the same time + QMutexLocker locker(&m_mutex); + m_taskRunner = base::SingleThreadTaskRunner::GetCurrentDefault(); + m_swapCompletionCallback = std::move(swap_ack_callback); + } + + if (auto obs = observer()) + obs->readyToSwap(); } inline QImage::Format imageFormat(SkColorType colorType) @@ -120,54 +84,68 @@ inline QImage::Format imageFormat(SkColorType colorType) } } -QSGNode *DisplaySoftwareOutputSurface::Device::updatePaintNode( - QSGNode *oldNode, RenderWidgetHostViewQtDelegate *delegate) +void DisplaySoftwareOutputSurface::Device::swapFrame() { QMutexLocker locker(&m_mutex); - // Delete old node to make sure refcount of m_image is at most 1. - delete oldNode; - QSGImageNode *node = delegate->createImageNode(); - - if (m_swapCompletionCallback) { - SkPixmap skPixmap; - surface_->peekPixels(&skPixmap); - QImage image(reinterpret_cast<const uchar *>(skPixmap.addr()), - viewport_pixel_size_.width(), viewport_pixel_size_.height(), - skPixmap.rowBytes(), imageFormat(skPixmap.colorType())); - if (m_image.size() == image.size()) { - QRect damageRect = toQt(damage_rect_); - QPainter(&m_image).drawImage(damageRect, image, damageRect); - } else { - m_image = image; - m_image.detach(); - } - m_imageDevicePixelRatio = m_devicePixelRatio; - m_taskRunner->PostTask(FROM_HERE, std::move(m_swapCompletionCallback)); - m_taskRunner.reset(); + if (!m_swapCompletionCallback) + return; + + SkPixmap skPixmap; + surface_->peekPixels(&skPixmap); + QImage image(reinterpret_cast<const uchar *>(skPixmap.addr()), viewport_pixel_size_.width(), + viewport_pixel_size_.height(), skPixmap.rowBytes(), + imageFormat(skPixmap.colorType())); + if (m_image.size() == image.size()) { + QRect damageRect = toQt(damage_rect_); + QPainter painter(&m_image); + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.drawImage(damageRect, image, damageRect); + } else { + m_image = image; + m_image.detach(); } + m_imageDevicePixelRatio = m_devicePixelRatio; + m_taskRunner->PostTask( + FROM_HERE, base::BindOnce(std::move(m_swapCompletionCallback), toGfx(m_image.size()))); + m_taskRunner.reset(); +} + +QSGTexture *DisplaySoftwareOutputSurface::Device::texture(QQuickWindow *win, uint32_t) +{ + return win->createTextureFromImage(m_image); +} - QSizeF sizeInDips = QSizeF(m_image.size()) / m_imageDevicePixelRatio; - node->setRect(QRectF(QPointF(0, 0), sizeInDips)); - node->setOwnsTexture(true); - node->setTexture(delegate->createTextureFromImage(m_image)); +bool DisplaySoftwareOutputSurface::Device::textureIsFlipped() +{ + return false; +} - return node; +float DisplaySoftwareOutputSurface::Device::devicePixelRatio() +{ + return m_imageDevicePixelRatio; +} + +QSize DisplaySoftwareOutputSurface::Device::size() +{ + return m_image.size(); +} + +bool DisplaySoftwareOutputSurface::Device::requiresAlphaChannel() +{ + return m_requiresAlpha; } -DisplaySoftwareOutputSurface::DisplaySoftwareOutputSurface(viz::UpdateVSyncParametersCallback callback) - : SoftwareOutputSurface(std::make_unique<Device>(), std::move(callback)) +DisplaySoftwareOutputSurface::DisplaySoftwareOutputSurface(bool requiresAlpha) + : SoftwareOutputSurface(std::make_unique<Device>(requiresAlpha)) {} DisplaySoftwareOutputSurface::~DisplaySoftwareOutputSurface() {} // Called from viz::Display::Initialize. -void DisplaySoftwareOutputSurface::BindToClient(viz::OutputSurfaceClient *client) +void DisplaySoftwareOutputSurface::SetFrameSinkId(const viz::FrameSinkId &id) { - auto display = static_cast<viz::Display *>(client); - auto device = static_cast<Device *>(software_device()); - device->bind(display->frame_sink_id()); - SoftwareOutputSurface::BindToClient(client); + static_cast<Device *>(software_device())->bind(id); } } // namespace QtWebEngineCore diff --git a/src/core/compositor/display_software_output_surface.h b/src/core/compositor/display_software_output_surface.h index 6707c74dc..d23664d56 100644 --- a/src/core/compositor/display_software_output_surface.h +++ b/src/core/compositor/display_software_output_surface.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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) 2019 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 #ifndef DISPLAY_SOFTWARE_OUTPUT_SURFACE_H #define DISPLAY_SOFTWARE_OUTPUT_SURFACE_H @@ -47,11 +11,11 @@ namespace QtWebEngineCore { class DisplaySoftwareOutputSurface final : public viz::SoftwareOutputSurface { public: - DisplaySoftwareOutputSurface(viz::UpdateVSyncParametersCallback callback); + DisplaySoftwareOutputSurface(bool requiresAlpha); ~DisplaySoftwareOutputSurface() override; - // Overridden from viz::SoftwareOutputSurface. - void BindToClient(viz::OutputSurfaceClient *client) override; + // Overridden from viz::OutputSurface. + void SetFrameSinkId(const viz::FrameSinkId &id) override; private: class Device; diff --git a/src/core/compositor/native_skia_output_device.cpp b/src/core/compositor/native_skia_output_device.cpp new file mode 100644 index 000000000..708692df7 --- /dev/null +++ b/src/core/compositor/native_skia_output_device.cpp @@ -0,0 +1,422 @@ +// Copyright (C) 2023 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 "native_skia_output_device.h" + +#include "type_conversion.h" + +#include "components/viz/common/resources/shared_image_format.h" +#include "components/viz/common/resources/shared_image_format_utils.h" +#include "components/viz/service/display_embedder/skia_output_surface_dependency.h" +#include "gpu/command_buffer/common/mailbox.h" +#include "gpu/command_buffer/common/shared_image_usage.h" +#include "gpu/command_buffer/service/shared_image/shared_image_factory.h" +#include "gpu/command_buffer/service/shared_image/shared_image_representation.h" +#include "gpu/command_buffer/service/skia_utils.h" +#include "third_party/skia/include/gpu/GrDirectContext.h" +#include "third_party/skia/include/core/SkSurfaceProps.h" +#include "ui/gfx/native_pixmap.h" +#include "ui/gfx/gpu_fence.h" +#include "ui/gl/gl_fence.h" + +#if defined(USE_OZONE) +#include "ui/ozone/public/ozone_platform.h" +#endif + +namespace QtWebEngineCore { + +namespace { + +// Helper function for moving a GpuFence from a fence handle to a unique_ptr. +std::unique_ptr<gfx::GpuFence> TakeGpuFence(gfx::GpuFenceHandle fence) +{ + return fence.is_null() ? nullptr : std::make_unique<gfx::GpuFence>(std::move(fence)); +} + +} // namespace + +NativeSkiaOutputDevice::NativeSkiaOutputDevice( + scoped_refptr<gpu::SharedContextState> contextState, bool requiresAlpha, + gpu::MemoryTracker *memoryTracker, viz::SkiaOutputSurfaceDependency *dependency, + gpu::SharedImageFactory *shared_image_factory, + gpu::SharedImageRepresentationFactory *shared_image_representation_factory, + DidSwapBufferCompleteCallback didSwapBufferCompleteCallback) + : SkiaOutputDevice(contextState->gr_context(), contextState->graphite_context(), memoryTracker, + didSwapBufferCompleteCallback) + , Compositor(Type::Native) + , m_contextState(contextState) + , m_requiresAlpha(requiresAlpha) + , m_factory(shared_image_factory) + , m_representationFactory(shared_image_representation_factory) + , m_deps(dependency) +{ + capabilities_.uses_default_gl_framebuffer = false; + capabilities_.supports_surfaceless = true; + capabilities_.output_surface_origin = gfx::SurfaceOrigin::kTopLeft; + capabilities_.preserve_buffer_content = true; + capabilities_.only_invalidates_damage_rect = false; + +#if defined(USE_OZONE) + m_isNativeBufferSupported = ui::OzonePlatform::GetInstance() + ->GetPlatformRuntimeProperties() + .supports_native_pixmaps; +#endif +} + +NativeSkiaOutputDevice::~NativeSkiaOutputDevice() +{ +} + +void NativeSkiaOutputDevice::SetFrameSinkId(const viz::FrameSinkId &id) +{ + bind(id); +} + +bool NativeSkiaOutputDevice::Reshape(const SkImageInfo &image_info, + const gfx::ColorSpace &colorSpace, + int sample_count, + float device_scale_factor, + gfx::OverlayTransform transform) +{ + m_shape = Shape{image_info, device_scale_factor, colorSpace, sample_count}; + DCHECK_EQ(transform, gfx::OVERLAY_TRANSFORM_NONE); + return true; +} + +void NativeSkiaOutputDevice::Present(const absl::optional<gfx::Rect> &update_rect, + BufferPresentedCallback feedback, + viz::OutputSurfaceFrame frame) +{ + DCHECK(m_backBuffer); + + StartSwapBuffers(std::move(feedback)); + m_frame = std::move(frame); + { + QMutexLocker locker(&m_mutex); + m_backBuffer->createFence(); + m_gpuTaskRunner = base::SingleThreadTaskRunner::GetCurrentDefault(); + std::swap(m_middleBuffer, m_backBuffer); + m_readyToUpdate = true; + } + + if (auto obs = observer()) + obs->readyToSwap(); +} + +void NativeSkiaOutputDevice::EnsureBackbuffer() +{ +} + +void NativeSkiaOutputDevice::DiscardBackbuffer() +{ +} + +SkSurface *NativeSkiaOutputDevice::BeginPaint(std::vector<GrBackendSemaphore> *end_semaphores) +{ + { + QMutexLocker locker(&m_mutex); + if (!m_backBuffer || m_backBuffer->shape() != m_shape) { + m_backBuffer = std::make_unique<Buffer>(this); + if (!m_backBuffer->initialize()) + return nullptr; + } + } + auto surface = m_backBuffer->beginWriteSkia(); + *end_semaphores = m_backBuffer->takeEndWriteSkiaSemaphores(); + return surface; +} + +void NativeSkiaOutputDevice::EndPaint() +{ + m_backBuffer->endWriteSkia(true); +} + +void NativeSkiaOutputDevice::swapFrame() +{ + QMutexLocker locker(&m_mutex); + if (m_readyToUpdate) { + std::swap(m_frontBuffer, m_middleBuffer); + m_gpuTaskRunner->PostTask(FROM_HERE, + base::BindOnce(&NativeSkiaOutputDevice::SwapBuffersFinished, + base::Unretained(this))); + m_readyToUpdate = false; + if (m_frontBuffer) { + m_readyWithTexture = true; + m_frontBuffer->beginPresent(); + } + if (m_middleBuffer) + m_middleBuffer->freeTexture(); + m_gpuTaskRunner.reset(); + } +} + +void NativeSkiaOutputDevice::waitForTexture() +{ + if (m_readyWithTexture) + m_frontBuffer->consumeFence(); +} + +void NativeSkiaOutputDevice::releaseTexture() +{ + if (m_readyWithTexture) { + m_frontBuffer->endPresent(); + m_readyWithTexture = false; + } +} + +void NativeSkiaOutputDevice::releaseResources() +{ + if (m_frontBuffer) + m_frontBuffer->freeTexture(); +} + +bool NativeSkiaOutputDevice::textureIsFlipped() +{ + return false; +} + +QSize NativeSkiaOutputDevice::size() +{ + return m_frontBuffer ? toQt(m_frontBuffer->shape().imageInfo.dimensions()) : QSize(); +} + +bool NativeSkiaOutputDevice::requiresAlphaChannel() +{ + return m_requiresAlpha; +} + +float NativeSkiaOutputDevice::devicePixelRatio() +{ + return m_frontBuffer ? m_frontBuffer->shape().devicePixelRatio : 1; +} + +void NativeSkiaOutputDevice::SwapBuffersFinished() +{ + { + QMutexLocker locker(&m_mutex); + std::swap(m_backBuffer, m_middleBuffer); + } + + FinishSwapBuffers(gfx::SwapCompletionResult(gfx::SwapResult::SWAP_ACK), + gfx::Size(m_shape.imageInfo.width(), m_shape.imageInfo.height()), + std::move(m_frame)); +} + +NativeSkiaOutputDevice::Buffer::Buffer(NativeSkiaOutputDevice *parent) + : m_parent(parent), m_shape(m_parent->m_shape) +{ +} + +NativeSkiaOutputDevice::Buffer::~Buffer() +{ + if (m_scopedSkiaWriteAccess) + endWriteSkia(false); + + if (!m_mailbox.IsZero()) + m_parent->m_factory->DestroySharedImage(m_mailbox); +} + +// The following Buffer methods are based on +// components/viz/service/display_embedder/output_presenter.cc: Copyright 2020 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +bool NativeSkiaOutputDevice::Buffer::initialize() +{ + static const uint32_t kDefaultSharedImageUsage = gpu::SHARED_IMAGE_USAGE_SCANOUT + | gpu::SHARED_IMAGE_USAGE_DISPLAY_READ | gpu::SHARED_IMAGE_USAGE_DISPLAY_WRITE + | gpu::SHARED_IMAGE_USAGE_GLES2_FRAMEBUFFER_HINT; + auto mailbox = gpu::Mailbox::GenerateForSharedImage(); + + SkColorType skColorType = m_shape.imageInfo.colorType(); + if (!m_parent->m_factory->CreateSharedImage( + mailbox, viz::SkColorTypeToSinglePlaneSharedImageFormat(skColorType), + { m_shape.imageInfo.width(), m_shape.imageInfo.height() }, m_shape.colorSpace, + kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, m_parent->m_deps->GetSurfaceHandle(), + kDefaultSharedImageUsage, "QWE_SharedImageBuffer")) { + LOG(ERROR) << "CreateSharedImage failed."; + return false; + } + m_mailbox = mailbox; + + m_skiaRepresentation = + m_parent->m_representationFactory->ProduceSkia(m_mailbox, m_parent->m_contextState); + if (!m_skiaRepresentation) { + LOG(ERROR) << "ProduceSkia() failed."; + return false; + } + + if (m_parent->m_isNativeBufferSupported) { + m_overlayRepresentation = m_parent->m_representationFactory->ProduceOverlay(m_mailbox); + if (!m_overlayRepresentation) { + LOG(ERROR) << "ProduceOverlay() failed"; + return false; + } + } + + return true; +} + +SkSurface *NativeSkiaOutputDevice::Buffer::beginWriteSkia() +{ + DCHECK(!m_scopedSkiaWriteAccess); + DCHECK(!m_presentCount); + DCHECK(m_endSemaphores.empty()); + + std::vector<GrBackendSemaphore> beginSemaphores; + SkSurfaceProps surface_props{ 0, kUnknown_SkPixelGeometry }; + + // Buffer queue is internal to GPU proc and handles texture initialization, + // so allow uncleared access. + m_scopedSkiaWriteAccess = m_skiaRepresentation->BeginScopedWriteAccess( + m_shape.sampleCount, surface_props, &beginSemaphores, &m_endSemaphores, + gpu::SharedImageRepresentation::AllowUnclearedAccess::kYes); + DCHECK(m_scopedSkiaWriteAccess); + if (!beginSemaphores.empty()) { + m_scopedSkiaWriteAccess->surface()->wait(beginSemaphores.size(), beginSemaphores.data(), + /*deleteSemaphoresAfterWait=*/false); + } + return m_scopedSkiaWriteAccess->surface(); +} + +void NativeSkiaOutputDevice::Buffer::endWriteSkia(bool force_flush) +{ + // The Flush now takes place in finishPaintCurrentBuffer on the CPU side. + // check if end_semaphores is not empty then flush here + DCHECK(m_scopedSkiaWriteAccess); + if (!m_endSemaphores.empty() || force_flush) { + GrFlushInfo flush_info = {}; + flush_info.fNumSemaphores = m_endSemaphores.size(); + flush_info.fSignalSemaphores = m_endSemaphores.data(); + auto *direct_context = + m_scopedSkiaWriteAccess->surface()->recordingContext()->asDirectContext(); + DCHECK(direct_context); + direct_context->flush(m_scopedSkiaWriteAccess->surface(), {}); + m_scopedSkiaWriteAccess->ApplyBackendSurfaceEndState(); + direct_context->flush(m_scopedSkiaWriteAccess->surface(), flush_info, nullptr); + direct_context->submit(); + } + m_scopedSkiaWriteAccess.reset(); + m_endSemaphores.clear(); + + // SkiaRenderer always draws the full frame. + m_skiaRepresentation->SetCleared(); +} + +std::vector<GrBackendSemaphore> NativeSkiaOutputDevice::Buffer::takeEndWriteSkiaSemaphores() +{ + return std::exchange(m_endSemaphores, {}); +} + +void NativeSkiaOutputDevice::Buffer::createSkImageOnGPUThread() +{ + if (!m_scopedSkiaReadAccess) { + m_skImageMutex.unlock(); + return; + } + + m_cachedSkImage = m_scopedSkiaReadAccess->CreateSkImage(m_parent->m_contextState.get()); + m_skImageMutex.unlock(); + if (!m_cachedSkImage) + qWarning("SKIA: Failed to create SkImage."); +} + +void NativeSkiaOutputDevice::Buffer::beginPresent() +{ + if (++m_presentCount != 1) { + DCHECK(m_scopedOverlayReadAccess || m_scopedSkiaReadAccess); + return; + } + + DCHECK(!m_scopedSkiaWriteAccess); + DCHECK(!m_scopedOverlayReadAccess && !m_scopedSkiaReadAccess); + + if (m_overlayRepresentation) { + m_scopedOverlayReadAccess = m_overlayRepresentation->BeginScopedReadAccess(); + DCHECK(m_scopedOverlayReadAccess); + m_acquireFence = TakeGpuFence(m_scopedOverlayReadAccess->TakeAcquireFence()); + } else { + DCHECK(m_skiaRepresentation); + std::vector<GrBackendSemaphore> beginSemaphores; + m_scopedSkiaReadAccess = + m_skiaRepresentation->BeginScopedReadAccess(&beginSemaphores, nullptr); + DCHECK(m_scopedSkiaReadAccess); + if (!beginSemaphores.empty()) + qWarning("SKIA: Unexpected semaphores while reading texture, wait is not implemented."); + + m_skImageMutex.tryLock(); + m_parent->m_gpuTaskRunner->PostTask(FROM_HERE, + base::BindOnce(&NativeSkiaOutputDevice::Buffer::createSkImageOnGPUThread, + base::Unretained(this))); + } +} + +void NativeSkiaOutputDevice::Buffer::endPresent() +{ + if (!m_presentCount) + return; + DCHECK(m_scopedOverlayReadAccess || m_scopedSkiaReadAccess); + if (--m_presentCount) + return; + + if (m_scopedOverlayReadAccess) { + DCHECK(!m_scopedSkiaReadAccess); + m_scopedOverlayReadAccess.reset(); + } else if (m_scopedSkiaReadAccess) { + DCHECK(!m_scopedOverlayReadAccess); + QMutexLocker locker(&m_skImageMutex); + m_scopedSkiaReadAccess.reset(); + } +} + +void NativeSkiaOutputDevice::Buffer::freeTexture() +{ + if (textureCleanupCallback) { + textureCleanupCallback(); + textureCleanupCallback = nullptr; + } +} + +void NativeSkiaOutputDevice::Buffer::createFence() +{ + // For some reason we still need to create this, but we do not need to wait on it. + if (m_parent->m_contextState->gr_context_type() == gpu::GrContextType::kGL) + m_fence = gl::GLFence::Create(); +} + +void NativeSkiaOutputDevice::Buffer::consumeFence() +{ + if (m_acquireFence) { + m_acquireFence->Wait(); + m_acquireFence.reset(); + } +} + +sk_sp<SkImage> NativeSkiaOutputDevice::Buffer::skImage() +{ + QMutexLocker locker(&m_skImageMutex); + return m_cachedSkImage; +} +#if defined(USE_OZONE) +scoped_refptr<gfx::NativePixmap> NativeSkiaOutputDevice::Buffer::nativePixmap() +{ + DCHECK(m_presentCount); + if (!m_scopedOverlayReadAccess) + return nullptr; + + return m_scopedOverlayReadAccess->GetNativePixmap(); +} +#elif defined(Q_OS_WIN) +absl::optional<gl::DCLayerOverlayImage> NativeSkiaOutputDevice::Buffer::overlayImage() const +{ + DCHECK(m_presentCount); + return m_scopedOverlayReadAccess->GetDCLayerOverlayImage(); +} +#elif defined(Q_OS_MACOS) +gfx::ScopedIOSurface NativeSkiaOutputDevice::Buffer::ioSurface() const +{ + DCHECK(m_presentCount); + return m_scopedOverlayReadAccess->GetIOSurface(); +} +#endif + +} // namespace QtWebEngineCore diff --git a/src/core/compositor/native_skia_output_device.h b/src/core/compositor/native_skia_output_device.h new file mode 100644 index 000000000..2c35cef77 --- /dev/null +++ b/src/core/compositor/native_skia_output_device.h @@ -0,0 +1,183 @@ +// Copyright (C) 2023 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 + +#ifndef NATIVE_SKIA_OUTPUT_DEVICE_H +#define NATIVE_SKIA_OUTPUT_DEVICE_H + +#include "compositor.h" + +#include "base/task/single_thread_task_runner.h" +#include "components/viz/service/display_embedder/skia_output_device.h" +#include "gpu/command_buffer/service/shared_context_state.h" +#include "gpu/command_buffer/service/shared_image/shared_image_representation.h" +#include "gpu/config/gpu_preferences.h" + +#include <QMutex> + +#if defined(Q_OS_WIN) +#include "ui/gl/dc_layer_overlay_image.h" +#endif + +#if defined(Q_OS_MACOS) +#include "ui/gfx/mac/io_surface.h" +#endif + +QT_BEGIN_NAMESPACE +class QQuickWindow; +QT_END_NAMESPACE + +namespace gl { +class GLFence; +} + +namespace gfx { +class GpuFence; +class NativePixmap; +} + +namespace gpu { +class SharedImageFactory; +class SharedImageRepresentationFactory; +} + +namespace viz { +class SkiaOutputSurfaceDependency; +} + +namespace QtWebEngineCore { + +class NativeSkiaOutputDevice : public viz::SkiaOutputDevice, public Compositor +{ +public: + NativeSkiaOutputDevice(scoped_refptr<gpu::SharedContextState> contextState, + bool requiresAlpha, + gpu::MemoryTracker *memoryTracker, + viz::SkiaOutputSurfaceDependency *dependency, + gpu::SharedImageFactory *shared_image_factory, + gpu::SharedImageRepresentationFactory *shared_image_representation_factory, + DidSwapBufferCompleteCallback didSwapBufferCompleteCallback); + ~NativeSkiaOutputDevice() override; + + // Overridden from SkiaOutputDevice. + void SetFrameSinkId(const viz::FrameSinkId &frame_sink_id) override; + bool Reshape(const SkImageInfo &image_info, + const gfx::ColorSpace &color_space, + int sample_count, + float device_scale_factor, + gfx::OverlayTransform transform) override; + void Present(const absl::optional<gfx::Rect>& update_rect, + BufferPresentedCallback feedback, + viz::OutputSurfaceFrame frame) override; + void EnsureBackbuffer() override; + void DiscardBackbuffer() override; + SkSurface *BeginPaint(std::vector<GrBackendSemaphore> *semaphores) override; + void EndPaint() override; + + // Overridden from Compositor. + void swapFrame() override; + void waitForTexture() override; + void releaseTexture() override; + void releaseResources() override; + bool textureIsFlipped() override; + QSize size() override; + bool requiresAlphaChannel() override; + float devicePixelRatio() override; + +protected: + struct Shape + { + SkImageInfo imageInfo; + float devicePixelRatio; + gfx::ColorSpace colorSpace; + int sampleCount; + + bool operator==(const Shape &that) const + { + return (imageInfo == that.imageInfo && + devicePixelRatio == that.devicePixelRatio && + colorSpace == that.colorSpace && + sampleCount == that.sampleCount); + } + bool operator!=(const Shape &that) const { return !(*this == that); } + }; + + class Buffer + { + public: + Buffer(NativeSkiaOutputDevice *parent); + ~Buffer(); + + bool initialize(); + SkSurface *beginWriteSkia(); + void endWriteSkia(bool force_flush); + std::vector<GrBackendSemaphore> takeEndWriteSkiaSemaphores(); + void beginPresent(); + void endPresent(); + void freeTexture(); + void createFence(); + void consumeFence(); + + sk_sp<SkImage> skImage(); +#if defined(USE_OZONE) + scoped_refptr<gfx::NativePixmap> nativePixmap(); +#elif defined(Q_OS_WIN) + absl::optional<gl::DCLayerOverlayImage> overlayImage() const; +#elif defined(Q_OS_MACOS) + gfx::ScopedIOSurface ioSurface() const; +#endif + + const Shape &shape() const { return m_shape; } + viz::SharedImageFormat sharedImageFormat() const { return m_skiaRepresentation->format(); } + + std::function<void()> textureCleanupCallback; + + private: + void createSkImageOnGPUThread(); + + NativeSkiaOutputDevice *m_parent; + Shape m_shape; + uint64_t m_estimatedSize = 0; // FIXME: estimate size + std::unique_ptr<gfx::GpuFence> m_acquireFence; + std::unique_ptr<gl::GLFence> m_fence; + gpu::Mailbox m_mailbox; + std::unique_ptr<gpu::SkiaImageRepresentation> m_skiaRepresentation; + std::unique_ptr<gpu::SkiaImageRepresentation::ScopedWriteAccess> m_scopedSkiaWriteAccess; + std::unique_ptr<gpu::SkiaImageRepresentation::ScopedReadAccess> m_scopedSkiaReadAccess; + std::unique_ptr<gpu::OverlayImageRepresentation> m_overlayRepresentation; + std::unique_ptr<gpu::OverlayImageRepresentation::ScopedReadAccess> + m_scopedOverlayReadAccess; + std::vector<GrBackendSemaphore> m_endSemaphores; + int m_presentCount = 0; + + mutable QMutex m_skImageMutex; + sk_sp<SkImage> m_cachedSkImage; + }; + +protected: + scoped_refptr<gpu::SharedContextState> m_contextState; + std::unique_ptr<Buffer> m_frontBuffer; + bool m_readyWithTexture = false; + bool m_isNativeBufferSupported = true; + +private: + friend class NativeSkiaOutputDevice::Buffer; + + void SwapBuffersFinished(); + + mutable QMutex m_mutex; + Shape m_shape; + std::unique_ptr<Buffer> m_middleBuffer; + std::unique_ptr<Buffer> m_backBuffer; + viz::OutputSurfaceFrame m_frame; + bool m_readyToUpdate = false; + bool m_requiresAlpha; + scoped_refptr<base::SingleThreadTaskRunner> m_gpuTaskRunner; + + const raw_ptr<gpu::SharedImageFactory> m_factory; + const raw_ptr<gpu::SharedImageRepresentationFactory> m_representationFactory; + const raw_ptr<viz::SkiaOutputSurfaceDependency> m_deps; +}; + +} // namespace QtWebEngineCore + +#endif // !NATIVE_SKIA_OUTPUT_DEVICE_H diff --git a/src/core/compositor/native_skia_output_device_direct3d11.cpp b/src/core/compositor/native_skia_output_device_direct3d11.cpp new file mode 100644 index 000000000..2f1ed5f61 --- /dev/null +++ b/src/core/compositor/native_skia_output_device_direct3d11.cpp @@ -0,0 +1,89 @@ +// Copyright (C) 2024 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 "native_skia_output_device_direct3d11.h" + +#include <QtCore/private/qsystemerror_p.h> +#include <QtQuick/qquickwindow.h> +#include <QtQuick/qsgtexture.h> + +#include <d3d11_1.h> + +namespace QtWebEngineCore { + +NativeSkiaOutputDeviceDirect3D11::NativeSkiaOutputDeviceDirect3D11( + scoped_refptr<gpu::SharedContextState> contextState, bool requiresAlpha, + gpu::MemoryTracker *memoryTracker, viz::SkiaOutputSurfaceDependency *dependency, + gpu::SharedImageFactory *shared_image_factory, + gpu::SharedImageRepresentationFactory *shared_image_representation_factory, + DidSwapBufferCompleteCallback didSwapBufferCompleteCallback) + : NativeSkiaOutputDevice(contextState, requiresAlpha, memoryTracker, dependency, + shared_image_factory, shared_image_representation_factory, + didSwapBufferCompleteCallback) +{ + SkColorType skColorType = kRGBA_8888_SkColorType; + capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::RGBA_8888)] = skColorType; + capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::RGBX_8888)] = skColorType; + capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::BGRA_8888)] = skColorType; + capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::BGRX_8888)] = skColorType; +} + +NativeSkiaOutputDeviceDirect3D11::~NativeSkiaOutputDeviceDirect3D11() { } + +QSGTexture *NativeSkiaOutputDeviceDirect3D11::texture(QQuickWindow *win, uint32_t textureOptions) +{ + if (!m_frontBuffer || !m_readyWithTexture) + return nullptr; + + absl::optional<gl::DCLayerOverlayImage> overlayImage = m_frontBuffer->overlayImage(); + if (!overlayImage) { + qWarning("No overlay image."); + return nullptr; + } + + QSGRendererInterface *ri = win->rendererInterface(); + + HRESULT status = S_OK; + HANDLE sharedHandle = nullptr; + IDXGIResource1 *resource = nullptr; + if (!overlayImage->nv12_texture()) { + qWarning("No D3D texture."); + return nullptr; + } + status = overlayImage->nv12_texture()->QueryInterface(__uuidof(IDXGIResource1), + (void **)&resource); + Q_ASSERT(status == S_OK); + status = resource->CreateSharedHandle(NULL, DXGI_SHARED_RESOURCE_READ, NULL, &sharedHandle); + Q_ASSERT(status == S_OK); + Q_ASSERT(sharedHandle); + resource->Release(); + + // Pass texture between two D3D devices: + ID3D11Device1 *device = static_cast<ID3D11Device1 *>( + ri->getResource(win, QSGRendererInterface::DeviceResource)); + + ID3D11Texture2D *qtTexture; + status = device->OpenSharedResource1(sharedHandle, __uuidof(ID3D11Texture2D), + (void **)&qtTexture); + if (status != S_OK) { + qWarning("Failed to share D3D11 texture (%s). This will result in failed rendering. Report " + "the bug, and try restarting with QTWEBENGINE_CHROMIUM_FLAGS=--disble-gpu", + qPrintable(QSystemError::windowsComString(status))); + ::CloseHandle(sharedHandle); + return nullptr; + } + + Q_ASSERT(qtTexture); + QQuickWindow::CreateTextureOptions texOpts(textureOptions); + QSGTexture *texture = + QNativeInterface::QSGD3D11Texture::fromNative(qtTexture, win, size(), texOpts); + + m_frontBuffer->textureCleanupCallback = [qtTexture, sharedHandle]() { + qtTexture->Release(); + ::CloseHandle(sharedHandle); + }; + + return texture; +} + +} // namespace QtWebEngineCore diff --git a/src/core/compositor/native_skia_output_device_direct3d11.h b/src/core/compositor/native_skia_output_device_direct3d11.h new file mode 100644 index 000000000..33cf1bcd6 --- /dev/null +++ b/src/core/compositor/native_skia_output_device_direct3d11.h @@ -0,0 +1,28 @@ +// Copyright (C) 2024 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 + +#ifndef NATIVE_SKIA_OUTPUT_DEVICE_DIRECT3D11_H +#define NATIVE_SKIA_OUTPUT_DEVICE_DIRECT3D11_H + +#include "native_skia_output_device.h" + +namespace QtWebEngineCore { + +class NativeSkiaOutputDeviceDirect3D11 final : public NativeSkiaOutputDevice +{ +public: + NativeSkiaOutputDeviceDirect3D11( + scoped_refptr<gpu::SharedContextState> contextState, bool requiresAlpha, + gpu::MemoryTracker *memoryTracker, viz::SkiaOutputSurfaceDependency *dependency, + gpu::SharedImageFactory *shared_image_factory, + gpu::SharedImageRepresentationFactory *shared_image_representation_factory, + DidSwapBufferCompleteCallback didSwapBufferCompleteCallback); + ~NativeSkiaOutputDeviceDirect3D11() override; + + // Overridden from Compositor: + QSGTexture *texture(QQuickWindow *win, uint32_t textureOptions) override; +}; + +} // namespace QtWebEngineCore + +#endif // NATIVE_SKIA_OUTPUT_DEVICE_DIRECT3D11_H diff --git a/src/core/compositor/native_skia_output_device_mac.mm b/src/core/compositor/native_skia_output_device_mac.mm new file mode 100644 index 000000000..bf21ef8d7 --- /dev/null +++ b/src/core/compositor/native_skia_output_device_mac.mm @@ -0,0 +1,97 @@ +// Copyright (C) 2023 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 + +// This is a workaround to be able to include Qt headers without +// "redefinition of 'NSString' as different kind of symbol" errors. +// TODO: Remove this when namespace ambiguity issues are fixed properly, +// see get_forward_declaration_macro() in cmake/Functions.cmake +#undef Q_FORWARD_DECLARE_OBJC_CLASS + +#import <AppKit/AppKit.h> +#import <IOSurface/IOSurface.h> +#import <Metal/Metal.h> + +#include <QtGui/qtguiglobal.h> +#include <QtQuick/qquickwindow.h> +#include <QtQuick/qsgrendererinterface.h> +#include <QtQuick/qsgtexture.h> + +#if QT_CONFIG(opengl) +#include <OpenGL/OpenGL.h> +#include <QtGui/qopenglcontext.h> +#include <QtGui/qopenglextrafunctions.h> +#include <QtOpenGL/qopengltextureblitter.h> +#include <QtOpenGL/qopenglframebufferobject.h> +#endif + +namespace QtWebEngineCore { + +QSGTexture *makeMetalTexture(QQuickWindow *win, IOSurfaceRef ioSurface, uint ioSurfacePlane, + const QSize &size, QQuickWindow::CreateTextureOptions texOpts) +{ + auto desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm + width:size.width() + height:size.height() + mipmapped:false]; + + QSGRendererInterface *ri = win->rendererInterface(); + auto device = (__bridge id<MTLDevice>)(ri->getResource(win, QSGRendererInterface::DeviceResource)); + id<MTLTexture> texture = [device newTextureWithDescriptor:desc + iosurface:ioSurface + plane:ioSurfacePlane]; + return QNativeInterface::QSGMetalTexture::fromNative(texture, win, size, texOpts); +} + +void releaseMetalTexture(void *texture) +{ + [static_cast<id<MTLTexture>>(texture) release]; +} + +#if QT_CONFIG(opengl) +uint32_t makeCGLTexture(QQuickWindow *win, IOSurfaceRef ioSurface, const QSize &size) +{ + const int width = size.width(); + const int height = size.height(); + + auto glContext = QOpenGLContext::currentContext(); + auto glFun = glContext->extraFunctions(); + auto nscontext = glContext->nativeInterface<QNativeInterface::QCocoaGLContext>()->nativeContext(); + CGLContextObj cglContext = [nscontext CGLContextObj]; + + win->beginExternalCommands(); + // Bind the IO surface to a texture + GLuint glTexture; + glFun->glGenTextures(1, &glTexture); + glFun->glBindTexture(GL_TEXTURE_RECTANGLE_ARB, glTexture); + CGLTexImageIOSurface2D(cglContext, GL_TEXTURE_RECTANGLE_ARB, GL_RGBA, width, height, GL_BGRA, + GL_UNSIGNED_INT_8_8_8_8_REV, ioSurface, 0); + glFun->glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + glFun->glViewport(0, 0, width, height); + + // The bound IO surface is a weird dynamic bind, so take a snapshot of it to a normal texture + { + QOpenGLFramebufferObject fbo(width, height, GL_TEXTURE_2D); + auto success = fbo.bind(); + Q_ASSERT(success); + + QOpenGLTextureBlitter blitter; + success = blitter.create(); + Q_ASSERT(success); + glFun->glDisable(GL_BLEND); + glFun->glDisable(GL_SCISSOR_TEST); + blitter.bind(GL_TEXTURE_RECTANGLE_ARB); + blitter.blit(glTexture, {}, QOpenGLTextureBlitter::OriginBottomLeft); + blitter.release(); + blitter.destroy(); + + glFun->glDeleteTextures(1, &glTexture); + glTexture = fbo.takeTexture(); + fbo.release(); + } + win->endExternalCommands(); + + return glTexture; +} +#endif // QT_CONFIG(opengl) + +} // namespace diff --git a/src/core/compositor/native_skia_output_device_metal.cpp b/src/core/compositor/native_skia_output_device_metal.cpp new file mode 100644 index 000000000..a9d6e4fd5 --- /dev/null +++ b/src/core/compositor/native_skia_output_device_metal.cpp @@ -0,0 +1,66 @@ +// Copyright (C) 2024 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 "native_skia_output_device_metal.h" + +#include <QtQuick/qquickwindow.h> +#include <QtQuick/qsgtexture.h> + +namespace QtWebEngineCore { + +NativeSkiaOutputDeviceMetal::NativeSkiaOutputDeviceMetal( + scoped_refptr<gpu::SharedContextState> contextState, bool requiresAlpha, + gpu::MemoryTracker *memoryTracker, viz::SkiaOutputSurfaceDependency *dependency, + gpu::SharedImageFactory *shared_image_factory, + gpu::SharedImageRepresentationFactory *shared_image_representation_factory, + DidSwapBufferCompleteCallback didSwapBufferCompleteCallback) + : NativeSkiaOutputDevice(contextState, requiresAlpha, memoryTracker, dependency, + shared_image_factory, shared_image_representation_factory, + didSwapBufferCompleteCallback) +{ + SkColorType skColorType = kRGBA_8888_SkColorType; + capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::RGBA_8888)] = skColorType; + capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::RGBX_8888)] = skColorType; + capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::BGRA_8888)] = skColorType; + capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::BGRX_8888)] = skColorType; +} + +NativeSkiaOutputDeviceMetal::~NativeSkiaOutputDeviceMetal() { } + +QSGTexture *makeMetalTexture(QQuickWindow *win, IOSurfaceRef ioSurface, uint ioSurfacePlane, + const QSize &size, QQuickWindow::CreateTextureOptions texOpts); +void releaseMetalTexture(void *texture); + +QSGTexture *NativeSkiaOutputDeviceMetal::texture(QQuickWindow *win, uint32_t textureOptions) +{ + if (!m_frontBuffer || !m_readyWithTexture) + return nullptr; + + gfx::ScopedIOSurface ioSurface = m_frontBuffer->ioSurface(); + if (!ioSurface) { + qWarning("No IOSurface."); + return nullptr; + } + + // This is a workaround to not to release metal texture too early. + // In RHI, QMetalTexture wraps MTLTexture. QMetalTexture seems to be only destructed after the + // next MTLTexture is imported. The "old" MTLTexture can be still pontentially used by RHI + // while QMetalTexture is not destructed. Metal Validation Layer also warns about it. + // Delay releasing MTLTexture after the next one is presented. + if (m_currentMetalTexture) { + m_frontBuffer->textureCleanupCallback = [texture = m_currentMetalTexture]() { + releaseMetalTexture(texture); + }; + m_currentMetalTexture = nullptr; + } + + QQuickWindow::CreateTextureOptions texOpts(textureOptions); + QSGTexture *qsgTexture = makeMetalTexture(win, ioSurface.get(), /* plane */ 0, size(), texOpts); + + auto ni = qsgTexture->nativeInterface<QNativeInterface::QSGMetalTexture>(); + m_currentMetalTexture = ni->nativeTexture(); + + return qsgTexture; +} + +} // namespace QtWebEngineCore diff --git a/src/core/compositor/native_skia_output_device_metal.h b/src/core/compositor/native_skia_output_device_metal.h new file mode 100644 index 000000000..8e8d0fab8 --- /dev/null +++ b/src/core/compositor/native_skia_output_device_metal.h @@ -0,0 +1,31 @@ +// Copyright (C) 2024 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 + +#ifndef NATIVE_SKIA_OUTPUT_DEVICE_METAL_H +#define NATIVE_SKIA_OUTPUT_DEVICE_METAL_H + +#include "native_skia_output_device.h" + +namespace QtWebEngineCore { + +class NativeSkiaOutputDeviceMetal final : public NativeSkiaOutputDevice +{ +public: + NativeSkiaOutputDeviceMetal( + scoped_refptr<gpu::SharedContextState> contextState, bool requiresAlpha, + gpu::MemoryTracker *memoryTracker, viz::SkiaOutputSurfaceDependency *dependency, + gpu::SharedImageFactory *shared_image_factory, + gpu::SharedImageRepresentationFactory *shared_image_representation_factory, + DidSwapBufferCompleteCallback didSwapBufferCompleteCallback); + ~NativeSkiaOutputDeviceMetal() override; + + // Overridden from Compositor: + QSGTexture *texture(QQuickWindow *win, uint32_t textureOptions) override; + +private: + void *m_currentMetalTexture = nullptr; +}; + +} // namespace QtWebEngineCore + +#endif // NATIVE_SKIA_OUTPUT_DEVICE_METAL_H diff --git a/src/core/compositor/native_skia_output_device_opengl.cpp b/src/core/compositor/native_skia_output_device_opengl.cpp new file mode 100644 index 000000000..058573b9e --- /dev/null +++ b/src/core/compositor/native_skia_output_device_opengl.cpp @@ -0,0 +1,86 @@ +// Copyright (C) 2024 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 "native_skia_output_device_opengl.h" + +#include <QtGui/qopenglcontext.h> +#include <QtGui/qopenglextrafunctions.h> +#include <QtQuick/qquickwindow.h> +#include <QtQuick/qsgtexture.h> + +namespace QtWebEngineCore { + +NativeSkiaOutputDeviceOpenGL::NativeSkiaOutputDeviceOpenGL( + scoped_refptr<gpu::SharedContextState> contextState, bool requiresAlpha, + gpu::MemoryTracker *memoryTracker, viz::SkiaOutputSurfaceDependency *dependency, + gpu::SharedImageFactory *shared_image_factory, + gpu::SharedImageRepresentationFactory *shared_image_representation_factory, + DidSwapBufferCompleteCallback didSwapBufferCompleteCallback) + : NativeSkiaOutputDevice(contextState, requiresAlpha, memoryTracker, dependency, + shared_image_factory, shared_image_representation_factory, + didSwapBufferCompleteCallback) +{ + SkColorType skColorType = kRGBA_8888_SkColorType; + capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::RGBA_8888)] = skColorType; + capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::RGBX_8888)] = skColorType; + capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::BGRA_8888)] = skColorType; + capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::BGRX_8888)] = skColorType; +} + +NativeSkiaOutputDeviceOpenGL::~NativeSkiaOutputDeviceOpenGL() { } + +#if defined(Q_OS_MACOS) +uint32_t makeCGLTexture(QQuickWindow *win, IOSurfaceRef ioSurface, const QSize &size); +#endif + +QSGTexture *NativeSkiaOutputDeviceOpenGL::texture(QQuickWindow *win, uint32_t textureOptions) +{ + if (!m_frontBuffer || !m_readyWithTexture) + return nullptr; + +#if defined(USE_OZONE) + scoped_refptr<gfx::NativePixmap> nativePixmap = m_frontBuffer->nativePixmap(); + if (!nativePixmap) { + qWarning("No native pixmap."); + return nullptr; + } +#elif defined(Q_OS_WIN) + auto overlayImage = m_frontBuffer->overlayImage(); + if (!overlayImage) { + qWarning("No overlay image."); + return nullptr; + } +#elif defined(Q_OS_MACOS) + gfx::ScopedIOSurface ioSurface = m_frontBuffer->ioSurface(); + if (!ioSurface) { + qWarning("No IOSurface."); + return nullptr; + } +#endif + + QQuickWindow::CreateTextureOptions texOpts(textureOptions); + QSGTexture *texture = nullptr; + +#if defined(USE_OZONE) + // TODO(QTBUG-112281): Add ANGLE support to Linux. + QT_NOT_YET_IMPLEMENTED +#elif defined(Q_OS_WIN) + // TODO: Add WGL support over ANGLE. + QT_NOT_YET_IMPLEMENTED +#elif defined(Q_OS_MACOS) + uint32_t glTexture = makeCGLTexture(win, ioSurface.get(), size()); + texture = QNativeInterface::QSGOpenGLTexture::fromNative(glTexture, win, size(), texOpts); + + m_frontBuffer->textureCleanupCallback = [glTexture]() { + auto *glContext = QOpenGLContext::currentContext(); + if (!glContext) + return; + auto glFun = glContext->functions(); + glFun->glDeleteTextures(1, &glTexture); + }; +#endif + + return texture; +} + +} // namespace QtWebEngineCore diff --git a/src/core/compositor/native_skia_output_device_opengl.h b/src/core/compositor/native_skia_output_device_opengl.h new file mode 100644 index 000000000..233f51df9 --- /dev/null +++ b/src/core/compositor/native_skia_output_device_opengl.h @@ -0,0 +1,28 @@ +// Copyright (C) 2024 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 + +#ifndef NATIVE_SKIA_OUTPUT_DEVICE_OPENGL_H +#define NATIVE_SKIA_OUTPUT_DEVICE_OPENGL_H + +#include "native_skia_output_device.h" + +namespace QtWebEngineCore { + +class NativeSkiaOutputDeviceOpenGL final : public NativeSkiaOutputDevice +{ +public: + NativeSkiaOutputDeviceOpenGL( + scoped_refptr<gpu::SharedContextState> contextState, bool requiresAlpha, + gpu::MemoryTracker *memoryTracker, viz::SkiaOutputSurfaceDependency *dependency, + gpu::SharedImageFactory *shared_image_factory, + gpu::SharedImageRepresentationFactory *shared_image_representation_factory, + DidSwapBufferCompleteCallback didSwapBufferCompleteCallback); + ~NativeSkiaOutputDeviceOpenGL() override; + + // Overridden from Compositor: + QSGTexture *texture(QQuickWindow *win, uint32_t textureOptions) override; +}; + +} // namespace QtWebEngineCore + +#endif // NATIVE_SKIA_OUTPUT_DEVICE_OPENGL_H diff --git a/src/core/compositor/native_skia_output_device_vulkan.cpp b/src/core/compositor/native_skia_output_device_vulkan.cpp new file mode 100644 index 000000000..b775276f6 --- /dev/null +++ b/src/core/compositor/native_skia_output_device_vulkan.cpp @@ -0,0 +1,309 @@ +// Copyright (C) 2024 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 "native_skia_output_device_vulkan.h" + +#include "gpu/command_buffer/service/shared_image/shared_image_format_service_utils.h" +#include "ui/base/ozone_buildflags.h" + +#include <QtGui/qvulkaninstance.h> +#include <QtGui/qvulkanfunctions.h> +#include <QtQuick/qquickwindow.h> +#include <QtQuick/qsgtexture.h> + +#if defined(USE_OZONE) +#if BUILDFLAG(IS_OZONE_X11) +// We need to define USE_VULKAN_XCB for proper vulkan function pointers. +// Avoiding it may lead to call wrong vulkan functions. +// This is originally defined in chromium/gpu/vulkan/BUILD.gn. +#define USE_VULKAN_XCB +#endif // BUILDFLAG(IS_OZONE_X11) +#include "gpu/vulkan/vulkan_function_pointers.h" +#include "components/viz/common/gpu/vulkan_context_provider.h" +#include "gpu/vulkan/vulkan_device_queue.h" +#include "third_party/skia/include/gpu/vk/GrVkTypes.h" +#include "third_party/skia/include/gpu/ganesh/vk/GrVkBackendSurface.h" +#endif // defined(USE_OZONE) + +namespace QtWebEngineCore { + +NativeSkiaOutputDeviceVulkan::NativeSkiaOutputDeviceVulkan( + scoped_refptr<gpu::SharedContextState> contextState, bool requiresAlpha, + gpu::MemoryTracker *memoryTracker, viz::SkiaOutputSurfaceDependency *dependency, + gpu::SharedImageFactory *shared_image_factory, + gpu::SharedImageRepresentationFactory *shared_image_representation_factory, + DidSwapBufferCompleteCallback didSwapBufferCompleteCallback) + : NativeSkiaOutputDevice(contextState, requiresAlpha, memoryTracker, dependency, + shared_image_factory, shared_image_representation_factory, + didSwapBufferCompleteCallback) +{ + SkColorType skColorType = kRGBA_8888_SkColorType; + capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::RGBA_8888)] = skColorType; + capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::RGBX_8888)] = skColorType; + capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::BGRA_8888)] = skColorType; + capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::BGRX_8888)] = skColorType; +} + +NativeSkiaOutputDeviceVulkan::~NativeSkiaOutputDeviceVulkan() { } + +QSGTexture *NativeSkiaOutputDeviceVulkan::texture(QQuickWindow *win, uint32_t textureOptions) +{ + if (!m_frontBuffer || !m_readyWithTexture) + return nullptr; + +#if defined(USE_OZONE) + Q_ASSERT(m_contextState->gr_context_type() == gpu::GrContextType::kVulkan); + + GrVkImageInfo vkImageInfo; + scoped_refptr<gfx::NativePixmap> nativePixmap = m_frontBuffer->nativePixmap(); + if (!nativePixmap) { + if (m_isNativeBufferSupported) { + qWarning("VULKAN: No NativePixmap."); + return nullptr; + } + + sk_sp<SkImage> skImage = m_frontBuffer->skImage(); + if (!skImage) { + qWarning("VULKAN: No SkImage."); + return nullptr; + } + + if (!skImage->isTextureBacked()) { + qWarning("VULKAN: SkImage is not backed by GPU texture."); + return nullptr; + } + + GrBackendTexture backendTexture; + bool success = SkImages::GetBackendTextureFromImage(skImage, &backendTexture, false); + if (!success || !backendTexture.isValid()) { + qWarning("VULKAN: Failed to retrieve backend texture from SkImage."); + return nullptr; + } + + if (backendTexture.backend() != GrBackendApi::kVulkan) { + qWarning("VULKAN: Backend texture is not a Vulkan texture."); + return nullptr; + } + + GrBackendTextures::GetVkImageInfo(backendTexture, &vkImageInfo); + + if (vkImageInfo.fAlloc.fMemory == VK_NULL_HANDLE) { + qWarning("VULKAN: Unable to access Vulkan memory."); + return nullptr; + } + } +#elif defined(Q_OS_WIN) + Q_ASSERT(m_contextState->gr_context_type() == gpu::GrContextType::kGL); + + absl::optional<gl::DCLayerOverlayImage> overlayImage = m_frontBuffer->overlayImage(); + if (!overlayImage) { + qWarning("No overlay image."); + return nullptr; + } +#endif + + QSGRendererInterface *ri = win->rendererInterface(); + VkDevice qtVulkanDevice = + *static_cast<VkDevice *>(ri->getResource(win, QSGRendererInterface::DeviceResource)); + VkPhysicalDevice qtPhysicalDevice = *static_cast<VkPhysicalDevice *>( + ri->getResource(win, QSGRendererInterface::PhysicalDeviceResource)); + QVulkanFunctions *f = win->vulkanInstance()->functions(); + QVulkanDeviceFunctions *df = win->vulkanInstance()->deviceFunctions(qtVulkanDevice); + + VkImageLayout imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + VkPhysicalDeviceProperties deviceProperties; + f->vkGetPhysicalDeviceProperties(qtPhysicalDevice, &deviceProperties); + if (deviceProperties.vendorID == 0x10DE) { + // FIXME: This is a workaround for Nvidia driver. + // The imported image is empty if the initialLayout is not + // VK_IMAGE_LAYOUT_PREINITIALIZED. + imageLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; + } + + VkExternalMemoryImageCreateInfoKHR externalMemoryImageCreateInfo = { + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR + }; +#if defined(USE_OZONE) + VkSubresourceLayout planeLayout = {}; + VkImageDrmFormatModifierExplicitCreateInfoEXT modifierInfo = { + VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT + }; + base::ScopedFD scopedFd; + + if (nativePixmap) { + gfx::NativePixmapHandle nativePixmapHandle = nativePixmap->ExportHandle(); + if (nativePixmapHandle.planes.size() != 1) + qFatal("VULKAN: Multiple planes are not supported."); + + planeLayout.offset = nativePixmapHandle.planes[0].offset; + planeLayout.size = 0; + planeLayout.rowPitch = nativePixmapHandle.planes[0].stride; + planeLayout.arrayPitch = 0; + planeLayout.depthPitch = 0; + + modifierInfo.drmFormatModifier = nativePixmapHandle.modifier; + modifierInfo.drmFormatModifierPlaneCount = 1; + modifierInfo.pPlaneLayouts = &planeLayout; + + externalMemoryImageCreateInfo.pNext = &modifierInfo; + externalMemoryImageCreateInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; + + scopedFd = std::move(nativePixmapHandle.planes[0].fd); + } else { + externalMemoryImageCreateInfo.pNext = nullptr; + externalMemoryImageCreateInfo.handleTypes = + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; + + VkMemoryGetFdInfoKHR exportInfo = { VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR }; + exportInfo.pNext = nullptr; + exportInfo.memory = vkImageInfo.fAlloc.fMemory; + exportInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; + + gpu::VulkanFunctionPointers *vfp = gpu::GetVulkanFunctionPointers(); + gpu::VulkanDeviceQueue *vulkanDeviceQueue = + m_contextState->vk_context_provider()->GetDeviceQueue(); + VkDevice vulkanDevice = vulkanDeviceQueue->GetVulkanDevice(); + + int fd = -1; + if (vfp->vkGetMemoryFdKHR(vulkanDevice, &exportInfo, &fd) != VK_SUCCESS) + qFatal("VULKAN: Unable to extract file descriptor out of external VkImage."); + + scopedFd.reset(fd); + } + + if (!scopedFd.is_valid()) + qFatal("VULKAN: Unable to extract file descriptor."); +#elif defined(Q_OS_WIN) + externalMemoryImageCreateInfo.pNext = nullptr; + externalMemoryImageCreateInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT; + + HRESULT status = S_OK; + HANDLE sharedHandle = nullptr; + IDXGIResource1 *resource = nullptr; + if (!overlayImage->nv12_texture()) { + qWarning("VULKAN: No D3D texture."); + return nullptr; + } + status = overlayImage->nv12_texture()->QueryInterface(__uuidof(IDXGIResource1), + (void **)&resource); + Q_ASSERT(status == S_OK); + status = resource->CreateSharedHandle(NULL, DXGI_SHARED_RESOURCE_READ, NULL, &sharedHandle); + Q_ASSERT(status == S_OK); + resource->Release(); + + if (!sharedHandle) + qFatal("VULKAN: Unable to extract shared handle."); +#endif + + constexpr VkImageUsageFlags kUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT + | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT + | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + + VkImageCreateInfo importedImageCreateInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; + importedImageCreateInfo.pNext = &externalMemoryImageCreateInfo; + importedImageCreateInfo.flags = 0; + importedImageCreateInfo.imageType = VK_IMAGE_TYPE_2D; + importedImageCreateInfo.format = gpu::ToVkFormatSinglePlanar(m_frontBuffer->sharedImageFormat()); + importedImageCreateInfo.extent.width = static_cast<uint32_t>(size().width()); + importedImageCreateInfo.extent.height = static_cast<uint32_t>(size().height()); + importedImageCreateInfo.extent.depth = 1; + importedImageCreateInfo.mipLevels = 1; + importedImageCreateInfo.arrayLayers = 1; + importedImageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + importedImageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + importedImageCreateInfo.usage = kUsage; + importedImageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + importedImageCreateInfo.queueFamilyIndexCount = 0; + importedImageCreateInfo.pQueueFamilyIndices = nullptr; + importedImageCreateInfo.initialLayout = imageLayout; + +#if defined(USE_OZONE) + if (nativePixmap) + importedImageCreateInfo.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT; + else + importedImageCreateInfo.tiling = vkImageInfo.fImageTiling; +#endif + + VkResult result; + VkImage importedImage = VK_NULL_HANDLE; + result = df->vkCreateImage(qtVulkanDevice, &importedImageCreateInfo, nullptr /* pAllocator */, + &importedImage); + if (result != VK_SUCCESS) + qFatal() << "VULKAN: vkCreateImage failed result:" << result; + +#if defined(USE_OZONE) + VkImportMemoryFdInfoKHR importMemoryHandleInfo = { + VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR + }; + importMemoryHandleInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; + importMemoryHandleInfo.fd = scopedFd.release(); + + if (nativePixmap) + importMemoryHandleInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; +#elif defined(Q_OS_WIN) + VkImportMemoryWin32HandleInfoKHR importMemoryHandleInfo = { + VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR + }; + importMemoryHandleInfo.pNext = nullptr; + importMemoryHandleInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT; + importMemoryHandleInfo.handle = sharedHandle; +#endif + + VkMemoryDedicatedAllocateInfoKHR dedicatedMemoryInfo = { + VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR + }; + dedicatedMemoryInfo.pNext = &importMemoryHandleInfo; + dedicatedMemoryInfo.image = importedImage; + + VkMemoryAllocateInfo memoryAllocateInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + memoryAllocateInfo.pNext = &dedicatedMemoryInfo; + + VkMemoryRequirements requirements; + df->vkGetImageMemoryRequirements(qtVulkanDevice, importedImage, &requirements); + if (!requirements.memoryTypeBits) + qFatal("VULKAN: vkGetImageMemoryRequirements failed."); + + VkPhysicalDeviceMemoryProperties memoryProperties; + f->vkGetPhysicalDeviceMemoryProperties(qtPhysicalDevice, &memoryProperties); + constexpr VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + constexpr uint32_t kMaxIndex = 31; + uint32_t memoryTypeIndex = kMaxIndex + 1; + for (uint32_t i = 0; i <= kMaxIndex; i++) { + if (((1u << i) & requirements.memoryTypeBits) == 0) + continue; + if ((memoryProperties.memoryTypes[i].propertyFlags & flags) != flags) + continue; + memoryTypeIndex = i; + break; + } + + if (memoryTypeIndex > kMaxIndex) + qFatal("VULKAN: Cannot find valid memory type index."); + + memoryAllocateInfo.allocationSize = requirements.size; + memoryAllocateInfo.memoryTypeIndex = memoryTypeIndex; + + VkDeviceMemory importedImageMemory = VK_NULL_HANDLE; + result = df->vkAllocateMemory(qtVulkanDevice, &memoryAllocateInfo, nullptr /* pAllocator */, + &importedImageMemory); + if (result != VK_SUCCESS) + qFatal() << "VULKAN: vkAllocateMemory failed result:" << result; + + df->vkBindImageMemory(qtVulkanDevice, importedImage, importedImageMemory, 0); + + QQuickWindow::CreateTextureOptions texOpts(textureOptions); + QSGTexture *texture = QNativeInterface::QSGVulkanTexture::fromNative(importedImage, imageLayout, + win, size(), texOpts); + + m_frontBuffer->textureCleanupCallback = [=]() { + df->vkDestroyImage(qtVulkanDevice, importedImage, nullptr); + df->vkFreeMemory(qtVulkanDevice, importedImageMemory, nullptr); +#if defined(Q_OS_WIN) + ::CloseHandle(sharedHandle); +#endif + }; + + return texture; +} + +} // namespace QtWebEngineCore diff --git a/src/core/compositor/native_skia_output_device_vulkan.h b/src/core/compositor/native_skia_output_device_vulkan.h new file mode 100644 index 000000000..bead0cc11 --- /dev/null +++ b/src/core/compositor/native_skia_output_device_vulkan.h @@ -0,0 +1,28 @@ +// Copyright (C) 2024 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 + +#ifndef NATIVE_SKIA_OUTPUT_DEVICE_VULKAN_H +#define NATIVE_SKIA_OUTPUT_DEVICE_VULKAN_H + +#include "native_skia_output_device.h" + +namespace QtWebEngineCore { + +class NativeSkiaOutputDeviceVulkan final : public NativeSkiaOutputDevice +{ +public: + NativeSkiaOutputDeviceVulkan( + scoped_refptr<gpu::SharedContextState> contextState, bool requiresAlpha, + gpu::MemoryTracker *memoryTracker, viz::SkiaOutputSurfaceDependency *dependency, + gpu::SharedImageFactory *shared_image_factory, + gpu::SharedImageRepresentationFactory *shared_image_representation_factory, + DidSwapBufferCompleteCallback didSwapBufferCompleteCallback); + ~NativeSkiaOutputDeviceVulkan() override; + + // Overridden from Compositor: + QSGTexture *texture(QQuickWindow *win, uint32_t textureOptions) override; +}; + +} // namespace QtWebEngineCore + +#endif // NATIVE_SKIA_OUTPUT_DEVICE_VULKAN_H diff --git a/src/core/compositor/stream_video_node.cpp b/src/core/compositor/stream_video_node.cpp deleted file mode 100644 index 29922f866..000000000 --- a/src/core/compositor/stream_video_node.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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 "stream_video_node.h" - -#include <QtQuick/qsgtexture.h> - -namespace QtWebEngineCore { - -class StreamVideoMaterialShader : public QSGMaterialShader -{ -public: - StreamVideoMaterialShader(TextureTarget target) : m_target(target) { } - virtual void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial); - - char const *const *attributeNames() const override { - static const char *names[] = { - "a_position", - "a_texCoord", - 0 - }; - return names; - } - -protected: - const char *vertexShader() const override { - // Keep in sync with cc::VertexShaderVideoTransform - static const char *shader = - "attribute highp vec4 a_position;\n" - "attribute mediump vec2 a_texCoord;\n" - "uniform highp mat4 matrix;\n" - "uniform highp mat4 texMatrix;\n" - "varying mediump vec2 v_texCoord;\n" - "void main() {\n" - " gl_Position = matrix * a_position;\n" - " v_texCoord = vec4(texMatrix * vec4(a_texCoord.x, 1.0 - a_texCoord.y, 0.0, 1.0)).xy;\n" - "}"; - return shader; - } - - const char *fragmentShader() const override { - // Keep in sync with cc::FragmentShaderRGBATexAlpha - static const char *shaderExternal = - "#extension GL_OES_EGL_image_external : require\n" - "varying mediump vec2 v_texCoord;\n" - "uniform samplerExternalOES s_texture;\n" - "uniform lowp float alpha;\n" - "void main() {\n" - " lowp vec4 texColor = texture2D(s_texture, v_texCoord);\n" - " gl_FragColor = texColor * alpha;\n" - "}"; - static const char *shader2DRect = - "#extension GL_ARB_texture_rectangle : require\n" - "varying mediump vec2 v_texCoord;\n" - "uniform sampler2DRect s_texture;\n" - "uniform lowp float alpha;\n" - "void main() {\n" - " lowp vec4 texColor = texture2DRect(s_texture, v_texCoord);\n" - " gl_FragColor = texColor * alpha;\n" - "}"; - if (m_target == ExternalTarget) - return shaderExternal; - else - return shader2DRect; - } - - virtual void initialize() { - m_id_matrix = program()->uniformLocation("matrix"); - m_id_sTexture = program()->uniformLocation("s_texture"); - m_id_texMatrix = program()->uniformLocation("texMatrix"); - m_id_opacity = program()->uniformLocation("alpha"); - } - - int m_id_matrix; - int m_id_texMatrix; - int m_id_sTexture; - int m_id_opacity; - TextureTarget m_target; -}; - -void StreamVideoMaterialShader::updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) -{ - Q_UNUSED(oldMaterial); - - StreamVideoMaterial *mat = static_cast<StreamVideoMaterial *>(newMaterial); - program()->setUniformValue(m_id_sTexture, 0); - - mat->m_texture->bind(); - - if (state.isOpacityDirty()) - program()->setUniformValue(m_id_opacity, state.opacity()); - - if (state.isMatrixDirty()) - program()->setUniformValue(m_id_matrix, state.combinedMatrix()); - - program()->setUniformValue(m_id_texMatrix, mat->m_texMatrix); -} - -StreamVideoMaterial::StreamVideoMaterial(QSGTexture *texture, TextureTarget target) - : m_texture(texture) - , m_target(target) -{ -} - -QSGMaterialShader *StreamVideoMaterial::createShader() const -{ - return new StreamVideoMaterialShader(m_target); -} - -StreamVideoNode::StreamVideoNode(QSGTexture *texture, bool flip, TextureTarget target) - : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4) - , m_flip(flip) -{ - setGeometry(&m_geometry); - setFlag(QSGNode::OwnsMaterial); - m_material = new StreamVideoMaterial(texture, target); - setMaterial(m_material); -} - -void StreamVideoNode::setRect(const QRectF &rect) -{ - if (m_flip) - QSGGeometry::updateTexturedRectGeometry(geometry(), rect, QRectF(0, 1, 1, -1)); - else - QSGGeometry::updateTexturedRectGeometry(geometry(), rect, QRectF(0, 0, 1, 1)); -} - -void StreamVideoNode::setTextureMatrix(const QMatrix4x4 &matrix) -{ - m_material->m_texMatrix = matrix; -} - -} // namespace diff --git a/src/core/compositor/stream_video_node.h b/src/core/compositor/stream_video_node.h deleted file mode 100644 index 9d937791f..000000000 --- a/src/core/compositor/stream_video_node.h +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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 STREAM_VIDEO_NODE_H -#define STREAM_VIDEO_NODE_H - -#include <QtQuick/qsgmaterial.h> -#include <QtQuick/qsgnode.h> - -QT_FORWARD_DECLARE_CLASS(QSGTexture) - -namespace QtWebEngineCore { - -// These classes duplicate, QtQuick style, the logic of GLRenderer::DrawStreamVideoQuad. -// Their behavior should stay as close as possible to GLRenderer. - -enum TextureTarget { ExternalTarget, RectangleTarget }; - -class StreamVideoMaterial : public QSGMaterial -{ -public: - StreamVideoMaterial(QSGTexture *texture, TextureTarget target); - - QSGMaterialType *type() const override - { - static QSGMaterialType theType; - return &theType; - } - - QSGMaterialShader *createShader() const override; - - QSGTexture *m_texture; - QMatrix4x4 m_texMatrix; - TextureTarget m_target; -}; - -class StreamVideoNode : public QSGGeometryNode -{ -public: - StreamVideoNode(QSGTexture *texture, bool flip, TextureTarget target); - void setRect(const QRectF &rect); - void setTextureMatrix(const QMatrix4x4 &matrix); - -private: - QSGGeometry m_geometry; - bool m_flip; - StreamVideoMaterial *m_material; -}; - -} // namespace - -#endif // STREAM_VIDEO_NODE_H diff --git a/src/core/compositor/vulkan_implementation_qt.cpp b/src/core/compositor/vulkan_implementation_qt.cpp new file mode 100644 index 000000000..2f2259666 --- /dev/null +++ b/src/core/compositor/vulkan_implementation_qt.cpp @@ -0,0 +1,162 @@ +// Copyright (C) 2022 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 "vulkan_implementation_qt.h" + +#include "base/environment.h" +#include "base/logging.h" +#include "gpu/vulkan/vulkan_image.h" +#include "gpu/vulkan/vulkan_surface.h" +#include "gpu/vulkan/vulkan_util.h" +#include "ui/gfx/gpu_fence.h" + +#include <vulkan/vulkan.h> + +namespace gpu { + +VulkanImplementationQt::VulkanImplementationQt() : VulkanImplementation(false) { } + +VulkanImplementationQt::~VulkanImplementationQt() = default; + +bool VulkanImplementationQt::InitializeVulkanInstance(bool /*using_surface*/) +{ + std::vector<const char *> required_extensions = { + VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, + VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, + }; + + auto env = base::Environment::Create(); + std::string vulkan_path; + if (!env->GetVar("QT_VULKAN_LIB", &vulkan_path)) { +#if BUILDFLAG(IS_WIN) + vulkan_path = "vulkan-1.dll"; +#else + vulkan_path = "libvulkan.so.1"; +#endif + } + + if (!vulkan_instance_.Initialize(base::FilePath::FromUTF8Unsafe(vulkan_path), + required_extensions, {})) { + LOG(ERROR) << "Failed to initialize vulkan instance"; + return false; + } + + return true; +} + +VulkanInstance *VulkanImplementationQt::GetVulkanInstance() +{ + return &vulkan_instance_; +} + +std::unique_ptr<VulkanSurface> +VulkanImplementationQt::CreateViewSurface(gfx::AcceleratedWidget /*window*/) +{ + NOTREACHED(); + return nullptr; +} + +bool VulkanImplementationQt::GetPhysicalDevicePresentationSupport( + VkPhysicalDevice /*device*/, + const std::vector<VkQueueFamilyProperties> & /*queue_family_properties*/, + uint32_t /*queue_family_index*/) +{ + NOTREACHED(); + return true; +} + +std::vector<const char *> VulkanImplementationQt::GetRequiredDeviceExtensions() +{ + return { + VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME, +#if BUILDFLAG(IS_WIN) + VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, +#else + VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, +#endif + }; +} + +std::vector<const char *> VulkanImplementationQt::GetOptionalDeviceExtensions() +{ + return { + VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME, +#if BUILDFLAG(IS_WIN) + VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME, +#else + VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, + VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME, + VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME, + VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME, +#endif + }; +} + +VkFence VulkanImplementationQt::CreateVkFenceForGpuFence(VkDevice /*vk_device*/) +{ + NOTREACHED(); + return VK_NULL_HANDLE; +} + +std::unique_ptr<gfx::GpuFence> +VulkanImplementationQt::ExportVkFenceToGpuFence(VkDevice /*vk_device*/, VkFence /*vk_fence*/) +{ + NOTREACHED(); + return nullptr; +} + +VkSemaphore VulkanImplementationQt::ImportSemaphoreHandle(VkDevice vk_device, + SemaphoreHandle sync_handle) +{ + return ImportVkSemaphoreHandle(vk_device, std::move(sync_handle)); +} + +VkExternalSemaphoreHandleTypeFlagBits VulkanImplementationQt::GetExternalSemaphoreHandleType() +{ +#if BUILDFLAG(IS_WIN) + return VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT; +#else + return VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT; +#endif +} + +bool VulkanImplementationQt::CanImportGpuMemoryBuffer( + VulkanDeviceQueue *device_queue, + gfx::GpuMemoryBufferType memory_buffer_type) +{ +#if BUILDFLAG(IS_LINUX) + const auto &enabled_extensions = device_queue->enabled_extensions(); + return gfx::HasExtension(enabled_extensions, + VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME) && + gfx::HasExtension(enabled_extensions, + VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME) && + memory_buffer_type == gfx::GpuMemoryBufferType::NATIVE_PIXMAP; +#else + return false; +#endif +} + +std::unique_ptr<VulkanImage> VulkanImplementationQt::CreateImageFromGpuMemoryHandle(VulkanDeviceQueue *device_queue, + gfx::GpuMemoryBufferHandle gmb_handle, + gfx::Size size, + VkFormat vk_format, + const gfx::ColorSpace &) +{ +#if BUILDFLAG(IS_LINUX) + constexpr auto kUsage = + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + auto tiling = gmb_handle.native_pixmap_handle.modifier == + gfx::NativePixmapHandle::kNoModifier + ? VK_IMAGE_TILING_OPTIMAL + : VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT; + return gpu::VulkanImage::CreateFromGpuMemoryBufferHandle( + device_queue, std::move(gmb_handle), size, vk_format, kUsage, /*flags=*/0, + tiling, VK_QUEUE_FAMILY_EXTERNAL); +#else + NOTIMPLEMENTED(); + return nullptr; +#endif +} + +} // namespace gpu diff --git a/src/core/compositor/vulkan_implementation_qt.h b/src/core/compositor/vulkan_implementation_qt.h new file mode 100644 index 000000000..88983331f --- /dev/null +++ b/src/core/compositor/vulkan_implementation_qt.h @@ -0,0 +1,46 @@ +// Copyright (C) 2022 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 + +#ifndef VULKAN_IMPLEMENTATION_QT_H +#define VULKAN_IMPLEMENTATION_QT_H + +#include "gpu/vulkan/vulkan_implementation.h" +#include "gpu/vulkan/vulkan_instance.h" + +namespace gpu { + +class VulkanImplementationQt : public VulkanImplementation +{ +public: + VulkanImplementationQt(); + ~VulkanImplementationQt() override; + + // Overridden from VulkanImplementation. + bool InitializeVulkanInstance(bool using_surface) override; + VulkanInstance *GetVulkanInstance() override; + std::unique_ptr<VulkanSurface> CreateViewSurface(gfx::AcceleratedWidget window) override; + bool GetPhysicalDevicePresentationSupport( + VkPhysicalDevice device, + const std::vector<VkQueueFamilyProperties> &queue_family_properties, + uint32_t queue_family_index) override; + std::vector<const char *> GetRequiredDeviceExtensions() override; + std::vector<const char *> GetOptionalDeviceExtensions() override; + VkFence CreateVkFenceForGpuFence(VkDevice vk_device) override; + std::unique_ptr<gfx::GpuFence> ExportVkFenceToGpuFence(VkDevice vk_device, + VkFence vk_fence) override; + VkSemaphore ImportSemaphoreHandle(VkDevice vk_device, SemaphoreHandle handle) override; + VkExternalSemaphoreHandleTypeFlagBits GetExternalSemaphoreHandleType() override; + bool CanImportGpuMemoryBuffer(VulkanDeviceQueue* device_queue, + gfx::GpuMemoryBufferType memory_buffer_type) override; + std::unique_ptr<VulkanImage> CreateImageFromGpuMemoryHandle(VulkanDeviceQueue *device_queue, + gfx::GpuMemoryBufferHandle gmb_handle, + gfx::Size size, VkFormat vk_format, + const gfx::ColorSpace &color_space) override; + +private: + VulkanInstance vulkan_instance_; +}; + +} // namespace gpu + +#endif // VULKAN_IMPLEMENTATION_QT_H diff --git a/src/core/compositor/yuv_video_node.cpp b/src/core/compositor/yuv_video_node.cpp deleted file mode 100644 index 4a436d952..000000000 --- a/src/core/compositor/yuv_video_node.cpp +++ /dev/null @@ -1,352 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ - -// Based on cc/output/gl_renderer.cc and cc/output/shader.cc: -// Copyright 2011 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.Chromium file. - -#include "yuv_video_node.h" - -#include <QtGui/qopenglcontext.h> -#include <QtGui/qopenglfunctions.h> -#include <QtQuick/qsgtexture.h> - -#include "ui/gfx/color_space.h" -#include "ui/gfx/color_transform.h" - -namespace QtWebEngineCore { - -class YUVVideoMaterialShader : public QSGMaterialShader -{ -public: - YUVVideoMaterialShader(const gfx::ColorSpace &colorSpace) - { - static const char *shaderHead = - "varying mediump vec2 v_yaTexCoord;\n" - "varying mediump vec2 v_uvTexCoord;\n" - "uniform sampler2D y_texture;\n" - "uniform sampler2D u_texture;\n" - "uniform sampler2D v_texture;\n" - "uniform mediump float alpha;\n" - "uniform mediump vec4 ya_clamp_rect;\n" - "uniform mediump vec4 uv_clamp_rect;\n"; - static const char *shader = - "void main() {\n" - " mediump vec2 ya_clamped =\n" - " max(ya_clamp_rect.xy, min(ya_clamp_rect.zw, v_yaTexCoord));\n" - " mediump float y_raw = texture2D(y_texture, ya_clamped).x;\n" - " mediump vec2 uv_clamped =\n" - " max(uv_clamp_rect.xy, min(uv_clamp_rect.zw, v_uvTexCoord));\n" - " mediump float u_unsigned = texture2D(u_texture, uv_clamped).x;\n" - " mediump float v_unsigned = texture2D(v_texture, uv_clamped).x;\n" - " mediump vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned);\n" - " mediump vec3 rgb = DoColorConversion(yuv);\n" - " gl_FragColor = vec4(rgb, 1.0) * alpha;\n" - "}"; - // Invalid or unspecified color spaces should be treated as REC709. - gfx::ColorSpace src = colorSpace.IsValid() ? colorSpace : gfx::ColorSpace::CreateREC709(); - gfx::ColorSpace dst = gfx::ColorSpace::CreateSRGB(); - std::unique_ptr<gfx::ColorTransform> transform = - gfx::ColorTransform::NewColorTransform(src, dst, gfx::ColorTransform::Intent::INTENT_PERCEPTUAL); - - QByteArray header(shaderHead); - if (QOpenGLContext::currentContext()->isOpenGLES()) - header = QByteArray("precision mediump float;\n") + header; - - m_csShader = QByteArray::fromStdString(transform->GetShaderSource()); - m_fragmentShader = header + m_csShader + QByteArray(shader); - } - void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; - - char const *const *attributeNames() const override { - static const char *names[] = { - "a_position", - "a_texCoord", - 0 - }; - return names; - } - -protected: - const char *vertexShader() const override { - // Keep in sync with logic in VertexShader in components/viz/service/display/shader.cc - const char *shader = - "attribute highp vec4 a_position;\n" - "attribute mediump vec2 a_texCoord;\n" - "uniform highp mat4 matrix;\n" - "varying mediump vec2 v_yaTexCoord;\n" - "varying mediump vec2 v_uvTexCoord;\n" - "uniform mediump vec2 yaTexScale;\n" - "uniform mediump vec2 yaTexOffset;\n" - "uniform mediump vec2 uvTexScale;\n" - "uniform mediump vec2 uvTexOffset;\n" - "void main() {\n" - " gl_Position = matrix * a_position;\n" - " v_yaTexCoord = a_texCoord * yaTexScale + yaTexOffset;\n" - " v_uvTexCoord = a_texCoord * uvTexScale + uvTexOffset;\n" - "}"; - return shader; - } - - const char *fragmentShader() const override { - return m_fragmentShader.constData(); - } - - void initialize() override { - m_id_matrix = program()->uniformLocation("matrix"); - m_id_yaTexScale = program()->uniformLocation("yaTexScale"); - m_id_uvTexScale = program()->uniformLocation("uvTexScale"); - m_id_yaTexOffset = program()->uniformLocation("yaTexOffset"); - m_id_uvTexOffset = program()->uniformLocation("uvTexOffset"); - m_id_yaClampRect = program()->uniformLocation("ya_clamp_rect"); - m_id_uvClampRect = program()->uniformLocation("uv_clamp_rect"); - m_id_yTexture = program()->uniformLocation("y_texture"); - m_id_uTexture = program()->uniformLocation("u_texture"); - m_id_vTexture = program()->uniformLocation("v_texture"); - m_id_yuvMatrix = program()->uniformLocation("yuv_matrix"); - m_id_yuvAdjust = program()->uniformLocation("yuv_adj"); - m_id_opacity = program()->uniformLocation("alpha"); - } - - int m_id_matrix; - int m_id_yaTexScale; - int m_id_uvTexScale; - int m_id_yaTexOffset; - int m_id_uvTexOffset; - int m_id_yaClampRect; - int m_id_uvClampRect; - int m_id_yTexture; - int m_id_uTexture; - int m_id_vTexture; - int m_id_yuvMatrix; - int m_id_yuvAdjust; - int m_id_opacity; - QByteArray m_csShader; - QByteArray m_fragmentShader; -}; - -class YUVAVideoMaterialShader : public YUVVideoMaterialShader -{ -public: - YUVAVideoMaterialShader(const gfx::ColorSpace &colorSpace) : YUVVideoMaterialShader(colorSpace) - { - static const char *shaderHead = - "varying mediump vec2 v_yaTexCoord;\n" - "varying mediump vec2 v_uvTexCoord;\n" - "uniform sampler2D y_texture;\n" - "uniform sampler2D u_texture;\n" - "uniform sampler2D v_texture;\n" - "uniform sampler2D a_texture;\n" - "uniform mediump float alpha;\n" - "uniform mediump vec4 ya_clamp_rect;\n" - "uniform mediump vec4 uv_clamp_rect;\n"; - static const char *shader = - "void main() {\n" - " mediump vec2 ya_clamped =\n" - " max(ya_clamp_rect.xy, min(ya_clamp_rect.zw, v_yaTexCoord));\n" - " mediump float y_raw = texture2D(y_texture, ya_clamped).x;\n" - " mediump vec2 uv_clamped =\n" - " max(uv_clamp_rect.xy, min(uv_clamp_rect.zw, v_uvTexCoord));\n" - " mediump float u_unsigned = texture2D(u_texture, uv_clamped).x;\n" - " mediump float v_unsigned = texture2D(v_texture, uv_clamped).x;\n" - " mediump float a_raw = texture2D(a_texture, ya_clamped).x;\n" - " mediump vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned);\n" - " mediump vec3 rgb = DoColorConversion(yuv);\n" - " gl_FragColor = vec4(rgb, 1.0) * (alpha * a_raw);\n" - "}"; - QByteArray header(shaderHead); - if (QOpenGLContext::currentContext()->isOpenGLES()) - header = QByteArray("precision mediump float;\n") + header; - m_fragmentShader = header + m_csShader + QByteArray(shader); - } - void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; - -protected: - void initialize() override { - // YUVVideoMaterialShader has a subset of the uniforms. - YUVVideoMaterialShader::initialize(); - m_id_aTexture = program()->uniformLocation("a_texture"); - } - - int m_id_aTexture; -}; - -void YUVVideoMaterialShader::updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) -{ - Q_UNUSED(oldMaterial); - - // Keep logic in sync with logic in GLRenderer::DrawYUVVideoQuad: - - YUVVideoMaterial *mat = static_cast<YUVVideoMaterial *>(newMaterial); - program()->setUniformValue(m_id_yTexture, 0); - program()->setUniformValue(m_id_uTexture, 1); - program()->setUniformValue(m_id_vTexture, 2); - - QOpenGLFunctions glFuncs(QOpenGLContext::currentContext()); - - glFuncs.glActiveTexture(GL_TEXTURE1); - mat->m_uTexture->bind(); - glFuncs.glActiveTexture(GL_TEXTURE2); - mat->m_vTexture->bind(); - glFuncs.glActiveTexture(GL_TEXTURE0); // Finish with 0 as default texture unit - mat->m_yTexture->bind(); - - const QSizeF yaSizeScale(1.0f / mat->m_yaTexSize.width(), 1.0f / mat->m_yaTexSize.height()); - const QSizeF uvSizeScale(1.0f / mat->m_uvTexSize.width(), 1.0f / mat->m_uvTexSize.height()); - - const QPointF yaTexOffset(mat->m_yaTexCoordRect.left() * yaSizeScale.width(), mat->m_yaTexCoordRect.top() * yaSizeScale.height()); - const QPointF uvTexOffset(mat->m_uvTexCoordRect.left() * uvSizeScale.width(), mat->m_uvTexCoordRect.top() * uvSizeScale.height()); - const QSizeF yaTexScale(mat->m_yaTexCoordRect.width() * yaSizeScale.width(), mat->m_yaTexCoordRect.height() * yaSizeScale.height()); - const QSizeF uvTexScale(mat->m_uvTexCoordRect.width() * uvSizeScale.width(), mat->m_uvTexCoordRect.height() * uvSizeScale.height()); - program()->setUniformValue(m_id_yaTexOffset, yaTexOffset); - program()->setUniformValue(m_id_uvTexOffset, uvTexOffset); - program()->setUniformValue(m_id_yaTexScale, yaTexScale); - program()->setUniformValue(m_id_uvTexScale, uvTexScale); - QRectF yaClampRect(yaTexOffset, yaTexScale); - QRectF uvClampRect(uvTexOffset, uvTexScale); - yaClampRect = yaClampRect.marginsRemoved(QMarginsF(yaSizeScale.width() * 0.5f, yaSizeScale.height() * 0.5f, - yaSizeScale.width() * 0.5f, yaSizeScale.height() * 0.5f)); - uvClampRect = uvClampRect.marginsRemoved(QMarginsF(uvSizeScale.width() * 0.5f, uvSizeScale.height() * 0.5f, - uvSizeScale.width() * 0.5f, uvSizeScale.height() * 0.5f)); - - const QVector4D yaClampV(yaClampRect.left(), yaClampRect.top(), yaClampRect.right(), yaClampRect.bottom()); - const QVector4D uvClampV(uvClampRect.left(), uvClampRect.top(), uvClampRect.right(), uvClampRect.bottom()); - program()->setUniformValue(m_id_yaClampRect, yaClampV); - program()->setUniformValue(m_id_uvClampRect, uvClampV); - - if (state.isOpacityDirty()) - program()->setUniformValue(m_id_opacity, state.opacity()); - - if (state.isMatrixDirty()) - program()->setUniformValue(m_id_matrix, state.combinedMatrix()); -} - -void YUVAVideoMaterialShader::updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) -{ - YUVVideoMaterialShader::updateState(state, newMaterial, oldMaterial); - - YUVAVideoMaterial *mat = static_cast<YUVAVideoMaterial *>(newMaterial); - program()->setUniformValue(m_id_aTexture, 3); - - QOpenGLFunctions glFuncs(QOpenGLContext::currentContext()); - - glFuncs.glActiveTexture(GL_TEXTURE3); - mat->m_aTexture->bind(); - - // Reset the default texture unit. - glFuncs.glActiveTexture(GL_TEXTURE0); -} - - -YUVVideoMaterial::YUVVideoMaterial(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, - const QRectF &yaTexCoordRect, const QRectF &uvTexCoordRect, const QSizeF &yaTexSize, const QSizeF &uvTexSize, - const gfx::ColorSpace &colorspace, - float rMul, float rOff) - : m_yTexture(yTexture) - , m_uTexture(uTexture) - , m_vTexture(vTexture) - , m_yaTexCoordRect(yaTexCoordRect) - , m_uvTexCoordRect(uvTexCoordRect) - , m_yaTexSize(yaTexSize) - , m_uvTexSize(uvTexSize) - , m_colorSpace(colorspace) - , m_resourceMultiplier(rMul) - , m_resourceOffset(rOff) -{ -} - -QSGMaterialShader *YUVVideoMaterial::createShader() const -{ - return new YUVVideoMaterialShader(m_colorSpace); -} - -int YUVVideoMaterial::compare(const QSGMaterial *other) const -{ - const YUVVideoMaterial *m = static_cast<const YUVVideoMaterial *>(other); - if (int diff = m_yTexture->textureId() - m->m_yTexture->textureId()) - return diff; - if (int diff = m_uTexture->textureId() - m->m_uTexture->textureId()) - return diff; - return m_vTexture->textureId() - m->m_vTexture->textureId(); -} - -YUVAVideoMaterial::YUVAVideoMaterial(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, QSGTexture *aTexture, - const QRectF &yaTexCoordRect, const QRectF &uvTexCoordRect, const QSizeF &yaTexSize, const QSizeF &uvTexSize, - const gfx::ColorSpace &colorspace, - float rMul, float rOff) - : YUVVideoMaterial(yTexture, uTexture, vTexture, yaTexCoordRect, uvTexCoordRect, yaTexSize, uvTexSize, colorspace, rMul, rOff) - , m_aTexture(aTexture) -{ - setFlag(Blending, aTexture); -} - -QSGMaterialShader *YUVAVideoMaterial::createShader() const -{ - return new YUVAVideoMaterialShader(m_colorSpace); -} - -int YUVAVideoMaterial::compare(const QSGMaterial *other) const -{ - if (int diff = YUVVideoMaterial::compare(other)) - return diff; - const YUVAVideoMaterial *m = static_cast<const YUVAVideoMaterial *>(other); - return (m_aTexture ? m_aTexture->textureId() : 0) - (m->m_aTexture ? m->m_aTexture->textureId() : 0); -} - -YUVVideoNode::YUVVideoNode(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, QSGTexture *aTexture, - const QRectF &yaTexCoordRect, const QRectF &uvTexCoordRect, const QSizeF &yaTexSize, const QSizeF &uvTexSize, - const gfx::ColorSpace &colorspace, float rMul, float rOff) - : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4) -{ - setGeometry(&m_geometry); - setFlag(QSGNode::OwnsMaterial); - if (aTexture) - m_material = new YUVAVideoMaterial(yTexture, uTexture, vTexture, aTexture, yaTexCoordRect, uvTexCoordRect, yaTexSize, uvTexSize, colorspace, rMul, rOff); - else - m_material = new YUVVideoMaterial(yTexture, uTexture, vTexture, yaTexCoordRect, uvTexCoordRect, yaTexSize, uvTexSize, colorspace, rMul, rOff); - setMaterial(m_material); -} - -void YUVVideoNode::setRect(const QRectF &rect) -{ - QSGGeometry::updateTexturedRectGeometry(geometry(), rect, QRectF(0, 0, 1, 1)); -} - -} // namespace diff --git a/src/core/compositor/yuv_video_node.h b/src/core/compositor/yuv_video_node.h deleted file mode 100644 index dca8fa5e2..000000000 --- a/src/core/compositor/yuv_video_node.h +++ /dev/null @@ -1,117 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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 YUV_VIDEO_NODE_H -#define YUV_VIDEO_NODE_H - -#include <QtQuick/qsgmaterial.h> -#include <QtQuick/qsgnode.h> - -#include "ui/gfx/color_space.h" - -QT_FORWARD_DECLARE_CLASS(QSGTexture) - -namespace QtWebEngineCore { - -// These classes duplicate, QtQuick style, the logic of GLRenderer::DrawYUVVideoQuad. -// Their behavior should stay as close as possible to GLRenderer. - -class YUVVideoMaterial : public QSGMaterial -{ -public: - YUVVideoMaterial(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, - const QRectF &yaTexCoordRect, const QRectF &uvTexCoordRect, const QSizeF &yaTexSize, const QSizeF &uvTexSize, - const gfx::ColorSpace &colorspace, float rMul, float rOff); - - QSGMaterialType *type() const override - { - static QSGMaterialType theType; - return &theType; - } - - QSGMaterialShader *createShader() const override; - int compare(const QSGMaterial *other) const override; - - QSGTexture *m_yTexture; - QSGTexture *m_uTexture; - QSGTexture *m_vTexture; - QRectF m_yaTexCoordRect; - QRectF m_uvTexCoordRect; - QSizeF m_yaTexSize; - QSizeF m_uvTexSize; - gfx::ColorSpace m_colorSpace; - float m_resourceMultiplier; - float m_resourceOffset; -}; - -class YUVAVideoMaterial : public YUVVideoMaterial -{ -public: - YUVAVideoMaterial(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, QSGTexture *aTexture, - const QRectF &yaTexCoordRect, const QRectF &uvTexCoordRect, const QSizeF &yaTexSize, const QSizeF &uvTexSize, - const gfx::ColorSpace &colorspace, float rMul, float rOff); - - QSGMaterialType *type() const override - { - static QSGMaterialType theType; - return &theType; - } - - QSGMaterialShader *createShader() const override; - int compare(const QSGMaterial *other) const override; - - QSGTexture *m_aTexture; -}; - -class YUVVideoNode : public QSGGeometryNode -{ -public: - YUVVideoNode(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, QSGTexture *aTexture, - const QRectF &yaTexCoordRect, const QRectF &uvTexCoordRect, const QSizeF &yaTexSize, const QSizeF &uvTexSize, - const gfx::ColorSpace &colorspace, float rMul, float rOff); - void setRect(const QRectF &rect); - -private: - QSGGeometry m_geometry; - YUVVideoMaterial *m_material; -}; - -} // namespace - -#endif // YUV_VIDEO_NODE_H |