Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
vulkanserverbufferintegration.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// Qt-Security score:critical reason:network-protocol
4
6
8
9#include <QtOpenGL/QOpenGLTexture>
10#include <QtGui/QOpenGLContext>
11#include <QtGui/QOffscreenSurface>
12#include <QtGui/qopengl.h>
13
14#include <unistd.h>
15#include <fcntl.h>
16
17#include <QtCore/QDebug>
18
20static constexpr bool vsbiExtraDebug = false;
21
22#define DECL_GL_FUNCTION(name, type)
23 type name
24
25#define FIND_GL_FUNCTION(name, type)
26 do {
27 name = reinterpret_cast<type>(glContext->getProcAddress(#name));
28 if (!name) {
29 qWarning() << "ERROR in GL proc lookup. Could not find " #name;
30 return false;
31 }
32 } while (0)
33
35{
36 DECL_GL_FUNCTION(glCreateMemoryObjectsEXT, PFNGLCREATEMEMORYOBJECTSEXTPROC);
37 DECL_GL_FUNCTION(glImportMemoryFdEXT, PFNGLIMPORTMEMORYFDEXTPROC);
38 //DECL_GL_FUNCTION(glTextureStorageMem2DEXT, PFNGLTEXTURESTORAGEMEM2DEXTPROC);
39 DECL_GL_FUNCTION(glTexStorageMem2DEXT, PFNGLTEXSTORAGEMEM2DEXTPROC);
40 DECL_GL_FUNCTION(glDeleteMemoryObjectsEXT, PFNGLDELETEMEMORYOBJECTSEXTPROC);
41
42 bool init(QOpenGLContext *glContext)
43 {
44 FIND_GL_FUNCTION(glCreateMemoryObjectsEXT, PFNGLCREATEMEMORYOBJECTSEXTPROC);
45 FIND_GL_FUNCTION(glImportMemoryFdEXT, PFNGLIMPORTMEMORYFDEXTPROC);
46 //FIND_GL_FUNCTION(glTextureStorageMem2DEXT, PFNGLTEXTURESTORAGEMEM2DEXTPROC);
47 FIND_GL_FUNCTION(glTexStorageMem2DEXT, PFNGLTEXSTORAGEMEM2DEXTPROC);
48 FIND_GL_FUNCTION(glDeleteMemoryObjectsEXT, PFNGLDELETEMEMORYOBJECTSEXTPROC);
49
50 return true;
51 }
52 static bool create(QOpenGLContext *glContext);
53};
54
56
57//RAII
59{
60public:
62 {
63 if (!QOpenGLContext::currentContext()) {
64 if (QOpenGLContext::globalShareContext()) {
65 if (!localContext) {
66 localContext = new QOpenGLContext;
67 localContext->setShareContext(QOpenGLContext::globalShareContext());
68 localContext->create();
69 }
70 if (!offscreenSurface) {
71 offscreenSurface = new QOffscreenSurface;
72 offscreenSurface->setFormat(localContext->format());
73 offscreenSurface->create();
74 }
75 localContext->makeCurrent(offscreenSurface);
76 localContextInUse = true;
77 } else {
78 qCritical("VulkanServerBufferIntegration: no globalShareContext");
79 }
80 }
81 }
83 {
84 if (localContextInUse)
85 localContext->doneCurrent();
86 }
87 QOpenGLContext *context() { return localContextInUse ? localContext : QOpenGLContext::currentContext(); }
88private:
89 static QOpenGLContext *localContext;
90 static QOffscreenSurface *offscreenSurface;
91 bool localContextInUse = false;
92};
93
94QOpenGLContext *CurrentContext::localContext = nullptr;
95QOffscreenSurface *CurrentContext::offscreenSurface = nullptr;
96
97bool VulkanServerBufferGlFunctions::create(QOpenGLContext *glContext)
98{
99 if (funcs)
100 return true;
102 if (!funcs->init(glContext)) {
103 delete funcs;
104 funcs = nullptr;
105 return false;
106 }
107 return true;
108}
109
110VulkanServerBuffer::VulkanServerBuffer(VulkanServerBufferIntegration *integration, const QImage &qimage, QtWayland::ServerBuffer::Format format)
111 : QtWayland::ServerBuffer(qimage.size(),format)
112 , m_integration(integration)
113 , m_width(qimage.width())
114 , m_height(qimage.height())
115{
116 m_format = format;
117 switch (m_format) {
118 case RGBA32:
119 m_glInternalFormat = GL_RGBA8;
120 break;
121 // case A8:
122 // m_glInternalFormat = GL_R8;
123 // break;
124 default:
125 qWarning("VulkanServerBuffer: unsupported format");
126 m_glInternalFormat = GL_RGBA8;
127 break;
128 }
129
130 auto vulkanWrapper = m_integration->vulkanWrapper();
131 m_vImage = vulkanWrapper->createTextureImage(qimage);
132 if (m_vImage)
133 m_fd = vulkanWrapper->getImageInfo(m_vImage, &m_memorySize);
134}
135
136VulkanServerBuffer::VulkanServerBuffer(VulkanServerBufferIntegration *integration, VulkanImageWrapper *vImage, uint glInternalFormat, const QSize &size)
138 , m_integration(integration)
139 , m_width(size.width())
140 , m_height(size.height())
141 , m_vImage(vImage)
143{
144 auto vulkanWrapper = m_integration->vulkanWrapper();
145 m_fd = vulkanWrapper->getImageInfo(m_vImage, &m_memorySize);
146}
147
149{
150 delete m_texture; //this is always nullptr for now
151 auto vulkanWrapper = m_integration->vulkanWrapper();
152 vulkanWrapper->freeTextureImage(m_vImage);
153}
154
155struct ::wl_resource *VulkanServerBuffer::resourceForClient(struct ::wl_client *client)
156{
157 auto *bufferResource = resourceMap().value(client);
158 if (!bufferResource) {
159 auto integrationResource = m_integration->resourceMap().value(client);
160 if (!integrationResource) {
161 qWarning("VulkanServerBuffer::resourceForClient: Trying to get resource for ServerBuffer. But client is not bound to the vulkan interface");
162 return nullptr;
163 }
164 struct ::wl_resource *shm_integration_resource = integrationResource->handle;
165 Resource *resource = add(client, 1);
166 m_integration->send_server_buffer_created(shm_integration_resource, resource->handle, m_fd, m_width, m_height, m_memorySize, m_glInternalFormat);
167 return resource->handle;
168 }
169 return bufferResource->handle;
170}
171
173{
174 if (m_texture && m_texture->isCreated())
175 return m_texture;
176
177 CurrentContext current;
178
180 return nullptr;
181
182 funcs->glCreateMemoryObjectsEXT(1, &m_memoryObject);
183 if (vsbiExtraDebug) qDebug() << "glCreateMemoryObjectsEXT" << Qt::hex << glGetError();
184
185
186 int dupfd = fcntl(m_fd, F_DUPFD_CLOEXEC, 0);
187 if (dupfd < 0) {
188 perror("VulkanServerBuffer::toOpenGlTexture() Could not dup fd:");
189 return nullptr;
190 }
191
192 funcs->glImportMemoryFdEXT(m_memoryObject, m_memorySize, GL_HANDLE_TYPE_OPAQUE_FD_EXT, dupfd);
193 if (vsbiExtraDebug) qDebug() << "glImportMemoryFdEXT" << Qt::hex << glGetError();
194
195
196 if (!m_texture)
197 m_texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
198 m_texture->create();
199
200 GLuint texId = m_texture->textureId();
201 if (vsbiExtraDebug) qDebug() << "created texture" << texId << Qt::hex << glGetError();
202
203 m_texture->bind();
204 if (vsbiExtraDebug) qDebug() << "bound texture" << texId << Qt::hex << glGetError();
205 funcs->glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, m_glInternalFormat, m_size.width(), m_size.height(), m_memoryObject, 0 );
206 if (vsbiExtraDebug) qDebug() << "glTexStorageMem2DEXT" << Qt::hex << glGetError();
207 if (vsbiExtraDebug) qDebug() << "format" << Qt::hex << m_glInternalFormat << GL_RGBA8;
208
209
210 return m_texture;
211}
212
214{
215 if (!m_texture || !m_texture->isCreated())
216 return;
217
218 CurrentContext current;
219 m_texture->destroy();
220 funcs->glDeleteMemoryObjectsEXT(1, &m_memoryObject);
221}
222
223
225{
226 return (m_texture && m_texture->isCreated()) || resourceMap().size() > 0;
227}
228
230{
231 qCDebug(qLcWaylandCompositorHardwareIntegration) << "server_buffer RELEASE resource" << resource->handle << wl_resource_get_id(resource->handle) << "for client" << resource->client();
232 wl_resource_destroy(resource->handle);
233}
234
238
242
243bool VulkanServerBufferIntegration::initializeHardware(QWaylandCompositor *compositor)
244{
245 Q_ASSERT(QGuiApplication::platformNativeInterface());
246
247 QtWaylandServer::zqt_vulkan_server_buffer_v1::init(compositor->display(), 1);
248 return true;
249}
250
251bool VulkanServerBufferIntegration::supportsFormat(QtWayland::ServerBuffer::Format format) const
252{
253 switch (format) {
254 case QtWayland::ServerBuffer::RGBA32:
255 return true;
256 case QtWayland::ServerBuffer::A8:
257 return false;
258 default:
259 return false;
260 }
261}
262
263QtWayland::ServerBuffer *VulkanServerBufferIntegration::createServerBufferFromImage(const QImage &qimage, QtWayland::ServerBuffer::Format format)
264{
265 if (!m_vulkanWrapper) {
266 CurrentContext current;
267 m_vulkanWrapper = new VulkanWrapper(current.context());
268 }
269 return new VulkanServerBuffer(this, qimage, format);
270}
271
273VulkanServerBufferIntegration::createServerBufferFromData(QByteArrayView view, const QSize &size,
274 uint glInternalFormat)
275{
276 if (!m_vulkanWrapper) {
277 CurrentContext current;
278 m_vulkanWrapper = new VulkanWrapper(current.context());
279 }
280
281 auto *vImage = m_vulkanWrapper->createTextureImageFromData(
282 reinterpret_cast<const uchar *>(view.constData()), view.size(), size, glInternalFormat);
283
284 if (vImage)
285 return new VulkanServerBuffer(this, vImage, glInternalFormat, size);
286
287 qCWarning(qLcWaylandCompositorHardwareIntegration) << "could not load compressed texture";
288 return nullptr;
289}
290
291QT_END_NAMESPACE
bool supportsFormat(QtWayland::ServerBuffer::Format format) const override
bool initializeHardware(QWaylandCompositor *) override
QtWayland::ServerBuffer * createServerBufferFromData(QByteArrayView view, const QSize &size, uint glInternalFormat) override
void server_buffer_release(Resource *resource) override
QOpenGLTexture * toOpenGlTexture() override
VulkanServerBuffer(VulkanServerBufferIntegration *integration, VulkanImageWrapper *vImage, uint glInternalFormat, const QSize &size)
int getImageInfo(const VulkanImageWrapper *imgWrapper, int *memSize, int *w=nullptr, int *h=nullptr)
VulkanWrapper(QOpenGLContext *glContext)
void freeTextureImage(VulkanImageWrapper *imageWrapper)
VulkanImageWrapper * createTextureImage(const QImage &img)
#define DECL_GL_FUNCTION(name, type)
#define FIND_GL_FUNCTION(name, type)
static QT_BEGIN_NAMESPACE constexpr bool vsbiExtraDebug
static VulkanServerBufferGlFunctions * funcs
static bool create(QOpenGLContext *glContext)