Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qwltexturesharingextension.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
5
6#include <QWaylandSurface>
7
8#include <QDebug>
9
10#include <QQuickWindow>
11
12#include <QPainter>
13#include <QPen>
14#include <QTimer>
15
16#include <QtGui/private/qtexturefilereader_p.h>
17
18#include <QtOpenGL/QOpenGLTexture>
19#include <QtGui/QImageReader>
20
21#include <QtQuick/QSGTexture>
22#include <QQmlContext>
23#include <QThread>
24
26
28{
29public:
34
36 {
37 if (m_buffer && !QCoreApplication::closingDown())
38 const_cast<QtWayland::ServerBuffer*>(m_buffer)->releaseOpenGlTexture();
39 }
40
41 QSize textureSize() const override
42 {
43 return m_buffer ? m_buffer->size() : QSize();
44 }
45
46 int textureByteCount() const override
47 {
48 return m_buffer ? (m_buffer->size().width() * m_buffer->size().height() * 4) : 0;
49 }
50
52 {
53 if (m_buffer != nullptr) {
54 QOpenGLTexture *texture = const_cast<QtWayland::ServerBuffer *>(m_buffer)->toOpenGlTexture();
55 return QNativeInterface::QSGOpenGLTexture::fromNative(texture->textureId(),
56 window,
57 m_buffer->size(),
58 QQuickWindow::TextureHasAlphaChannel);
59 }
60
61 return nullptr;
62 }
63
64private:
65 const QtWayland::ServerBuffer *m_buffer = nullptr;
66};
67
69{
71public:
78
85
87 {
88 if (m_buffer) {
89// qDebug() << "Creating shared buffer texture for" << m_id;
90 return new SharedTextureFactory(m_buffer);
91 }
92// qDebug() << "Shared buffer NOT found for" << m_id;
93 m_errorString = QLatin1String("Shared buffer not found");
94 return nullptr;
95 }
96
97 QString errorString() const override
98 {
99 return m_errorString;
100 }
101
102public Q_SLOTS:
104 {
105 if (key != m_id)
106 return; //somebody else's texture
107
108 m_buffer = buffer;
109
110 if (m_extension)
112
113 emit finished();
114 }
115
116private:
117 QString m_id;
118 QWaylandTextureSharingExtension *m_extension = nullptr;
119 mutable QString m_errorString;
120 QtWayland::ServerBuffer *m_buffer = nullptr;
121};
122
126
130
132{
133 Q_UNUSED(requestedSize);
134
135// qDebug() << "Provider: got request for" << id;
136
138 auto *response = new SharedTextureImageResponse(extension, id);
139 if (!extension)
140 m_pendingResponses << response;
141
142 return response;
143}
144
146{
147 for (auto *response : std::as_const(m_pendingResponses))
148 response->doRequest(extension);
149 m_pendingResponses.clear();
150 m_pendingResponses.squeeze();
151}
152
153QWaylandTextureSharingExtension *QWaylandTextureSharingExtension::s_self = nullptr; // theoretical race conditions, but OK as long as we don't delete it while we are running
154
159
165
167{
168 //qDebug() << Q_FUNC_INFO;
169 //dumpBufferInfo();
170
171 for (auto b : m_server_buffers)
172 delete b.buffer;
173
174 if (s_self == this)
175 s_self = nullptr;
176}
177
179{
180 m_image_dirs = path.split(QLatin1Char(';'));
181
182 for (auto it = m_image_dirs.begin(); it != m_image_dirs.end(); ++it)
183 if (!(*it).endsWith(QLatin1Char('/')))
184 (*it) += QLatin1Char('/');
185}
186
188{
191 init(compositor->display(), 1);
192
193 QString image_search_path = qEnvironmentVariable("QT_WAYLAND_SHAREDTEXTURE_SEARCH_PATH");
194 if (!image_search_path.isEmpty())
195 setImageSearchPath(image_search_path);
196
197 if (m_image_dirs.isEmpty())
198 m_image_dirs << QLatin1String(":/") << QLatin1String("./");
199
201 suffixes.append(QImageReader::supportedImageFormats());
202 for (auto ext : std::as_const(suffixes))
203 m_image_suffixes << QLatin1Char('.') + QString::fromLatin1(ext);
204
205 //qDebug() << "m_image_suffixes" << m_image_suffixes << "m_image_dirs" << m_image_dirs;
206
207 auto *ctx = QQmlEngine::contextForObject(this);
208 if (ctx) {
209 QQmlEngine *engine = ctx->engine();
210 if (engine) {
211 auto *provider = static_cast<QWaylandSharedTextureProvider*>(engine->imageProvider(QLatin1String("wlshared")));
212 if (provider)
213 provider->setExtensionReady(this);
214 }
215 }
216}
217
218QString QWaylandTextureSharingExtension::getExistingFilePath(const QString &key) const
219{
220 // The default search path blocks absolute pathnames, but this does not prevent relative
221 // paths containing '../'. We handle that here, at the price of also blocking directory
222 // names ending with two or more dots.
223
224 if (key.contains(QLatin1String("../")))
225 return QString();
226
227 for (auto dir : std::as_const(m_image_dirs)) {
228 QString path = dir + key;
230 return path;
231 }
232
233 for (auto dir : std::as_const(m_image_dirs)) {
234 for (auto ext : m_image_suffixes) {
235 QString fp = dir + key + ext;
236 //qDebug() << "trying" << fp;
238 return fp;
239 }
240 }
241 return QString();
242}
243
244QtWayland::ServerBuffer *QWaylandTextureSharingExtension::getBuffer(const QString &key)
245{
246 if (!initServerBufferIntegration())
247 return nullptr;
248
249//qDebug() << "getBuffer" << key;
250
252
253 if ((buffer = m_server_buffers.value(key).buffer))
254 return buffer;
255
256 QByteArray pixelData;
257 QSize size;
258 uint glInternalFormat = GL_NONE;
259
260 if (customPixelData(key, &pixelData, &size, &glInternalFormat)) {
261 if (!pixelData.isEmpty()) {
262 buffer = m_server_buffer_integration->createServerBufferFromData(pixelData, size, glInternalFormat);
263 if (!buffer)
264 qWarning() << "QWaylandTextureSharingExtension: could not create buffer from custom data for key:" << key;
265 }
266 } else {
267 QString pathName = getExistingFilePath(key);
268 //qDebug() << "pathName" << pathName;
269 if (pathName.isEmpty())
270 return nullptr;
271
272 buffer = getCompressedBuffer(pathName);
273 //qDebug() << "getCompressedBuffer" << buffer;
274
275 if (!buffer) {
276 QImage img(pathName);
277 if (!img.isNull()) {
280 }
281 //qDebug() << "createServerBufferFromImage" << buffer;
282 }
283 }
284 if (buffer)
285 m_server_buffers.insert(key, BufferInfo(buffer));
286
287 //qDebug() << ">>>>" << key << buffer;
288
289 return buffer;
290}
291
292// Compositor requesting image for its own UI
294{
295 //qDebug() << "requestBuffer" << key;
296
298 qWarning("QWaylandTextureSharingExtension::requestBuffer() called from outside main thread: possible race condition");
299
300 auto *buffer = getBuffer(key);
301
302 if (buffer)
303 m_server_buffers[key].usedLocally = true;
304
305 //dumpBufferInfo();
306
308}
309
311{
312 //qDebug() << "texture_sharing_request_image" << key;
313 auto *buffer = getBuffer(key);
314 if (buffer) {
315 struct ::wl_client *client = resource->client();
316 struct ::wl_resource *buffer_resource = buffer->resourceForClient(client);
317 //qDebug() << " server_buffer resource" << buffer_resource;
318 if (buffer_resource)
319 send_provide_buffer(resource->handle, buffer_resource, key);
320 else
321 qWarning() << "QWaylandTextureSharingExtension: no buffer resource for client";
322 } else {
323 send_image_failed(resource->handle, key, QString());
324 }
325 //dumpBufferInfo();
326}
327
329{
330 Q_UNUSED(resource);
331 Q_UNUSED(key);
332// qDebug() << Q_FUNC_INFO << resource << key;
334}
335
336// A client has disconnected
338{
339 Q_UNUSED(resource);
340// qDebug() << "texture_sharing_destroy_resource" << resource->handle << resource->handle->object.id << "client" << resource->client();
341// dumpBufferInfo();
343}
344
345bool QWaylandTextureSharingExtension::initServerBufferIntegration()
346{
347 if (!m_server_buffer_integration) {
349
350 m_server_buffer_integration = QWaylandCompositorPrivate::get(compositor)->serverBufferIntegration();
351 if (!m_server_buffer_integration) {
352 qWarning("QWaylandTextureSharingExtension initialization failed: No Server Buffer Integration");
353 if (qEnvironmentVariableIsEmpty("QT_WAYLAND_SERVER_BUFFER_INTEGRATION"))
354 qWarning("Set the environment variable 'QT_WAYLAND_SERVER_BUFFER_INTEGRATION' to specify.");
355 return false;
356 }
357 }
358 return true;
359}
360
361QtWayland::ServerBuffer *QWaylandTextureSharingExtension::getCompressedBuffer(const QString &pathName)
362{
363 QFile f(pathName);
364 if (!f.open(QIODevice::ReadOnly))
365 return nullptr;
366
367 QTextureFileReader r(&f, pathName);
368
369 if (!r.canRead())
370 return nullptr;
371
372 QTextureFileData td(r.read());
373
374 //qDebug() << "QWaylandTextureSharingExtension: reading compressed texture data" << td;
375
376 if (!td.isValid()) {
377 qWarning() << "VulkanServerBufferIntegration:" << pathName << "not valid compressed texture";
378 return nullptr;
379 }
380
381 return m_server_buffer_integration->createServerBufferFromData(td.getDataView(), td.size(),
382 td.glInternalFormat());
383}
384
386{
387 for (auto it = m_server_buffers.begin(); it != m_server_buffers.end(); ) {
388 auto *buffer = it.value().buffer;
389 if (!it.value().usedLocally && !buffer->bufferInUse()) {
390 //qDebug() << "deleting buffer for" << it.key();
391 it = m_server_buffers.erase(it);
392 delete buffer;
393 } else {
394 ++it;
395 }
396 }
397 //dumpBufferInfo();
398}
399
400void QWaylandTextureSharingExtension::dumpBufferInfo()
401{
402 qDebug() << "shared buffers:" << m_server_buffers.size();
403 for (auto it = m_server_buffers.cbegin(); it != m_server_buffers.cend(); ++it)
404 qDebug() << " " << it.key() << ":" << it.value().buffer << "in use" << it.value().buffer->bufferInUse() << "usedLocally" << it.value().usedLocally ;
405}
406
408
409#include "moc_qwltexturesharingextension_p.cpp"
410
411#include "qwltexturesharingextension.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:107
static bool closingDown()
Returns true if the application objects are being destroyed; otherwise returns false.
bool exists() const
Returns true if the file system entry this QFileInfo refers to exists; otherwise returns false.
\inmodule QtCore
Definition qfile.h:93
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1212
const_iterator cbegin() const noexcept
Definition qhash.h:1214
qsizetype size() const noexcept
Returns the number of items in the hash.
Definition qhash.h:927
iterator erase(const_iterator it)
Definition qhash.h:1233
T value(const Key &key) const noexcept
Definition qhash.h:1054
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
Definition qhash.h:1216
const_iterator cend() const noexcept
Definition qhash.h:1218
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1303
static QList< QByteArray > supportedImageFormats()
Returns the list of image formats supported by QImageReader.
\inmodule QtGui
Definition qimage.h:37
@ Format_RGBA8888_Premultiplied
Definition qimage.h:60
void squeeze()
Definition qlist.h:774
void clear()
Definition qlist.h:434
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
QThread * thread() const
Returns the thread in which the object lives.
Definition qobject.cpp:1598
\inmodule QtGui
The QQmlEngine class provides an environment for instantiating QML components.
Definition qqmlengine.h:57
static QQmlContext * contextForObject(const QObject *)
Returns the QQmlContext for the object, or nullptr if no context has been set.
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....
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
\inmodule QtQuick
Definition qsgtexture.h:20
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:133
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:130
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
static QList< QByteArray > supportedFileFormats()
static QThread * currentThread()
Definition qthread.cpp:1039
bool singleShot
whether the timer is a single-shot timer
Definition qtimer.h:22
virtual void initialize()
Initializes the QWaylandCompositorExtension.
static QWaylandCompositorPrivate * get(QWaylandCompositor *compositor)
\qmltype WaylandCompositor \instantiates QWaylandCompositor \inqmlmodule QtWayland....
QQuickImageResponse * requestImageResponse(const QString &id, const QSize &requestedSize) override
Implement this method to return the job that will provide the texture with id.
void setExtensionReady(QWaylandTextureSharingExtension *extension)
void zqt_texture_sharing_v1_destroy_resource(Resource *resource) override
void zqt_texture_sharing_v1_request_image(Resource *resource, const QString &key) override
void initialize() override
Initializes the QWaylandCompositorExtension.
virtual bool customPixelData(const QString &key, QByteArray *data, QSize *size, uint *glInternalFormat)
void zqt_texture_sharing_v1_abandon_image(Resource *resource, const QString &key) override
void bufferResult(const QString &key, QtWayland::ServerBuffer *buffer)
static QWaylandTextureSharingExtension * self()
virtual ServerBuffer * createServerBufferFromData(QByteArrayView view, const QSize &size, uint glInternalFormat)
virtual ServerBuffer * createServerBufferFromImage(const QImage &qimage, ServerBuffer::Format format)=0
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 QtWayland::ServerBuffer *buffer)
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 doRequest(QWaylandTextureSharingExtension *extension)
SharedTextureImageResponse(QWaylandTextureSharingExtension *extension, const QString &id)
void doResponse(const QString &key, QtWayland::ServerBuffer *buffer)
QString errorString() const override
Returns the error string for the job execution.
QQuickTextureFactory * textureFactory() const override
Returns the texture factory for the job.
EGLContext ctx
void extension()
[6]
Definition dialogs.cpp:230
QSet< QString >::iterator it
Combined button and popup list for selecting options.
@ AutoConnection
#define qDebug
[1]
Definition qlogging.h:164
#define qWarning
Definition qlogging.h:166
static QOpenGLCompositor * compositor
GLboolean GLboolean GLboolean b
GLuint64 key
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLenum GLuint id
[7]
GLfloat GLfloat f
GLenum GLuint buffer
GLenum GLuint texture
GLint void * img
Definition qopenglext.h:233
GLsizei const GLchar *const * path
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define fp
QString qEnvironmentVariable(const char *varName, const QString &defaultValue)
Q_CORE_EXPORT bool qEnvironmentVariableIsEmpty(const char *varName) noexcept
static QT_BEGIN_NAMESPACE void init(QTextBoundaryFinder::BoundaryType type, QStringView str, QCharAttributes *attributes)
#define Q_OBJECT
#define Q_SLOTS
#define emit
#define Q_UNUSED(x)
unsigned int uint
Definition qtypes.h:34
myObject disconnect()
[26]
QString dir
[11]
aWidget window() -> setWindowTitle("New Window Title")
[2]
QJSEngine engine
[0]
\inmodule QtCore \reentrant
Definition qchar.h:18
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...