diff options
Diffstat (limited to 'src')
27 files changed, 691 insertions, 697 deletions
diff --git a/src/core/compositor/compositor.cpp b/src/core/compositor/compositor.cpp new file mode 100644 index 000000000..c45c02844 --- /dev/null +++ b/src/core/compositor/compositor.cpp @@ -0,0 +1,215 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "compositor.h" + +#include "base/memory/ref_counted.h" +#include "components/viz/common/surfaces/frame_sink_id.h" + +#include <QHash> +#include <QImage> +#include <QMutex> + +namespace QtWebEngineCore { + +// Compositor::Id + +Compositor::Id::Id(viz::FrameSinkId fid) : client_id(fid.client_id()), sink_id(fid.sink_id()) { } + +static size_t qHash(Compositor::Id id, size_t seed = 0) +{ + QtPrivate::QHashCombine hasher; + seed = hasher(seed, id.client_id); + seed = hasher(seed, id.sink_id); + return seed; +} + +static bool operator==(Compositor::Id id1, Compositor::Id id2) +{ + return id1.client_id == id2.client_id && id1.sink_id == id2.sink_id; +} + +// Compositor::Binding and Compositor::Bindings + +struct Compositor::Binding +{ + const Id id; + Compositor *compositor = nullptr; + Observer *observer = nullptr; + + Binding(Id id) : id(id) { } + ~Binding(); +}; + +class Compositor::BindingMap +{ +public: + void lock() { m_mutex.lock(); } + + void unlock() { m_mutex.unlock(); } + + 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; + } + + void remove(Id id) { m_map.remove(id); } + +private: + QMutex m_mutex; + QHash<Id, Binding *> m_map; +} static g_bindings; + +Compositor::Binding::~Binding() +{ + g_bindings.remove(id); +} + +// Compositor::Observer + +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::Observer::unbind() +{ + DCHECK(m_binding); + g_bindings.lock(); + m_binding->observer = nullptr; + if (m_binding->compositor == nullptr) + delete m_binding; + m_binding = nullptr; + g_bindings.unlock(); +} + +Compositor::Handle<Compositor> Compositor::Observer::compositor() +{ + if (!m_binding) + return nullptr; + g_bindings.lock(); + if (m_binding->compositor) + return m_binding->compositor; // delay unlock + g_bindings.unlock(); + return nullptr; +} + +// Compositor + +void Compositor::bind(Id id) +{ + DCHECK(!m_binding); + g_bindings.lock(); + m_binding = g_bindings.findOrCreate(id); + DCHECK(!m_binding->compositor); + m_binding->compositor = this; + g_bindings.unlock(); +} + +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(); +} + +Compositor::Handle<Compositor::Observer> Compositor::observer() +{ + if (!m_binding) + return nullptr; + g_bindings.lock(); + if (m_binding->observer) + return m_binding->observer; // delay unlock + g_bindings.unlock(); + return nullptr; +} + +float Compositor::devicePixelRatio() +{ + Q_UNREACHABLE(); + return 1; +} + +QImage Compositor::image() +{ + Q_UNREACHABLE(); + return {}; +} + +void Compositor::waitForTexture() +{ + Q_UNREACHABLE(); +} + +int Compositor::textureId() +{ + Q_UNREACHABLE(); + return 0; +} + +QSize Compositor::textureSize() +{ + Q_UNREACHABLE(); + return {}; +} + +bool Compositor::hasAlphaChannel() +{ + Q_UNREACHABLE(); + return false; +} + +// static +void Compositor::unlockBindings() +{ + g_bindings.unlock(); +} +} // namespace QtWebEngineCore diff --git a/src/core/compositor/compositor.h b/src/core/compositor/compositor.h new file mode 100644 index 000000000..d10cf2ef6 --- /dev/null +++ b/src/core/compositor/compositor.h @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef COMPOSITOR_H +#define COMPOSITOR_H + +#include "qtwebenginecoreglobal_p.h" + +QT_BEGIN_NAMESPACE +class QImage; +class QSize; +QT_END_NAMESPACE + +namespace viz { +class FrameSinkId; +} // namespace viz + +namespace QtWebEngineCore { + +// Produces composited frames for display. +// +// Used by quick/widgets libraries for accessing the frame and +// controlling frame swapping. Must be cast to a subclass to access +// the frame as QImage or OpenGL texture, etc. +class Q_WEBENGINECORE_PRIVATE_EXPORT Compositor +{ + struct Binding; + +public: + // Identifies the implementation type. + enum class Type { + Software, + OpenGL, + }; + + // 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_PRIVATE_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() = default; + + 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(); + + // (Software) QImage of the frame. + // + // This is a big image so we should try not to make copies of it. + // In particular, the client should drop its QImage reference + // before calling swapFrame(), otherwise each swap will cause a + // detach. + virtual QImage image(); + + // (OpenGL) Wait on texture fence in Qt's current OpenGL context. + virtual void waitForTexture(); + + // (OpenGL) Properties of the current frame. + virtual int textureId(); + virtual QSize textureSize(); + virtual bool hasAlphaChannel(); + +protected: + Compositor(Type type) : m_type(type) { } + ~Compositor() = default; + +private: + template<typename T> + friend class Handle; + + class BindingMap; + static void unlockBindings(); + + const Type m_type; + Binding *m_binding = nullptr; +}; + +} // namespace QtWebEngineCore + +#endif // !COMPOSITOR_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 index 4f63e5b69..f736bba79 100644 --- a/src/core/compositor/display_gl_output_surface.cpp +++ b/src/core/compositor/display_gl_output_surface.cpp @@ -39,6 +39,8 @@ #include "display_gl_output_surface.h" +#include "type_conversion.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" @@ -51,8 +53,10 @@ namespace QtWebEngineCore { -DisplayGLOutputSurface::DisplayGLOutputSurface(scoped_refptr<viz::VizProcessContextProvider> contextProvider) +DisplayGLOutputSurface::DisplayGLOutputSurface( + scoped_refptr<viz::VizProcessContextProvider> contextProvider) : OutputSurface(contextProvider) + , Compositor(Compositor::Type::OpenGL) , m_commandBuffer(contextProvider->command_buffer()) , m_gl(contextProvider->ContextGL()) , m_vizContextProvider(contextProvider) @@ -63,18 +67,16 @@ DisplayGLOutputSurface::DisplayGLOutputSurface(scoped_refptr<viz::VizProcessCont DisplayGLOutputSurface::~DisplayGLOutputSurface() { + unbind(); m_vizContextProvider->SetUpdateVSyncParametersCallback(viz::UpdateVSyncParametersCallback()); 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); + bind(m_display->frame_sink_id()); } // Triggered by ui::Compositor::SetVisible(true). @@ -211,7 +213,8 @@ void DisplayGLOutputSurface::swapBuffersOnGpuThread(unsigned int id, std::unique m_middleBuffer->fence = CompositorResourceFence::create(std::move(fence)); } - m_sink->scheduleUpdate(); + if (auto obs = observer()) + obs->readyToSwap(); } void DisplayGLOutputSurface::swapBuffersOnVizThread() @@ -295,4 +298,44 @@ gfx::OverlayTransform DisplayGLOutputSurface::GetDisplayTransform() return gfx::OVERLAY_TRANSFORM_NONE; } +void DisplayGLOutputSurface::swapFrame() +{ + 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(); + } +} + +void DisplayGLOutputSurface::waitForTexture() +{ + if (m_frontBuffer && m_frontBuffer->fence) { + m_frontBuffer->fence->wait(); + m_frontBuffer->fence.reset(); + } +} + +int DisplayGLOutputSurface::textureId() +{ + return m_frontBuffer ? m_frontBuffer->serviceId : 0; +} + +QSize DisplayGLOutputSurface::textureSize() +{ + return m_frontBuffer ? toQt(m_frontBuffer->shape.sizeInPixels) : QSize(); +} + +bool DisplayGLOutputSurface::hasAlphaChannel() +{ + return m_frontBuffer ? m_frontBuffer->shape.hasAlpha : false; +} + +float DisplayGLOutputSurface::devicePixelRatio() +{ + return m_frontBuffer ? m_frontBuffer->shape.devicePixelRatio : 1; +} + } // namespace QtWebEngineCore diff --git a/src/core/compositor/display_gl_output_surface.h b/src/core/compositor/display_gl_output_surface.h index 67d987263..678d0cf5c 100644 --- a/src/core/compositor/display_gl_output_surface.h +++ b/src/core/compositor/display_gl_output_surface.h @@ -41,7 +41,7 @@ #define DISPLAY_GL_OUTPUT_SURFACE_H #include "compositor_resource_fence.h" -#include "display_frame_sink.h" +#include "compositor.h" #include "components/viz/common/display/update_vsync_parameters_callback.h" #include "components/viz/service/display/output_surface.h" @@ -49,6 +49,8 @@ #include "gpu/command_buffer/common/mailbox.h" #include "gpu/command_buffer/common/sync_token.h" +#include <QMutex> + namespace viz { class Display; class SyntheticBeginFrameSource; @@ -56,9 +58,7 @@ class SyntheticBeginFrameSource; 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 +class DisplayGLOutputSurface final : public viz::OutputSurface, public Compositor { public: DisplayGLOutputSurface(scoped_refptr<viz::VizProcessContextProvider> contextProvider); @@ -87,8 +87,13 @@ public: void SetDisplayTransformHint(gfx::OverlayTransform transform) override; gfx::OverlayTransform GetDisplayTransform() override; - // Overridden from DisplayProducer. - QSGNode *updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *delegate) override; + // Overridden from Compositor. + void swapFrame() override; + void waitForTexture() override; + int textureId() override; + QSize textureSize() override; + bool hasAlphaChannel() override; + float devicePixelRatio() override; private: struct Shape @@ -135,7 +140,6 @@ private: 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; 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 2ed24ef1d..000000000 --- a/src/core/compositor/display_gl_output_surface_qsg.cpp +++ /dev/null @@ -1,122 +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); - } - int comparisonKey() const override { return 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_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_software_output_surface.cpp b/src/core/compositor/display_software_output_surface.cpp index ba99799f0..b1a357615 100644 --- a/src/core/compositor/display_software_output_surface.cpp +++ b/src/core/compositor/display_software_output_surface.cpp @@ -39,7 +39,7 @@ #include "display_software_output_surface.h" -#include "display_frame_sink.h" +#include "compositor.h" #include "render_widget_host_view_qt_delegate.h" #include "type_conversion.h" @@ -49,28 +49,27 @@ #include <QMutex> #include <QPainter> -#include <QSGImageNode> namespace QtWebEngineCore { -class DisplaySoftwareOutputSurface::Device final : public viz::SoftwareOutputDevice, public DisplayProducer +class DisplaySoftwareOutputSurface::Device final : public viz::SoftwareOutputDevice, + public Compositor { public: + Device(); ~Device(); - // Called from DisplaySoftwareOutputSurface. - void bind(viz::FrameSinkId frameSinkId); - // Overridden from viz::SoftwareOutputDevice. void Resize(const gfx::Size &sizeInPixels, float devicePixelRatio) override; void OnSwapBuffers(SwapBuffersCallback swap_ack_callback) override; - // Overridden from DisplayProducer. - QSGNode *updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *delegate) override; + // Overridden from Compositor. + void swapFrame() override; + QImage image() override; + float devicePixelRatio() override; private: mutable QMutex m_mutex; - scoped_refptr<DisplayFrameSink> m_sink; float m_devicePixelRatio = 1.0; scoped_refptr<base::SingleThreadTaskRunner> m_taskRunner; SwapBuffersCallback m_swapCompletionCallback; @@ -78,16 +77,13 @@ private: float m_imageDevicePixelRatio = 1.0; }; -DisplaySoftwareOutputSurface::Device::~Device() -{ - if (m_sink) - m_sink->disconnect(this); -} +DisplaySoftwareOutputSurface::Device::Device() + : Compositor(Type::Software) +{} -void DisplaySoftwareOutputSurface::Device::bind(viz::FrameSinkId frameSinkId) +DisplaySoftwareOutputSurface::Device::~Device() { - m_sink = DisplayFrameSink::findOrCreate(frameSinkId); - m_sink->connect(this); + unbind(); } void DisplaySoftwareOutputSurface::Device::Resize(const gfx::Size &sizeInPixels, float devicePixelRatio) @@ -104,7 +100,8 @@ void DisplaySoftwareOutputSurface::Device::OnSwapBuffers(SwapBuffersCallback swa QMutexLocker locker(&m_mutex); m_taskRunner = base::ThreadTaskRunnerHandle::Get(); m_swapCompletionCallback = std::move(swap_ack_callback); - m_sink->scheduleUpdate(); + if (auto obs = observer()) + obs->readyToSwap(); } inline QImage::Format imageFormat(SkColorType colorType) @@ -120,41 +117,41 @@ 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 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(); + 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(); +} - QSizeF sizeInDips = QSizeF(m_image.size()) / m_imageDevicePixelRatio; - node->setRect(QRectF(QPointF(0, 0), sizeInDips)); - node->setOwnsTexture(true); - node->setTexture(delegate->createTextureFromImage(m_image)); +QImage DisplaySoftwareOutputSurface::Device::image() +{ + return m_image; +} - return node; +float DisplaySoftwareOutputSurface::Device::devicePixelRatio() +{ + return m_imageDevicePixelRatio; } DisplaySoftwareOutputSurface::DisplaySoftwareOutputSurface() diff --git a/src/core/core_chromium.pri b/src/core/core_chromium.pri index f2cedaf4a..14a65a39c 100644 --- a/src/core/core_chromium.pri +++ b/src/core/core_chromium.pri @@ -53,8 +53,8 @@ SOURCES = \ common/qt_ipc_logging.cpp \ common/qt_messages.cpp \ common/user_script_data.cpp \ + compositor/compositor.cpp \ compositor/content_gpu_client_qt.cpp \ - compositor/display_frame_sink.cpp \ compositor/display_overrides.cpp \ compositor/display_software_output_surface.cpp \ content_client_qt.cpp \ @@ -157,8 +157,8 @@ HEADERS = \ color_chooser_controller.h \ common/qt_messages.h \ common/user_script_data.h \ + compositor/compositor.h \ compositor/content_gpu_client_qt.h \ - compositor/display_frame_sink.h \ compositor/display_software_output_surface.h \ content_client_qt.h \ content_browser_client_qt.h \ @@ -293,8 +293,7 @@ qtConfig(webengine-printing-and-pdf) { contains(QT_CONFIG, opengl) { SOURCES += \ compositor/compositor_resource_fence.cpp \ - compositor/display_gl_output_surface.cpp \ - compositor/display_gl_output_surface_qsg.cpp + compositor/display_gl_output_surface.cpp HEADERS += \ compositor/compositor_resource_fence.h \ compositor/display_gl_output_surface.h diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index 27229df81..9be6fac9a 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -148,9 +148,6 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost *widget m_uiCompositor->SetAcceleratedWidget(gfx::kNullAcceleratedWidget); // null means offscreen m_uiCompositor->SetRootLayer(m_rootLayer.get()); - m_displayFrameSink = DisplayFrameSink::findOrCreate(m_uiCompositor->frame_sink_id()); - m_displayFrameSink->connect(this); - if (host()->delegate() && host()->delegate()->GetInputEventRouter()) host()->delegate()->GetInputEventRouter()->AddFrameSinkIdOwner(GetFrameSinkId(), this); @@ -172,8 +169,6 @@ RenderWidgetHostViewQt::~RenderWidgetHostViewQt() QObject::disconnect(m_adapterClientDestroyedConnection); - m_displayFrameSink->disconnect(this); - if (text_input_manager_) text_input_manager_->RemoveObserver(this); @@ -707,36 +702,12 @@ void RenderWidgetHostViewQt::OnDidUpdateVisualPropertiesComplete(const cc::Rende void RenderWidgetHostViewQt::OnDidFirstVisuallyNonEmptyPaint() { - if (m_loadVisuallyCommittedState == NotCommitted) { - m_loadVisuallyCommittedState = DidFirstVisuallyNonEmptyPaint; - } else if (m_loadVisuallyCommittedState == DidFirstCompositorFrameSwap) { - m_adapterClient->loadVisuallyCommitted(); - m_loadVisuallyCommittedState = NotCommitted; - } -} - -void RenderWidgetHostViewQt::scheduleUpdate() -{ - m_taskRunner->PostTask( - FROM_HERE, - base::BindOnce(&RenderWidgetHostViewQt::callUpdate, m_weakPtrFactory.GetWeakPtr())); -} - -void RenderWidgetHostViewQt::callUpdate() -{ - m_delegate->update(); - - if (m_loadVisuallyCommittedState == NotCommitted) { - m_loadVisuallyCommittedState = DidFirstCompositorFrameSwap; - } else if (m_loadVisuallyCommittedState == DidFirstVisuallyNonEmptyPaint) { - m_adapterClient->loadVisuallyCommitted(); - m_loadVisuallyCommittedState = NotCommitted; - } + m_adapterClient->didFirstVisuallyNonEmptyPaint(); } -QSGNode *RenderWidgetHostViewQt::updatePaintNode(QSGNode *oldNode) +Compositor::Id RenderWidgetHostViewQt::compositorId() { - return m_displayFrameSink->updatePaintNode(oldNode, m_delegate.get()); + return m_uiCompositor->frame_sink_id(); } void RenderWidgetHostViewQt::notifyShown() diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h index 42c44b007..7ed01f424 100644 --- a/src/core/render_widget_host_view_qt.h +++ b/src/core/render_widget_host_view_qt.h @@ -40,7 +40,7 @@ #ifndef RENDER_WIDGET_HOST_VIEW_QT_H #define RENDER_WIDGET_HOST_VIEW_QT_H -#include "compositor/display_frame_sink.h" +#include "compositor/compositor.h" #include "delegated_frame_host_client_qt.h" #include "render_widget_host_view_qt_delegate.h" @@ -81,15 +81,8 @@ class RenderWidgetHostViewQt , public ui::GestureProviderClient , public base::SupportsWeakPtr<RenderWidgetHostViewQt> , public content::TextInputManager::Observer - , public DisplayConsumer { public: - enum LoadVisuallyCommittedState { - NotCommitted, - DidFirstVisuallyNonEmptyPaint, - DidFirstCompositorFrameSwap - }; - RenderWidgetHostViewQt(content::RenderWidgetHost* widget); ~RenderWidgetHostViewQt(); @@ -172,11 +165,8 @@ public: // Overridden from content::RenderFrameMetadataProvider::Observer void OnRenderFrameMetadataChangedAfterActivation() override; - // Overridden from DisplayConsumer - void scheduleUpdate() override; - // Called from RenderWidgetHostViewQtDelegateClient. - QSGNode *updatePaintNode(QSGNode *); + Compositor::Id compositorId(); void notifyShown(); void notifyHidden(); bool updateScreenInfo(); @@ -205,7 +195,6 @@ private: bool isPopup() const; content::RenderFrameHost *getFocusedFrameHost(); - void callUpdate(); scoped_refptr<base::SingleThreadTaskRunner> m_taskRunner; ui::FilteredGestureProvider m_gestureProvider; @@ -221,14 +210,12 @@ private: gfx::Vector2dF m_lastScrollOffset; gfx::SizeF m_lastContentsSize; DelegatedFrameHostClientQt m_delegatedFrameHostClient { this }; - LoadVisuallyCommittedState m_loadVisuallyCommittedState = NotCommitted; // VIZ content::ScreenInfo m_screenInfo; std::unique_ptr<content::DelegatedFrameHost> m_delegatedFrameHost; std::unique_ptr<ui::Layer> m_rootLayer; std::unique_ptr<ui::Compositor> m_uiCompositor; - scoped_refptr<DisplayFrameSink> m_displayFrameSink; viz::ParentLocalSurfaceIdAllocator m_dfhLocalSurfaceIdAllocator; viz::ParentLocalSurfaceIdAllocator m_uiCompositorLocalSurfaceIdAllocator; diff --git a/src/core/render_widget_host_view_qt_delegate.h b/src/core/render_widget_host_view_qt_delegate.h index 0afe258f1..f5227bd52 100644 --- a/src/core/render_widget_host_view_qt_delegate.h +++ b/src/core/render_widget_host_view_qt_delegate.h @@ -59,13 +59,8 @@ #include <QtGui/QImage> QT_BEGIN_NAMESPACE -class QSGImageNode; -class QSGLayer; -class QSGRectangleNode; -class QSGTexture; class QWheelEvent; class QWindow; - QT_END_NAMESPACE namespace QtWebEngineCore { @@ -84,11 +79,6 @@ public: virtual void hide() = 0; virtual bool isVisible() const = 0; virtual QWindow* window() const = 0; - virtual QSGTexture *createTextureFromImage(const QImage &) = 0; - virtual QSGLayer *createLayer() = 0; - virtual QSGImageNode *createImageNode() = 0; - virtual QSGRectangleNode *createRectangleNode() = 0; - virtual void update() = 0; virtual void updateCursor(const QCursor &) = 0; virtual void resize(int width, int height) = 0; virtual void move(const QPoint &) = 0; diff --git a/src/core/render_widget_host_view_qt_delegate_client.cpp b/src/core/render_widget_host_view_qt_delegate_client.cpp index d7674fd13..bee4bc4c2 100644 --- a/src/core/render_widget_host_view_qt_delegate_client.cpp +++ b/src/core/render_widget_host_view_qt_delegate_client.cpp @@ -204,9 +204,9 @@ RenderWidgetHostViewQtDelegateClient::RenderWidgetHostViewQtDelegateClient( context && context->hasCapability(QPlatformInputContext::HiddenTextCapability); } -QSGNode *RenderWidgetHostViewQtDelegateClient::updatePaintNode(QSGNode *oldNode) +Compositor::Id RenderWidgetHostViewQtDelegateClient::compositorId() { - return m_rwhv->updatePaintNode(oldNode); + return m_rwhv->compositorId(); } void RenderWidgetHostViewQtDelegateClient::notifyShown() diff --git a/src/core/render_widget_host_view_qt_delegate_client.h b/src/core/render_widget_host_view_qt_delegate_client.h index bb14fe951..f67bed861 100644 --- a/src/core/render_widget_host_view_qt_delegate_client.h +++ b/src/core/render_widget_host_view_qt_delegate_client.h @@ -51,14 +51,13 @@ #ifndef RENDER_WIDGET_HOST_VIEW_QT_DELEGATE_CLIENT_H #define RENDER_WIDGET_HOST_VIEW_QT_DELEGATE_CLIENT_H -#include "qtwebenginecoreglobal_p.h" +#include "compositor/compositor.h" #include <QtGui/QCursor> #include <QtGui/QTouchEvent> QT_BEGIN_NAMESPACE class QEvent; -class QSGNode; class QVariant; class QMouseEvent; @@ -88,7 +87,7 @@ class Q_WEBENGINECORE_PRIVATE_EXPORT RenderWidgetHostViewQtDelegateClient public: RenderWidgetHostViewQtDelegateClient(RenderWidgetHostViewQt *rwhv); - QSGNode *updatePaintNode(QSGNode *); + Compositor::Id compositorId(); void notifyShown(); void notifyHidden(); void visualPropertiesChanged(); diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h index 04df99f0e..78040cc8d 100644 --- a/src/core/web_contents_adapter_client.h +++ b/src/core/web_contents_adapter_client.h @@ -465,7 +465,7 @@ public: virtual QColor backgroundColor() const = 0; virtual void loadStarted(const QUrl &provisionalUrl, bool isErrorPage = false) = 0; virtual void loadCommitted() = 0; - virtual void loadVisuallyCommitted() = 0; + virtual void didFirstVisuallyNonEmptyPaint() = 0; virtual void loadFinished(bool success, const QUrl &url, bool isErrorPage = false, int errorCode = 0, const QString &errorDescription = QString()) = 0; virtual void focusContainer() = 0; virtual void unhandledKeyEvent(QKeyEvent *event) = 0; diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index 7fddb16a9..8a426c887 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -482,11 +482,29 @@ void QQuickWebEngineViewPrivate::loadCommitted() m_history->reset(); } -void QQuickWebEngineViewPrivate::loadVisuallyCommitted() +void QQuickWebEngineViewPrivate::didFirstVisuallyNonEmptyPaint() { #if QT_CONFIG(webengine_testsupport) - if (m_testSupport) - Q_EMIT m_testSupport->loadVisuallyCommitted(); + if (m_loadVisuallyCommittedState == NotCommitted) { + m_loadVisuallyCommittedState = DidFirstVisuallyNonEmptyPaint; + } else if (m_loadVisuallyCommittedState == DidFirstCompositorFrameSwap) { + if (m_testSupport) + Q_EMIT m_testSupport->loadVisuallyCommitted(); + m_loadVisuallyCommittedState = NotCommitted; + } +#endif +} + +void QQuickWebEngineViewPrivate::didCompositorFrameSwap() +{ +#if QT_CONFIG(webengine_testsupport) + if (m_loadVisuallyCommittedState == NotCommitted) { + m_loadVisuallyCommittedState = DidFirstCompositorFrameSwap; + } else if (m_loadVisuallyCommittedState == DidFirstVisuallyNonEmptyPaint) { + if (m_testSupport) + Q_EMIT m_testSupport->loadVisuallyCommitted(); + m_loadVisuallyCommittedState = NotCommitted; + } #endif } diff --git a/src/webengine/api/qquickwebengineview_p.h b/src/webengine/api/qquickwebengineview_p.h index 9dbb8cffc..86b7145db 100644 --- a/src/webengine/api/qquickwebengineview_p.h +++ b/src/webengine/api/qquickwebengineview_p.h @@ -59,6 +59,10 @@ #include "qquickwebengineprofile.h" #include "qquickwebenginescript.h" +namespace QtWebEngineCore { +class RenderWidgetHostViewQtDelegateQuick; +} + QT_BEGIN_NAMESPACE class QQmlWebChannel; @@ -603,6 +607,7 @@ private: Q_DECLARE_PRIVATE(QQuickWebEngineView) QScopedPointer<QQuickWebEngineViewPrivate> d_ptr; + friend class QtWebEngineCore::RenderWidgetHostViewQtDelegateQuick; friend class QQuickContextMenuBuilder; friend class QQuickWebEngineNewViewRequest; friend class QQuickWebEngineFaviconProvider; diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h index 68d65410a..bfed75f45 100644 --- a/src/webengine/api/qquickwebengineview_p_p.h +++ b/src/webengine/api/qquickwebengineview_p_p.h @@ -115,7 +115,7 @@ public: QColor backgroundColor() const override; void loadStarted(const QUrl &provisionalUrl, bool isErrorPage = false) override; void loadCommitted() override; - void loadVisuallyCommitted() override; + void didFirstVisuallyNonEmptyPaint() override; void loadFinished(bool success, const QUrl &url, bool isErrorPage = false, int errorCode = 0, const QString &errorDescription = QString()) override; void focusContainer() override; void unhandledKeyEvent(QKeyEvent *event) override; @@ -173,6 +173,8 @@ public: void widgetChanged(QtWebEngineCore::RenderWidgetHostViewQtDelegate *newWidgetBase) override; void findTextFinished(const QWebEngineFindTextResult &result) override; + void didCompositorFrameSwap(); + void updateAction(QQuickWebEngineView::WebAction) const; void adoptWebContents(QtWebEngineCore::WebContentsAdapter *webContents); void setProfile(QQuickWebEngineProfile *profile); @@ -223,12 +225,19 @@ public: bool profileInitialized() const; private: + enum LoadVisuallyCommittedState { + NotCommitted, + DidFirstVisuallyNonEmptyPaint, + DidFirstCompositorFrameSwap + }; + QScopedPointer<QtWebEngineCore::UIDelegatesManager> m_uIDelegatesManager; QList<QQuickWebEngineScript *> m_userScripts; QColor m_backgroundColor; qreal m_zoomFactor; bool m_ui2Enabled; bool m_profileInitialized; + LoadVisuallyCommittedState m_loadVisuallyCommittedState = NotCommitted; }; #ifndef QT_NO_ACCESSIBILITY diff --git a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp index c0d4dd4a5..9ed660f2e 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp @@ -85,10 +85,12 @@ RenderWidgetHostViewQtDelegateQuick::RenderWidgetHostViewQtDelegateQuick(RenderW } #endif + bind(client->compositorId()); } RenderWidgetHostViewQtDelegateQuick::~RenderWidgetHostViewQtDelegateQuick() { + unbind(); QQuickWebEngineViewPrivate::bindViewAndWidget(nullptr, this); } @@ -167,30 +169,10 @@ QWindow* RenderWidgetHostViewQtDelegateQuick::window() const return QQuickItem::window(); } -QSGTexture *RenderWidgetHostViewQtDelegateQuick::createTextureFromImage(const QImage &image) +void RenderWidgetHostViewQtDelegateQuick::readyToSwap() { - return QQuickItem::window()->createTextureFromImage(image, QQuickWindow::TextureCanUseAtlas); -} - -QSGLayer *RenderWidgetHostViewQtDelegateQuick::createLayer() -{ - QSGRenderContext *renderContext = QQuickWindowPrivate::get(QQuickItem::window())->context; - return renderContext->sceneGraphContext()->createLayer(renderContext); -} - -QSGImageNode *RenderWidgetHostViewQtDelegateQuick::createImageNode() -{ - return QQuickItem::window()->createImageNode(); -} - -QSGRectangleNode *RenderWidgetHostViewQtDelegateQuick::createRectangleNode() -{ - return QQuickItem::window()->createRectangleNode(); -} - -void RenderWidgetHostViewQtDelegateQuick::update() -{ - QQuickItem::update(); + // Call update() on UI thread. + QMetaObject::invokeMethod(this, &QQuickItem::update, Qt::QueuedConnection); } void RenderWidgetHostViewQtDelegateQuick::updateCursor(const QCursor &cursor) @@ -345,6 +327,8 @@ void RenderWidgetHostViewQtDelegateQuick::itemChange(ItemChange change, const It disconnect(c); m_windowConnections.clear(); if (value.window) { + m_windowConnections.append(connect(value.window, SIGNAL(beforeRendering()), + SLOT(onBeforeRendering()), Qt::DirectConnection)); m_windowConnections.append(connect(value.window, SIGNAL(xChanged(int)), SLOT(onWindowPosChanged()))); m_windowConnections.append(connect(value.window, SIGNAL(yChanged(int)), SLOT(onWindowPosChanged()))); if (!m_isPopup) @@ -359,7 +343,58 @@ void RenderWidgetHostViewQtDelegateQuick::itemChange(ItemChange change, const It QSGNode *RenderWidgetHostViewQtDelegateQuick::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) { - return m_client->updatePaintNode(oldNode); + auto comp = compositor(); + if (!comp) + return nullptr; + + QQuickWindow *win = QQuickItem::window(); + + // Delete old node before swapFrame to decrement refcount of + // QImage in software mode. + delete oldNode; + QSGImageNode *node = win->createImageNode(); + node->setOwnsTexture(true); + + comp->swapFrame(); + + if (comp->type() == Compositor::Type::Software) { + QImage image = comp->image(); + float pixPerDip = comp->devicePixelRatio(); + QSizeF sizeInDips = QSizeF(image.size()) / pixPerDip; + node->setRect(QRectF(QPointF(0, 0), sizeInDips)); + node->setTexture(win->createTextureFromImage(image)); + } else if (comp->type() == Compositor::Type::OpenGL) { + QSize texSize = comp->textureSize(); + float pixPerDip = comp->devicePixelRatio(); + QSizeF sizeInDips = QSizeF(texSize) / pixPerDip; + node->setRect(QRectF(QPointF(0, 0), sizeInDips)); + QQuickWindow::CreateTextureOptions texOpts; + if (comp->hasAlphaChannel()) + texOpts.setFlag(QQuickWindow::TextureHasAlphaChannel); + int texId = comp->textureId(); + node->setTexture(win->createTextureFromNativeObject(QQuickWindow::NativeObjectTexture, + texId, 0, texSize, texOpts)); + node->setTextureCoordinatesTransform(QSGImageNode::MirrorVertically); + } else { + Q_UNREACHABLE(); + } + +#if QT_CONFIG(webengine_testsupport) + if (m_view) + QMetaObject::invokeMethod( + m_view, [view = m_view]() { view->d_ptr->didCompositorFrameSwap(); }, + Qt::QueuedConnection); +#endif + + return node; +} + +void RenderWidgetHostViewQtDelegateQuick::onBeforeRendering() +{ + auto comp = compositor(); + if (!comp || comp->type() != Compositor::Type::OpenGL) + return; + comp->waitForTexture(); } void RenderWidgetHostViewQtDelegateQuick::onWindowPosChanged() diff --git a/src/webengine/render_widget_host_view_qt_delegate_quick.h b/src/webengine/render_widget_host_view_qt_delegate_quick.h index feea10017..cb38ebd20 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.h +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.h @@ -40,6 +40,7 @@ #ifndef RENDER_WIDGET_HOST_VIEW_QT_DELEGATE_QUICK_H #define RENDER_WIDGET_HOST_VIEW_QT_DELEGATE_QUICK_H +#include "compositor/compositor.h" #include "render_widget_host_view_qt_delegate.h" #include <QAccessibleObject> @@ -55,7 +56,9 @@ namespace QtWebEngineCore { class RenderWidgetHostViewQtDelegateClient; -class RenderWidgetHostViewQtDelegateQuick : public QQuickItem, public RenderWidgetHostViewQtDelegate +class RenderWidgetHostViewQtDelegateQuick : public QQuickItem, + public RenderWidgetHostViewQtDelegate, + public Compositor::Observer { Q_OBJECT public: @@ -73,11 +76,6 @@ public: void hide() override; bool isVisible() const override; QWindow* window() const override; - QSGTexture *createTextureFromImage(const QImage &) override; - QSGLayer *createLayer() override; - QSGImageNode *createImageNode() override; - QSGRectangleNode *createRectangleNode() override; - void update() override; void updateCursor(const QCursor &) override; void resize(int width, int height) override; void move(const QPoint&) override { } @@ -87,6 +85,8 @@ public: void setClearColor(const QColor &) override { } bool copySurface(const QRect &rect, const QSize &size, QImage &image) override; + void readyToSwap() override; + protected: bool event(QEvent *event) override; void focusInEvent(QFocusEvent *event) override; @@ -107,6 +107,7 @@ protected: QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override; private slots: + void onBeforeRendering(); void onWindowPosChanged(); void onHide(); diff --git a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp index 1de4d8835..0b7e736ad 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp +++ b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp @@ -121,32 +121,6 @@ QWindow *RenderWidgetHostViewQtDelegateQuickWindow::window() const return const_cast<RenderWidgetHostViewQtDelegateQuickWindow*>(this); } -QSGTexture *RenderWidgetHostViewQtDelegateQuickWindow::createTextureFromImage(const QImage &image) -{ - return m_realDelegate->createTextureFromImage(image); -} - -QSGLayer *RenderWidgetHostViewQtDelegateQuickWindow::createLayer() -{ - return m_realDelegate->createLayer(); -} - -QSGImageNode *RenderWidgetHostViewQtDelegateQuickWindow::createImageNode() -{ - return m_realDelegate->createImageNode(); -} - -QSGRectangleNode *RenderWidgetHostViewQtDelegateQuickWindow::createRectangleNode() -{ - return m_realDelegate->createRectangleNode(); -} - -void RenderWidgetHostViewQtDelegateQuickWindow::update() -{ - QQuickWindow::update(); - m_realDelegate->update(); -} - void RenderWidgetHostViewQtDelegateQuickWindow::updateCursor(const QCursor &cursor) { setCursor(cursor); diff --git a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h index bebbfa439..cff189d1c 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h +++ b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h @@ -66,11 +66,6 @@ public: void hide() override; bool isVisible() const override; QWindow* window() const override; - QSGTexture *createTextureFromImage(const QImage &) override; - QSGLayer *createLayer() override; - QSGImageNode *createImageNode() override; - QSGRectangleNode *createRectangleNode() override; - void update() override; void updateCursor(const QCursor &) override; void resize(int width, int height) override; void move(const QPoint &screenPos) override; diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h index 3ddf4b3d6..847684198 100644 --- a/src/webenginewidgets/api/qwebenginepage_p.h +++ b/src/webenginewidgets/api/qwebenginepage_p.h @@ -106,7 +106,7 @@ public: QColor backgroundColor() const override; void loadStarted(const QUrl &provisionalUrl, bool isErrorPage = false) override; void loadCommitted() override { } - void loadVisuallyCommitted() override { } + void didFirstVisuallyNonEmptyPaint() override { } void loadFinished(bool success, const QUrl &url, bool isErrorPage = false, int errorCode = 0, const QString &errorDescription = QString()) override; void focusContainer() override; void unhandledKeyEvent(QKeyEvent *event) override; diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp index a52fdef00..853553c47 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp @@ -56,14 +56,19 @@ namespace QtWebEngineCore { -class RenderWidgetHostViewQuickItem : public QQuickItem { +class RenderWidgetHostViewQuickItem : public QQuickItem, public Compositor::Observer +{ public: RenderWidgetHostViewQuickItem(RenderWidgetHostViewQtDelegateClient *client) : m_client(client) { setFlag(ItemHasContents, true); // Mark that this item should receive focus when the parent QQuickWidget receives focus. setFocus(true); + + bind(client->compositorId()); } + ~RenderWidgetHostViewQuickItem() { unbind(); } + protected: bool event(QEvent *event) override { @@ -84,17 +89,80 @@ protected: { m_client->forwardEvent(event); } - QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) override + void itemChange(ItemChange change, const ItemChangeData &value) override { - return m_client->updatePaintNode(oldNode); + QQuickItem::itemChange(change, value); + if (change == QQuickItem::ItemSceneChange) { + for (const QMetaObject::Connection &c : qAsConst(m_windowConnections)) + disconnect(c); + m_windowConnections.clear(); + if (value.window) { + m_windowConnections.append(connect( + value.window, &QQuickWindow::beforeRendering, this, + &RenderWidgetHostViewQuickItem::onBeforeRendering, Qt::DirectConnection)); + } + } } + QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) override + { + auto comp = compositor(); + if (!comp) + return nullptr; + + QQuickWindow *win = QQuickItem::window(); + + // Delete old node before swapFrame to decrement refcount of + // QImage in software mode. + delete oldNode; + QSGImageNode *node = win->createImageNode(); + node->setOwnsTexture(true); + + comp->swapFrame(); + + if (comp->type() == Compositor::Type::Software) { + QImage image = comp->image(); + float pixPerDip = comp->devicePixelRatio(); + QSizeF sizeInDips = QSizeF(image.size()) / pixPerDip; + node->setRect(QRectF(QPointF(0, 0), sizeInDips)); + node->setTexture(win->createTextureFromImage(image)); + } else if (comp->type() == Compositor::Type::OpenGL) { + QSize texSize = comp->textureSize(); + float pixPerDip = comp->devicePixelRatio(); + QSizeF sizeInDips = QSizeF(texSize) / pixPerDip; + node->setRect(QRectF(QPointF(0, 0), sizeInDips)); + QQuickWindow::CreateTextureOptions texOpts; + if (comp->hasAlphaChannel()) + texOpts.setFlag(QQuickWindow::TextureHasAlphaChannel); + int texId = comp->textureId(); + node->setTexture(win->createTextureFromNativeObject(QQuickWindow::NativeObjectTexture, + texId, 0, texSize, texOpts)); + node->setTextureCoordinatesTransform(QSGImageNode::MirrorVertically); + } else { + Q_UNREACHABLE(); + } + return node; + } + void onBeforeRendering() + { + auto comp = compositor(); + if (!comp || comp->type() != Compositor::Type::OpenGL) + return; + comp->waitForTexture(); + } QVariant inputMethodQuery(Qt::InputMethodQuery query) const override { return m_client->inputMethodQuery(query); } + void readyToSwap() override + { + // Call update() on UI thread. + QMetaObject::invokeMethod(this, &QQuickItem::update, Qt::QueuedConnection); + } + private: RenderWidgetHostViewQtDelegateClient *m_client; + QList<QMetaObject::Connection> m_windowConnections; }; RenderWidgetHostViewQtDelegateWidget::RenderWidgetHostViewQtDelegateWidget(RenderWidgetHostViewQtDelegateClient *client, QWidget *parent) @@ -293,32 +361,6 @@ QWindow* RenderWidgetHostViewQtDelegateWidget::window() const return root ? root->windowHandle() : 0; } -QSGTexture *RenderWidgetHostViewQtDelegateWidget::createTextureFromImage(const QImage &image) -{ - return quickWindow()->createTextureFromImage(image, QQuickWindow::TextureCanUseAtlas); -} - -QSGLayer *RenderWidgetHostViewQtDelegateWidget::createLayer() -{ - QSGRenderContext *renderContext = QQuickWindowPrivate::get(quickWindow())->context; - return renderContext->sceneGraphContext()->createLayer(renderContext); -} - -QSGImageNode *RenderWidgetHostViewQtDelegateWidget::createImageNode() -{ - return quickWindow()->createImageNode(); -} - -QSGRectangleNode *RenderWidgetHostViewQtDelegateWidget::createRectangleNode() -{ - return quickWindow()->createRectangleNode(); -} - -void RenderWidgetHostViewQtDelegateWidget::update() -{ - m_rootItem->update(); -} - void RenderWidgetHostViewQtDelegateWidget::updateCursor(const QCursor &cursor) { QQuickWidget::setCursor(cursor); diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h index 034fdd65c..57b272183 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h @@ -79,11 +79,6 @@ public: void hide() override; bool isVisible() const override; QWindow* window() const override; - QSGTexture *createTextureFromImage(const QImage &) override; - QSGLayer *createLayer() override; - QSGImageNode *createImageNode() override; - QSGRectangleNode *createRectangleNode() override; - void update() override; void updateCursor(const QCursor &) override; void resize(int width, int height) override; void move(const QPoint &screenPos) override; |