8#include <QtWaylandCompositor/QWaylandCompositor>
9#include <QtOpenGL/QOpenGLTexture>
10#include <QtGui/QGuiApplication>
11#include <QtGui/QOpenGLContext>
12#include <QtGui/QOffscreenSurface>
13#include <QtCore/QMutexLocker>
15#include <QtGui/private/qeglstreamconvenience_p.h>
16#include <qpa/qplatformnativeinterface.h>
18#include <QtWaylandCompositor/private/qwaylandcompositor_p.h>
19#include <QtWaylandCompositor/private/qwlbuffermanager_p.h>
20#include <QtWaylandCompositor/private/qwltextureorphanage_p.h>
23#include <EGL/eglext.h>
26#ifndef GL_TEXTURE_EXTERNAL_OES
27#define GL_TEXTURE_EXTERNAL_OES 0x8D65
31#define EGL_WAYLAND_BUFFER_WL 0x31D5
34#ifndef EGL_WAYLAND_EGLSTREAM_WL
35#define EGL_WAYLAND_EGLSTREAM_WL 0x334B
39#define EGL_WAYLAND_PLANE_WL 0x31D6
43#define EGL_WAYLAND_Y_INVERTED_WL 0x31DB
47#define EGL_TEXTURE_RGB 0x305D
51#define EGL_TEXTURE_RGBA 0x305E
55#define EGL_TEXTURE_EXTERNAL_WL 0x31DA
59#define EGL_TEXTURE_Y_U_V_WL 0x31D7
63#define EGL_TEXTURE_Y_UV_WL 0x31D8
67#define EGL_TEXTURE_Y_XUXV_WL 0x31D9
71#define EGL_PLATFORM_X11_KHR 0x31D5
79#ifndef EGL_WL_bind_wayland_display
80typedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDWAYLANDDISPLAYWL) (EGLDisplay dpy,
struct wl_display *display);
81typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNBINDWAYLANDDISPLAYWL) (EGLDisplay dpy,
struct wl_display *display);
87#define MYERRCODE(x) case x: return #x;
150 return shuttingDown ?
nullptr : integration->d_ptr.data();
160 bool localContextNeeded =
false;
161 if (!QOpenGLContext::currentContext()) {
162 if (!localContext && QOpenGLContext::globalShareContext()) {
163 localContext =
new QOpenGLContext;
164 localContext->setShareContext(QOpenGLContext::globalShareContext());
165 localContext->create();
168 if (!offscreenSurface) {
169 offscreenSurface =
new QOffscreenSurface;
170 offscreenSurface->setFormat(localContext->format());
171 offscreenSurface->create();
173 localContext->makeCurrent(offscreenSurface);
174 localContextNeeded =
true;
177 return localContextNeeded;
183 QMutexLocker locker(&bs->texturesLock);
185 bs->textures[plane] = texture;
186 bs->texturesContext[plane] = QOpenGLContext::currentContext();
188 Q_ASSERT(bs->texturesContext[plane] !=
nullptr);
190 qCDebug(qLcWaylandCompositorHardwareIntegration)
192 <<
"(eglstream) creating a cleanup-lambda for QOpenGLContext::aboutToBeDestroyed!"
193 <<
", texture: " << bs->textures[plane]
194 <<
", ctx: " << (
void*)bs->texturesContext[plane];
196 bs->texturesAboutToBeDestroyedConnection[plane] =
197 QObject::connect(bs->texturesContext[plane], &QOpenGLContext::aboutToBeDestroyed,
198 bs->texturesContext[plane], [bs, plane]() {
200 QMutexLocker locker(&bs->texturesLock);
204 if (bs->textures[plane] ==
nullptr)
207 delete bs->textures[plane];
209 qCDebug(qLcWaylandCompositorHardwareIntegration)
211 <<
"texture deleted due to QOpenGLContext::aboutToBeDestroyed!"
212 <<
"Pointer (now dead) was:" << (
void*)(bs->textures[plane])
213 <<
" Associated context (about to die too) is: " << (
void*)(bs->texturesContext[plane]);
215 bs->textures[plane] =
nullptr;
216 bs->texturesContext[plane] =
nullptr;
218 QObject::disconnect(bs->texturesAboutToBeDestroyedConnection[plane]);
219 bs->texturesAboutToBeDestroyedConnection[plane] = QMetaObject::Connection();
221 }, Qt::DirectConnection);
233 state.egl_stream = funcs->create_stream_from_file_descriptor(egl_display, streamFd);
236 EGLAttrib stream_attribs[] = {
240 state.egl_stream = funcs->create_stream_attrib_nv(egl_display, stream_attribs);
244 qWarning(
"%s:%d: eglCreateStreamFromFileDescriptorKHR failed: 0x%x", Q_FUNC_INFO, __LINE__, eglGetError());
250 Q_ASSERT(QOpenGLContext::currentContext());
254 setupBufferAndCleanup(buffer->d, texture, 0);
258 auto newStream = funcs->stream_consumer_gltexture(egl_display, state.egl_stream);
259 if (usingLocalContext)
260 localContext->doneCurrent();
263 EGLint code = eglGetError();
264 qWarning() <<
"Could not initialize EGLStream:" << egl_error_string(code) << Qt::hex << (
long)code;
265 funcs->destroy_stream(egl_display, state.egl_stream);
277 auto texture = state.textures[0];
285 if (funcs->stream_consumer_acquire(egl_display, state.egl_stream) != EGL_TRUE)
286 qWarning(
"%s:%d: eglStreamConsumerAcquireKHR failed: 0x%x", Q_FUNC_INFO, __LINE__, eglGetError());
289 if (usingLocalContext)
290 localContext->doneCurrent();
295 : d_ptr(
new WaylandEglStreamClientBufferIntegrationPrivate)
301 Q_D(WaylandEglStreamClientBufferIntegration);
303 if (d->egl_unbind_wayland_display !=
nullptr && d->display_bound) {
304 Q_ASSERT(d->wlDisplay !=
nullptr);
305 if (!d->egl_unbind_wayland_display(d->egl_display, d->wlDisplay))
306 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"eglUnbindWaylandDisplayWL failed";
312 Q_D(WaylandEglStreamClientBufferIntegration);
313 Q_UNUSED(wl_surface);
315 auto *clientBuffer =
new WaylandEglStreamClientBuffer(
this, wl_buffer);
316 auto *bufferManager = QWaylandCompositorPrivate::get(m_compositor)->bufferManager();
317 bufferManager->registerBuffer(wl_buffer, clientBuffer);
319 d->initEglStream(clientBuffer, wl_buffer);
324 Q_D(WaylandEglStreamClientBufferIntegration);
326 const bool ignoreBindDisplay = !qgetenv(
"QT_WAYLAND_IGNORE_BIND_DISPLAY").isEmpty();
328 QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
329 if (!nativeInterface) {
330 qWarning(
"QtCompositor: Failed to initialize EGL display. No native platform interface available.");
334 d->egl_display = nativeInterface->nativeResourceForIntegration(
"EglDisplay");
335 if (!d->egl_display) {
336 qWarning(
"QtCompositor: Failed to initialize EGL display. Could not get EglDisplay for window.");
340 const char *extensionString = eglQueryString(d->egl_display, EGL_EXTENSIONS);
341 if ((!extensionString || !strstr(extensionString,
"EGL_WL_bind_wayland_display")) && !ignoreBindDisplay) {
342 qWarning(
"QtCompositor: Failed to initialize EGL display. There is no EGL_WL_bind_wayland_display extension.");
346 d->egl_bind_wayland_display =
reinterpret_cast<PFNEGLBINDWAYLANDDISPLAYWL>(eglGetProcAddress(
"eglBindWaylandDisplayWL"));
347 d->egl_unbind_wayland_display =
reinterpret_cast<PFNEGLUNBINDWAYLANDDISPLAYWL>(eglGetProcAddress(
"eglUnbindWaylandDisplayWL"));
348 if ((!d->egl_bind_wayland_display || !d->egl_unbind_wayland_display) && !ignoreBindDisplay) {
349 qWarning(
"QtCompositor: Failed to initialize EGL display. Could not find eglBindWaylandDisplayWL and eglUnbindWaylandDisplayWL.");
353 d->egl_query_wayland_buffer =
reinterpret_cast<PFNEGLQUERYWAYLANDBUFFERWL_compat>(eglGetProcAddress(
"eglQueryWaylandBufferWL"));
354 if (!d->egl_query_wayland_buffer) {
355 qWarning(
"QtCompositor: Failed to initialize EGL display. Could not find eglQueryWaylandBufferWL.");
359 if (d->egl_bind_wayland_display && d->egl_unbind_wayland_display) {
360 d->display_bound = d->egl_bind_wayland_display(d->egl_display, display);
361 if (!d->display_bound)
362 qCDebug(qLcWaylandCompositorHardwareIntegration) <<
"Wayland display already bound by other client buffer integration.";
364 d->wlDisplay = display;
367 d->eglStreamController =
new WaylandEglStreamController(display,
this);
369 d->funcs =
new QEGLStreamConvenience;
370 d->funcs->initialize(d->egl_display);
375 if (wl_shm_buffer_get(buffer))
378 return new WaylandEglStreamClientBuffer(
this, buffer);
383 : ClientBuffer(buffer)
384 , m_integration(integration)
388 if (buffer && !wl_shm_buffer_get(buffer)) {
389 EGLint width, height;
390 p->egl_query_wayland_buffer(p->egl_display, buffer, EGL_WIDTH, &width);
391 p->egl_query_wayland_buffer(p->egl_display, buffer, EGL_HEIGHT, &height);
392 d->size = QSize(width, height);
402 p->funcs->destroy_stream(p->egl_display, d
->egl_stream);
406 QMutexLocker locker(&d->texturesLock);
408 for (
int i=0; i<3; i++) {
409 if (d->textures[i] !=
nullptr) {
411 qCDebug(qLcWaylandCompositorHardwareIntegration)
412 << Q_FUNC_INFO <<
" handing over texture!"
413 << (
void*)d->textures[i] <<
"; " << (
void*)d->texturesContext[i]
414 <<
" ... current context might be the same: " << QOpenGLContext::currentContext();
416 QtWayland::QWaylandTextureOrphanage::instance()->admitTexture(
417 d->textures[i], d->texturesContext[i]);
418 d->textures[i] =
nullptr;
419 d->texturesContext[i] =
nullptr;
420 QObject::disconnect(d->texturesAboutToBeDestroyedConnection[i]);
421 d->texturesAboutToBeDestroyedConnection[i] = QMetaObject::Connection();
432 return QWaylandBufferRef::BufferFormatEgl_EXTERNAL_OES;
443 return d->isYInverted ? QWaylandSurface::OriginTopLeft : QWaylandSurface::OriginBottomLeft;
449 QtWayland::QWaylandTextureOrphanage::instance()->deleteTextures();
454 return d->textures[plane];
459 ClientBuffer::setCommitted(damage);
QEGLStreamConvenience * funcs
QOffscreenSurface * offscreenSurface
WaylandEglStreamClientBufferIntegrationPrivate()=default
bool initEglStream(WaylandEglStreamClientBuffer *buffer, struct ::wl_resource *bufferHandle)
PFNEGLBINDWAYLANDDISPLAYWL egl_bind_wayland_display
PFNEGLUNBINDWAYLANDDISPLAYWL egl_unbind_wayland_display
void handleEglstreamTexture(WaylandEglStreamClientBuffer *buffer)
void setupBufferAndCleanup(ControllerBufferState *bs, QOpenGLTexture *texture, int plane)
PFNEGLQUERYWAYLANDBUFFERWL_compat egl_query_wayland_buffer
static WaylandEglStreamClientBufferIntegrationPrivate * get(WaylandEglStreamClientBufferIntegration *integration)
QOpenGLContext * localContext
WaylandEglStreamController * eglStreamController
void initializeHardware(struct ::wl_display *display) override
void attachEglStreamConsumer(struct ::wl_resource *wl_surface, struct ::wl_resource *wl_buffer)
QtWayland::ClientBuffer * createBufferFor(wl_resource *buffer) override
~WaylandEglStreamClientBufferIntegration() override
QOpenGLTexture * toOpenGlTexture(int plane) override
QWaylandSurface::Origin origin() const override
~WaylandEglStreamClientBuffer() override
void setCommitted(QRegion &damage) override
QWaylandBufferRef::BufferFormatEgl bufferFormatEgl() const override
QSize size() const override
#define EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR
#define EGL_STREAM_STATE_KHR
#define EGL_NO_STREAM_KHR
#define EGL_NO_FILE_DESCRIPTOR_KHR
#define EGL_PLATFORM_X11_KHR
#define GL_TEXTURE_EXTERNAL_OES
ControllerBufferState()=default
QMetaObject::Connection texturesAboutToBeDestroyedConnection[3]
QOpenGLTexture * textures[3]
QOpenGLContext * texturesContext[3]
#define EGL_TEXTURE_Y_U_V_WL
#define EGL_TEXTURE_EXTERNAL_WL
#define EGL_WAYLAND_BUFFER_WL
#define EGL_TEXTURE_Y_XUXV_WL
#define EGL_WAYLAND_Y_INVERTED_WL
#define EGL_WAYLAND_PLANE_WL
#define EGL_TEXTURE_Y_UV_WL
#define EGL_WAYLAND_EGLSTREAM_WL
QT_BEGIN_NAMESPACE typedef struct wl_resource EGLint attribute
static const char * egl_error_string(EGLint code)
QT_BEGIN_NAMESPACE typedef EGLBoolean(EGLAPIENTRYP PFNEGLQUERYWAYLANDBUFFERWL_compat)(EGLDisplay dpy
QT_BEGIN_NAMESPACE typedef struct wl_resource * buffer
QT_BEGIN_NAMESPACE typedef struct wl_resource EGLint EGLint * value