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