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
waylandeglclientbufferintegration.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6
7#include <QtWaylandCompositor/QWaylandCompositor>
8#include <QtWaylandCompositor/private/qwltextureorphanage_p.h>
9#include <qpa/qplatformnativeinterface.h>
10#include <QtOpenGL/QOpenGLTexture>
11#include <QtGui/QGuiApplication>
12#include <QtGui/QOpenGLContext>
13#include <QtGui/QOffscreenSurface>
14#include <qpa/qplatformscreen.h>
15#include <QtGui/QWindow>
16#include <QtCore/QPointer>
17#include <QDebug>
18
19#include <QMutex>
20#include <QMutexLocker>
21#include <QVarLengthArray>
22#include <QtCore/private/qcore_unix_p.h>
23#include <QtGui/private/qeglstreamconvenience_p.h>
24
25#ifndef GL_TEXTURE_EXTERNAL_OES
26#define GL_TEXTURE_EXTERNAL_OES 0x8D65
27#endif
28
29#ifndef EGL_WAYLAND_BUFFER_WL
30#define EGL_WAYLAND_BUFFER_WL 0x31D5
31#endif
32
33#ifndef EGL_WAYLAND_EGLSTREAM_WL
34#define EGL_WAYLAND_EGLSTREAM_WL 0x334B
35#endif
36
37#ifndef EGL_WAYLAND_PLANE_WL
38#define EGL_WAYLAND_PLANE_WL 0x31D6
39#endif
40
41#ifndef EGL_WAYLAND_Y_INVERTED_WL
42#define EGL_WAYLAND_Y_INVERTED_WL 0x31DB
43#endif
44
45#ifndef EGL_TEXTURE_RGB
46#define EGL_TEXTURE_RGB 0x305D
47#endif
48
49#ifndef EGL_TEXTURE_RGBA
50#define EGL_TEXTURE_RGBA 0x305E
51#endif
52
53#ifndef EGL_TEXTURE_EXTERNAL_WL
54#define EGL_TEXTURE_EXTERNAL_WL 0x31DA
55#endif
56
57#ifndef EGL_TEXTURE_Y_U_V_WL
58#define EGL_TEXTURE_Y_U_V_WL 0x31D7
59#endif
60
61#ifndef EGL_TEXTURE_Y_UV_WL
62#define EGL_TEXTURE_Y_UV_WL 0x31D8
63#endif
64
65#ifndef EGL_TEXTURE_Y_XUXV_WL
66#define EGL_TEXTURE_Y_XUXV_WL 0x31D9
67#endif
68
69#ifndef EGL_PLATFORM_X11_KHR
70#define EGL_PLATFORM_X11_KHR 0x31D5
71#endif
72
73/* Needed for compatibility with Mesa older than 10.0. */
75
76#ifndef EGL_WL_bind_wayland_display
77typedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDWAYLANDDISPLAYWL) (EGLDisplay dpy, struct wl_display *display);
78typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNBINDWAYLANDDISPLAYWL) (EGLDisplay dpy, struct wl_display *display);
79#endif
80
81#ifndef EGL_KHR_image
82typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
83typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image);
84#endif
85
86#ifndef GL_OES_EGL_image
87typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
88typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
89#endif
90
92
93static const char *
94egl_error_string(EGLint code)
95{
96#define MYERRCODE(x) case x: return #x;
97 switch (code) {
98 MYERRCODE(EGL_SUCCESS)
99 MYERRCODE(EGL_NOT_INITIALIZED)
100 MYERRCODE(EGL_BAD_ACCESS)
101 MYERRCODE(EGL_BAD_ALLOC)
102 MYERRCODE(EGL_BAD_ATTRIBUTE)
103 MYERRCODE(EGL_BAD_CONTEXT)
104 MYERRCODE(EGL_BAD_CONFIG)
105 MYERRCODE(EGL_BAD_CURRENT_SURFACE)
106 MYERRCODE(EGL_BAD_DISPLAY)
107 MYERRCODE(EGL_BAD_SURFACE)
108 MYERRCODE(EGL_BAD_MATCH)
109 MYERRCODE(EGL_BAD_PARAMETER)
110 MYERRCODE(EGL_BAD_NATIVE_PIXMAP)
111 MYERRCODE(EGL_BAD_NATIVE_WINDOW)
112 MYERRCODE(EGL_CONTEXT_LOST)
113 default:
114 return "unknown";
115 }
116#undef MYERRCODE
117}
118
142
144{
145public:
147
148 void initBuffer(WaylandEglClientBuffer *buffer);
149 void initEglTexture(WaylandEglClientBuffer *buffer, EGLint format);
151 bool initEglStream(WaylandEglClientBuffer *buffer, struct ::wl_resource *bufferHandle);
152 void setupBufferAndCleanup(BufferState *bs, QOpenGLTexture *texture, int plane);
153 void handleEglstreamTexture(WaylandEglClientBuffer *buffer, wl_resource *bufferHandle);
154 void registerBuffer(struct ::wl_resource *buffer, BufferState state);
155
157 bool display_bound = false;
158 ::wl_display *wlDisplay = nullptr;
161
165
168
170
172 static WaylandEglClientBufferIntegrationPrivate *get(WaylandEglClientBufferIntegration *integration) {
173 return integration ? integration->d_ptr.data() : nullptr;
174 }
175};
176
180
181void WaylandEglClientBufferIntegrationPrivate::initBuffer(WaylandEglClientBuffer *buffer)
182{
183 EGLint format;
184
185 if (egl_query_wayland_buffer(egl_display, buffer->waylandBufferHandle(), EGL_TEXTURE_FORMAT, &format))
186 initEglTexture(buffer, format);
187}
188
189void WaylandEglClientBufferIntegrationPrivate::initEglTexture(WaylandEglClientBuffer *buffer, EGLint format)
190{
191// Non-streaming case
192
193 // Resolving GL functions may need a context current, so do it only here.
194 if (!gl_egl_image_target_texture_2d)
195 gl_egl_image_target_texture_2d = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES"));
196
197 if (!gl_egl_image_target_texture_2d) {
198 qCWarning(qLcWaylandCompositorHardwareIntegration)
199 << "BindTextureToBuffer() failed. Could not find glEGLImageTargetTexture2DOES.";
200 return;
201 }
202
203 BufferState &state = *buffer->d;
204 state.egl_format = format;
205 state.eglMode = BufferState::ModeEGLImage;
206
207#if defined(EGL_WAYLAND_Y_INVERTED_WL)
208 EGLint isYInverted;
209 EGLBoolean ret = egl_query_wayland_buffer(egl_display, buffer->waylandBufferHandle(), EGL_WAYLAND_Y_INVERTED_WL, &isYInverted);
210 // Yes, this looks strange, but the specification says that EGL_FALSE return
211 // value (not supported) should be treated the same as EGL_TRUE return value
212 // and EGL_TRUE in value.
213 state.isYInverted = (ret == EGL_FALSE || isYInverted == EGL_TRUE);
214#endif
215
216 int planes = 1;
217
218 switch (format) {
219 default:
220 case EGL_TEXTURE_RGB:
221 case EGL_TEXTURE_RGBA:
223 planes = 1;
224 break;
226 planes = 2;
227 break;
229 planes = 3;
230 break;
232 planes = 2;
233 break;
234 }
235
236 for (int i = 0; i < planes; i++) {
237 EGLint attribs[5] = { EGL_WAYLAND_PLANE_WL, i, EGL_NONE };
238#ifdef EGL_EXT_protected_content
239 if (buffer->isProtected()) {
240 attribs[2] = EGL_PROTECTED_CONTENT_EXT;
241 attribs[3] = EGL_TRUE;
242 attribs[4] = EGL_NONE;
243 }
244#endif
245 EGLImageKHR image = egl_create_image(egl_display,
246 EGL_NO_CONTEXT,
248 buffer->waylandBufferHandle(),
249 attribs);
250
251 if (image == EGL_NO_IMAGE_KHR) {
252 qCWarning(qLcWaylandCompositorHardwareIntegration)
253 << "Failed to create EGL image for plane" << i;
254 }
255
256 state.egl_images << image;
257
258 QMutexLocker locker(&state.texturesLock);
259 state.textures[i] = nullptr;
260 }
261}
262
264{
265 bool localContextNeeded = false;
266 if (!QOpenGLContext::currentContext()) {
267 if (!localContext && QOpenGLContext::globalShareContext()) {
268 localContext = new QOpenGLContext;
269 localContext->setShareContext(QOpenGLContext::globalShareContext());
270 localContext->create();
271 }
272 if (localContext) {
273 if (!offscreenSurface) {
274 offscreenSurface = new QOffscreenSurface;
275 offscreenSurface->setFormat(localContext->format());
276 offscreenSurface->create();
277 }
278 localContext->makeCurrent(offscreenSurface);
279 localContextNeeded = true;
280 }
281 }
282 return localContextNeeded;
283}
284
285
287{
288 QMutexLocker locker(&bs->texturesLock);
289
290 bs->textures[plane] = texture;
291 bs->texturesContext[plane] = QOpenGLContext::currentContext();
292
293 Q_ASSERT(bs->texturesContext[plane] != nullptr);
294
295 qCDebug(qLcWaylandCompositorHardwareIntegration)
296 << Q_FUNC_INFO
297 << "(egl) creating a cleanup-lambda for QOpenGLContext::aboutToBeDestroyed!"
298 << ", texture: " << bs->textures[plane]
299 << ", ctx: " << (void*)bs->texturesContext[plane];
300
301 bs->texturesAboutToBeDestroyedConnection[plane] =
302 QObject::connect(bs->texturesContext[plane], &QOpenGLContext::aboutToBeDestroyed,
303 bs->texturesContext[plane], [bs, plane]() {
304
305 QMutexLocker locker(&bs->texturesLock);
306
307 // See above lock - there is a chance that this has already been removed from textures[plane]!
308 // Furthermore, we can trust that all the rest (e.g. disconnect) has also been properly executed!
309 if (bs->textures[plane] == nullptr)
310 return;
311
312 delete bs->textures[plane];
313
314 qCDebug(qLcWaylandCompositorHardwareIntegration)
315 << Q_FUNC_INFO
316 << "texture deleted due to QOpenGLContext::aboutToBeDestroyed!"
317 << "Pointer (now dead) was:" << (void*)(bs->textures[plane])
318 << " Associated context (about to die too) is: " << (void*)(bs->texturesContext[plane]);
319
320 bs->textures[plane] = nullptr;
321 bs->texturesContext[plane] = nullptr;
322
323 QObject::disconnect(bs->texturesAboutToBeDestroyedConnection[plane]);
324 bs->texturesAboutToBeDestroyedConnection[plane] = QMetaObject::Connection();
325
326 }, Qt::DirectConnection);
327}
328
329bool WaylandEglClientBufferIntegrationPrivate::initEglStream(WaylandEglClientBuffer *buffer, wl_resource *bufferHandle)
330{
331 BufferState &state = *buffer->d;
332 state.egl_format = EGL_TEXTURE_EXTERNAL_WL;
333 state.isYInverted = false;
334
335 EGLNativeFileDescriptorKHR streamFd = EGL_NO_FILE_DESCRIPTOR_KHR;
336
337 if (egl_query_wayland_buffer(egl_display, bufferHandle, EGL_WAYLAND_BUFFER_WL, &streamFd)) {
338 state.egl_stream = funcs->create_stream_from_file_descriptor(egl_display, streamFd);
339 close(streamFd);
340 } else {
341 EGLAttrib stream_attribs[] = {
342 EGL_WAYLAND_EGLSTREAM_WL, (EGLAttrib)bufferHandle,
343 EGL_NONE
344 };
345 state.egl_stream = funcs->create_stream_attrib_nv(egl_display, stream_attribs);
346 }
347
348 if (state.egl_stream == EGL_NO_STREAM_KHR) {
349 qCWarning(qLcWaylandCompositorHardwareIntegration, "%s:%d: eglCreateStreamFromFileDescriptorKHR failed: 0x%x", Q_FUNC_INFO, __LINE__, eglGetError());
350 return false;
351 }
352 state.eglMode = BufferState::ModeEGLStream;
353
354 if (!QOpenGLContext::currentContext()) {
355 qCWarning(qLcWaylandCompositorHardwareIntegration)
356 << "EglClientBufferIntegration: creating texture with no current context";
357 return false;
358 }
359
360 auto texture = new QOpenGLTexture(static_cast<QOpenGLTexture::Target>(GL_TEXTURE_EXTERNAL_OES));
361 texture->create();
362 setupBufferAndCleanup(buffer->d, texture, 0);
363
364 qCDebug(qLcWaylandCompositorHardwareIntegration)
365 << " NEW texture! It's pointer and ctx pointer: "
366 << (void*)state.textures[0] << "; " << (void*)state.texturesContext[0];
367
368 texture->bind();
369
370 auto newStream = funcs->stream_consumer_gltexture(egl_display, state.egl_stream);
371 if (!newStream) {
372 EGLint code = eglGetError();
373 qCWarning(qLcWaylandCompositorHardwareIntegration) << "Could not initialize EGLStream:" << egl_error_string(code) << Qt::hex << (long)code;
374 funcs->destroy_stream(egl_display, state.egl_stream);
375 state.egl_stream = EGL_NO_STREAM_KHR;
376 return false;
377 }
378 return true;
379}
380
381void WaylandEglClientBufferIntegrationPrivate::handleEglstreamTexture(WaylandEglClientBuffer *buffer, struct ::wl_resource *bufferHandle)
382{
383 bool usingLocalContext = ensureContext();
384
385 if (buffer->d->eglMode == BufferState::ModeUninitialized) {
386 bool streamOK = initEglStream(buffer, bufferHandle);
387 if (!streamOK)
388 return;
389 }
390
391 BufferState &state = *buffer->d;
392 auto texture = state.textures[0];
393
394 // EGLStream requires calling acquire on every frame.
395 texture->bind();
396 EGLint stream_state;
397 funcs->query_stream(egl_display, state.egl_stream, EGL_STREAM_STATE_KHR, &stream_state);
398
399 if (stream_state == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR) {
400 if (funcs->stream_consumer_acquire(egl_display, state.egl_stream) != EGL_TRUE)
401 qCWarning(qLcWaylandCompositorHardwareIntegration,
402 "%s:%d: eglStreamConsumerAcquireKHR failed: 0x%x", Q_FUNC_INFO, __LINE__,
403 eglGetError());
404 }
405
406 if (usingLocalContext)
407 localContext->doneCurrent();
408}
409
410WaylandEglClientBufferIntegration::WaylandEglClientBufferIntegration()
411 : d_ptr(new WaylandEglClientBufferIntegrationPrivate)
412{
413}
414
415WaylandEglClientBufferIntegration::~WaylandEglClientBufferIntegration()
416{
417 Q_D(WaylandEglClientBufferIntegration);
418 if (d->egl_unbind_wayland_display && d->display_bound) {
419 Q_ASSERT(d->wlDisplay);
420 if (!d->egl_unbind_wayland_display(d->egl_display, d->wlDisplay))
421 qCWarning(qLcWaylandCompositorHardwareIntegration) << "eglUnbindWaylandDisplayWL failed";
422 }
423}
424
425void WaylandEglClientBufferIntegration::initializeHardware(struct wl_display *display)
426{
427 Q_D(WaylandEglClientBufferIntegration);
428
429 const bool ignoreBindDisplay = !qgetenv("QT_WAYLAND_IGNORE_BIND_DISPLAY").isEmpty();
430
431 QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
432 if (!nativeInterface) {
433 qCWarning(qLcWaylandCompositorHardwareIntegration)
434 << "Failed to initialize EGL display. No native platform interface available.";
435 return;
436 }
437
438 d->egl_display = nativeInterface->nativeResourceForIntegration("EglDisplay");
439 if (!d->egl_display) {
440 qCWarning(qLcWaylandCompositorHardwareIntegration)
441 << "Failed to initialize EGL display. Could not get EglDisplay for window.";
442 return;
443 }
444
445 const char *extensionString = eglQueryString(d->egl_display, EGL_EXTENSIONS);
446 if ((!extensionString || !strstr(extensionString, "EGL_WL_bind_wayland_display")) && !ignoreBindDisplay) {
447 qCWarning(qLcWaylandCompositorHardwareIntegration)
448 << "Failed to initialize EGL display. There is no EGL_WL_bind_wayland_display extension.";
449 return;
450 }
451
452 d->egl_bind_wayland_display = reinterpret_cast<PFNEGLBINDWAYLANDDISPLAYWL>(eglGetProcAddress("eglBindWaylandDisplayWL"));
453 d->egl_unbind_wayland_display = reinterpret_cast<PFNEGLUNBINDWAYLANDDISPLAYWL>(eglGetProcAddress("eglUnbindWaylandDisplayWL"));
454 if ((!d->egl_bind_wayland_display || !d->egl_unbind_wayland_display) && !ignoreBindDisplay) {
455 qCWarning(qLcWaylandCompositorHardwareIntegration)
456 << "Failed to initialize EGL display. Could not find eglBindWaylandDisplayWL and eglUnbindWaylandDisplayWL.";
457 return;
458 }
459
460 d->egl_query_wayland_buffer = reinterpret_cast<PFNEGLQUERYWAYLANDBUFFERWL_compat>(eglGetProcAddress("eglQueryWaylandBufferWL"));
461 if (!d->egl_query_wayland_buffer) {
462 qCWarning(qLcWaylandCompositorHardwareIntegration)
463 << "Failed to initialize EGL display. Could not find eglQueryWaylandBufferWL.";
464 return;
465 }
466
467 d->egl_create_image = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress("eglCreateImageKHR"));
468 d->egl_destroy_image = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(eglGetProcAddress("eglDestroyImageKHR"));
469 if (!d->egl_create_image || !d->egl_destroy_image) {
470 qCWarning(qLcWaylandCompositorHardwareIntegration)
471 << "Failed to initialize EGL display. Could not find eglCreateImageKHR and eglDestroyImageKHR.";
472 return;
473 }
474
475 if (d->egl_bind_wayland_display && d->egl_unbind_wayland_display) {
476 d->display_bound = d->egl_bind_wayland_display(d->egl_display, display);
477 if (!d->display_bound)
478 qCDebug(qLcWaylandCompositorHardwareIntegration) << "Wayland display already bound by other client buffer integration.";
479 d->wlDisplay = display;
480 }
481
482 d->funcs = new QEGLStreamConvenience;
483 d->funcs->initialize(d->egl_display);
484}
485
486QtWayland::ClientBuffer *WaylandEglClientBufferIntegration::createBufferFor(wl_resource *buffer)
487{
488 Q_D(WaylandEglClientBufferIntegration);
489 int w = -1;
490 bool q = d->egl_query_wayland_buffer(d->egl_display, buffer, EGL_WIDTH, &w);
491 if (!q || w <= 0)
492 return nullptr;
493 return new WaylandEglClientBuffer(this, buffer);
494}
495
496WaylandEglClientBuffer::WaylandEglClientBuffer(WaylandEglClientBufferIntegration *integration, wl_resource *buffer)
497 : ClientBuffer(buffer)
498 , m_integration(integration)
499{
500 auto *p = WaylandEglClientBufferIntegrationPrivate::get(m_integration);
501 d = new BufferState;
502 if (buffer && !wl_shm_buffer_get(buffer)) {
503 EGLint width, height;
504 p->egl_query_wayland_buffer(p->egl_display, buffer, EGL_WIDTH, &width);
505 p->egl_query_wayland_buffer(p->egl_display, buffer, EGL_HEIGHT, &height);
506 d->size = QSize(width, height);
507
508 p->initBuffer(this);
509 }
510}
511
512
513WaylandEglClientBuffer::~WaylandEglClientBuffer()
514{
515 auto *p = WaylandEglClientBufferIntegrationPrivate::get(m_integration);
516
517 if (p) {
518 for (auto image : d->egl_images)
519 p->egl_destroy_image(p->egl_display, image);
520
521 if (d->egl_stream)
522 p->funcs->destroy_stream(p->egl_display, d->egl_stream);
523
524 }
525
526 {
527 QMutexLocker locker(&d->texturesLock);
528
529 for (int i=0; i<3; i++) {
530 if (d->textures[i] != nullptr) {
531
532 qCDebug(qLcWaylandCompositorHardwareIntegration)
533 << Q_FUNC_INFO << " handing over texture!"
534 << (void*)d->textures[i] << "; " << (void*)d->texturesContext[i]
535 << " ... current context might be the same: " << QOpenGLContext::currentContext();
536
537 QtWayland::QWaylandTextureOrphanage::instance()->admitTexture(
538 d->textures[i], d->texturesContext[i]);
539 d->textures[i] = nullptr; // in case the aboutToBeDestroyed lambda is called while we where here
540 d->texturesContext[i] = nullptr;
541 QObject::disconnect(d->texturesAboutToBeDestroyedConnection[i]);
542 d->texturesAboutToBeDestroyedConnection[i] = QMetaObject::Connection();
543 }
544 }
545 }
546
547 delete d;
548}
549
551 switch (format) {
552 case EGL_TEXTURE_RGB:
553 return QWaylandBufferRef::BufferFormatEgl_RGB;
554 case EGL_TEXTURE_RGBA:
555 return QWaylandBufferRef::BufferFormatEgl_RGBA;
557 return QWaylandBufferRef::BufferFormatEgl_EXTERNAL_OES;
559 return QWaylandBufferRef::BufferFormatEgl_Y_UV;
561 return QWaylandBufferRef::BufferFormatEgl_Y_U_V;
563 return QWaylandBufferRef::BufferFormatEgl_Y_XUXV;
564 }
565
566 return QWaylandBufferRef::BufferFormatEgl_RGBA;
567}
568
570 switch (format) {
571 case EGL_TEXTURE_RGB:
572 return QOpenGLTexture::RGBFormat;
573 case EGL_TEXTURE_RGBA:
574 return QOpenGLTexture::RGBAFormat;
575 default:
576 return QOpenGLTexture::NoFormat;
577 }
578}
579
580QWaylandBufferRef::BufferFormatEgl WaylandEglClientBuffer::bufferFormatEgl() const
581{
582 return formatFromEglFormat(d->egl_format);
583}
584
585QOpenGLTexture *WaylandEglClientBuffer::toOpenGlTexture(int plane)
586{
587 auto *p = WaylandEglClientBufferIntegrationPrivate::get(m_integration);
588 // At this point we should have a valid OpenGL context, so it's safe to destroy textures
589 QtWayland::QWaylandTextureOrphanage::instance()->deleteTextures();
590
591 if (!m_buffer)
592 return nullptr;
593
594 auto texture = d->textures[plane];
595 if (d->eglMode == BufferState::ModeEGLStream)
596 return texture; // EGLStreams texture is maintained by handle_eglstream_texture()
597
598 const auto target = static_cast<QOpenGLTexture::Target>(d->egl_format == EGL_TEXTURE_EXTERNAL_WL ? GL_TEXTURE_EXTERNAL_OES
599 : GL_TEXTURE_2D);
600 if (!texture) {
601 texture = new QOpenGLTexture(target);
602 texture->setFormat(openGLFormatFromEglFormat(d->egl_format));
603 texture->setSize(d->size.width(), d->size.height());
604 texture->create();
605 p->setupBufferAndCleanup(this->d, texture, plane);
606 }
607
608 if (m_textureDirty) {
609 m_textureDirty = false;
610 texture->bind();
611 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
612 p->gl_egl_image_target_texture_2d(target, d->egl_images[plane]);
613#ifdef GL_EXT_protected_textures
614 if (isProtected())
615 glTexParameteri(target, GL_TEXTURE_PROTECTED_EXT, GL_TRUE);
616#endif
617 }
618 return texture;
619}
620
621void WaylandEglClientBuffer::setCommitted(QRegion &damage)
622{
623 ClientBuffer::setCommitted(damage);
624 if (d->eglMode == BufferState::ModeEGLStream || d->eglMode == BufferState::ModeUninitialized) {
625 auto *p = WaylandEglClientBufferIntegrationPrivate::get(m_integration);
626 p->handleEglstreamTexture(this, waylandBufferHandle());
627 }
628}
629
630bool WaylandEglClientBuffer::isProtected()
631{
632 if (m_integration && m_buffer)
633 return m_integration->isProtected(m_buffer);
634
635 return false;
636}
637
638
639QWaylandSurface::Origin WaylandEglClientBuffer::origin() const
640{
641 return d->isYInverted ? QWaylandSurface::OriginTopLeft : QWaylandSurface::OriginBottomLeft;
642}
643
644quintptr WaylandEglClientBuffer::lockNativeBuffer()
645{
646 auto *p = WaylandEglClientBufferIntegrationPrivate::get(m_integration);
647
648 if (d->egl_stream != EGL_NO_STREAM_KHR)
649 return 0;
650
651 EGLImageKHR image = p->egl_create_image(p->egl_display, EGL_NO_CONTEXT,
653 m_buffer, nullptr);
654 return reinterpret_cast<quintptr>(image);
655}
656
657void WaylandEglClientBuffer::unlockNativeBuffer(quintptr native_buffer) const
658{
659 if (!native_buffer)
660 return;
661
662 auto *p = WaylandEglClientBufferIntegrationPrivate::get(m_integration);
663
664 EGLImageKHR image = reinterpret_cast<EGLImageKHR>(native_buffer);
665 p->egl_destroy_image(p->egl_display, image);
666}
667
668QSize WaylandEglClientBuffer::size() const
669{
670 return d->size;
671}
672
673QT_END_NAMESPACE
void handleEglstreamTexture(WaylandEglClientBuffer *buffer, wl_resource *bufferHandle)
static WaylandEglClientBufferIntegrationPrivate * get(WaylandEglClientBufferIntegration *integration)
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC gl_egl_image_target_texture_2d
void initEglTexture(WaylandEglClientBuffer *buffer, EGLint format)
bool initEglStream(WaylandEglClientBuffer *buffer, struct ::wl_resource *bufferHandle)
void registerBuffer(struct ::wl_resource *buffer, BufferState state)
void setupBufferAndCleanup(BufferState *bs, QOpenGLTexture *texture, int plane)
#define GL_TEXTURE_EXTERNAL_OES
QVarLengthArray< EGLImageKHR, 3 > egl_images
BufferState()=default
QMetaObject::Connection texturesAboutToBeDestroyedConnection[3]
QOpenGLContext * texturesContext[3]
static QOpenGLTexture::TextureFormat openGLFormatFromEglFormat(EGLint format)
#define EGL_TEXTURE_EXTERNAL_WL
typedef void(GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)(GLenum target
struct wl_resource EGLint EGLint * value
EGLContext EGLenum EGLClientBuffer const EGLint * attrib_list
typedef EGLBoolean(EGLAPIENTRYP PFNEGLQUERYWAYLANDBUFFERWL_compat)(EGLDisplay dpy
#define EGL_WAYLAND_Y_INVERTED_WL
#define MYERRCODE(x)
typedef EGLImageKHR(EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC)(EGLDisplay dpy
static QT_BEGIN_NAMESPACE const char * egl_error_string(EGLint code)
static QWaylandBufferRef::BufferFormatEgl formatFromEglFormat(EGLint format)
#define EGL_WAYLAND_EGLSTREAM_WL
struct wl_resource * buffer
struct wl_resource EGLint attribute