Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
sharedtextureprovider.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4
6
7#include <QFile>
8#include <QDebug>
9#include <qopenglfunctions.h>
10#include <QQuickWindow>
11
12#include <QtWaylandClient/private/qwaylandintegration_p.h>
13#include <QtWaylandClient/private/qwaylandserverbufferintegration_p.h>
14#include <QtGui/QGuiApplication>
15#include <QtGui/private/qguiapplication_p.h>
16#include <QtQuick/private/qsgrhisupport_p.h>
17#include <QtGui/qpa/qplatformnativeinterface.h>
18#include <QtGui/QWindow>
19#include <QOpenGLTexture>
20#include <QImageReader>
21
22#include <QTimer>
23
25
27
29{
30public:
32 : m_buffer(buffer), m_id(id), m_registry(registry)
33 {
34 }
35
37 {
38 //qDebug() << "====> DESTRUCTOR SharedTextureFactory" << this;
39 if (m_registry)
40 m_registry->abandonBuffer(m_id);
41 delete m_buffer; // TODO: make sure we are not keeping references to this elsewhere
42 //qDebug() << "buffer deleted";
43 }
44
45 QSize textureSize() const override
46 {
47 return m_buffer ? m_buffer->size() : QSize();
48 }
49
50 int textureByteCount() const override
51 {
52 return m_buffer ? (m_buffer->size().width() * m_buffer->size().height() * 4) : 0;
53 }
54
56 {
57 if (m_buffer != nullptr) {
58 QOpenGLTexture *texture = const_cast<QtWaylandClient::QWaylandServerBuffer *>(m_buffer)->toOpenGlTexture();
59 return QNativeInterface::QSGOpenGLTexture::fromNative(texture->textureId(),
60 window,
61 m_buffer->size(),
62 QQuickWindow::TextureHasAlphaChannel);
63 }
64 return nullptr;
65 }
66
67private:
68 const QtWaylandClient::QWaylandServerBuffer *m_buffer = nullptr;
69 QString m_id;
71};
72
73
75 : m_extension(new TextureSharingExtension)
76{
78 connect(m_extension, &TextureSharingExtension::activeChanged, this, &SharedTextureRegistry::handleExtensionActive);
79}
80
82{
83 delete m_extension;
84}
85
87{
88 return m_buffers.value(id);
89}
90
92{
93 if (!m_extension->isActive()) {
94 //qDebug() << "Extension not active, adding" << id << "to queue";
95 m_pendingBuffers << id;
96 return;
97 }
98 m_extension->requestImage(id);
99}
100
102{
103 m_buffers.remove(id);
104 m_extension->abandonImage(id);
105}
106
107
108void SharedTextureRegistry::handleExtensionActive()
109{
110 //qDebug() << "handleExtensionActive, queue:" << m_pendingBuffers;
111 if (m_extension->isActive())
112 while (!m_pendingBuffers.isEmpty())
113 requestBuffer(m_pendingBuffers.takeFirst());
114}
115
117{
118 if (QSGRhiSupport::instance()->rhiBackend() != QRhi::OpenGLES2) {
119 qWarning() << "The shared-texture extension is only supported on OpenGL. Use QQuickWindow::setSceneGraphBackend() to override the default.";
120 return false;
121 }
122
123 auto *serverBufferIntegration = QGuiApplicationPrivate::platformIntegration()->nativeInterface()->nativeResourceForIntegration("server_buffer_integration");
124
125 if (!serverBufferIntegration) {
126 qWarning() << "Wayland Server Buffer Integration not available.";
127 return false;
128 }
129
130 return true;
131}
132
134{
135 //qDebug() << "ReceiveBuffer for id" << id;
136 if (buffer)
137 m_buffers.insert(id, buffer);
139}
140
142{
144public:
146 : m_id(id), m_registry(registry)
147 {
148 if (!m_registry || m_registry->bufferForId(id)) {
149 // Shortcut: no server roundtrip needed, just let the event loop call the slot
151
152 } else {
153 // TBD: timeout?
155 registry->requestBuffer(id);
156 }
157 }
158
160 {
161 if (m_registry) {
163 if (buffer) {
164 //qDebug() << "Creating shared buffer texture for" << m_id;
165 return new SharedTextureFactory(buffer, m_id, m_registry);
166 }
167 //qDebug() << "Shared buffer NOT found for" << m_id;
168 }
169
170 // No shared buffer, do fallback
171 QString fbPath = fallbackPath();
172 if (fbPath.isEmpty()) {
173 m_errorString = QStringLiteral("Shared buffer not found, and no fallback path set.");
174 return nullptr;
175 }
176
177 QImageReader reader(fbPath + m_id);
178 QImage img = reader.read();
179 if (img.isNull()) {
180 qWarning() << "Could not load local image from id/path" << reader.fileName();
181 m_errorString = QStringLiteral("Shared buffer not found, and fallback local file loading failed: ") + reader.errorString();
182 return nullptr;
183 }
185 }
186
187 QString errorString() const override
188 {
189 return m_errorString;
190 }
191
193 {
194 static QString fbPath;
195 static bool isInit = false;
196 if (!isInit) {
197 isInit = true;
198 QByteArray envVal = qgetenv("QT_SHAREDTEXTURE_FALLBACK_DIR");
199 if (!envVal.isEmpty()) {
200 fbPath = QString::fromLocal8Bit(envVal);
201 if (!fbPath.endsWith(QLatin1Char('/')))
202 fbPath.append(QLatin1Char('/'));
203 }
204 }
205 return fbPath;
206 }
207
208
209public slots:
210 void doResponse(const QString &key) {
211 if (key != m_id)
212 return; // not our buffer
213
214 // No need to be called again
215 if (m_registry)
217
218 emit finished();
219 }
220
221private:
222 QString m_id;
223 SharedTextureRegistry *m_registry = nullptr;
224 mutable QString m_errorString;
225};
226
227
229{
230 m_sharingAvailable = SharedTextureRegistry::preinitialize();
231 if (!m_sharingAvailable) {
233 qWarning() << "Shared buffer images not available, and no fallback directory set.";
234 else
235 qWarning() << "Shared buffer images not available, will fallback to local image files from" << SharedTextureImageResponse::fallbackPath();
236 }
237}
238
240{
241 delete m_registry;
242}
243
245{
246 Q_UNUSED(requestedSize);
247
248 //qDebug() << "Provider: got request for" << id;
249
250 if (m_sharingAvailable && !m_registry)
251 m_registry = new SharedTextureRegistry;
252
253 return new SharedTextureImageResponse(m_registry, id);
254}
255
257
258#include "moc_sharedtextureprovider_p.cpp"
259
260#include "sharedtextureprovider.moc"
\inmodule QtCore
Definition qbytearray.h:57
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
Definition qbytearray.h:106
static QPlatformIntegration * platformIntegration()
bool remove(const Key &key)
Removes the item that has the key from the hash.
Definition qhash.h:956
T value(const Key &key) const noexcept
Definition qhash.h:1044
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1283
The QImageReader class provides a format independent interface for reading images from files or other...
QString errorString() const
Returns a human readable description of the last error that occurred.
QString fileName() const
If the currently assigned device is a QFile, or if setFileName() has been called, this function retur...
QImage read()
Reads an image from the device.
\inmodule QtGui
Definition qimage.h:37
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
\inmodule QtGui
virtual QPlatformNativeInterface * nativeInterface() const
virtual void * nativeResourceForIntegration(const QByteArray &resource)
\inmodule QtCore
Definition qpointer.h:18
The QQuickImageResponse class provides an interface for asynchronous image loading in QQuickAsyncImag...
void finished()
Signals that the job execution has finished (be it successfully, because an error happened or because...
The QQuickTextureFactory class provides an interface for loading custom textures from QML....
static QQuickTextureFactory * textureFactoryForImage(const QImage &image)
Returns a QQuickTextureFactory holding the given image.
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
@ OpenGLES2
Definition qrhi.h:1772
static QSGRhiSupport * instance()
\inmodule QtQuick
Definition qsgtexture.h:20
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:132
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:129
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5788
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition qstring.cpp:5350
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
QString & append(QChar c)
Definition qstring.cpp:3227
QSGTexture * createTexture(QQuickWindow *window) const override
This function is called on the scene graph rendering thread to create a QSGTexture instance from the ...
SharedTextureFactory(const QtWaylandClient::QWaylandServerBuffer *buffer, const QString &id, SharedTextureRegistry *registry)
QSize textureSize() const override
Returns the size of the texture.
int textureByteCount() const override
Returns the number of bytes of memory the texture consumes.
void doResponse(const QString &key, QtWayland::ServerBuffer *buffer)
void doResponse(const QString &key)
QString errorString() const override
Returns the error string for the job execution.
SharedTextureImageResponse(SharedTextureRegistry *registry, const QString &id)
QQuickTextureFactory * textureFactory() const override
Returns the texture factory for the job.
QQuickImageResponse * requestImageResponse(const QString &id, const QSize &requestedSize) override
Implement this method to return the job that will provide the texture with id.
const QtWaylandClient::QWaylandServerBuffer * bufferForId(const QString &id) const
void receiveBuffer(QtWaylandClient::QWaylandServerBuffer *buffer, const QString &id)
void abandonBuffer(const QString &id)
void requestBuffer(const QString &id)
void replyReceived(const QString &id)
void abandonImage(const QString &key)
void requestImage(const QString &key)
void bufferReceived(QtWaylandClient::QWaylandServerBuffer *buffer, const QString &key)
Combined button and popup list for selecting options.
@ QueuedConnection
#define qWarning
Definition qlogging.h:162
#define Q_ARG(Type, data)
Definition qobjectdefs.h:62
GLuint64 key
GLenum GLuint id
[7]
GLenum GLuint buffer
GLenum GLuint texture
GLint void * img
Definition qopenglext.h:233
#define QStringLiteral(str)
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
#define Q_OBJECT
#define slots
#define emit
#define Q_UNUSED(x)
myObject disconnect()
[26]
aWidget window() -> setWindowTitle("New Window Title")
[2]
\inmodule QtCore \reentrant
Definition qchar.h:17
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
\threadsafe This is an overloaded member function, provided for convenience. It differs from the abov...