7#include <QtWaylandCompositor/QWaylandCompositor>
8#include <QtOpenGL/QOpenGLTexture>
9#include <QtGui/QGuiApplication>
10#include <QtGui/QOpenGLContext>
11#include <QtGui/QOffscreenSurface>
12#include <QtCore/QMutexLocker>
14#include <QtGui/private/qeglstreamconvenience_p.h>
15#include <qpa/qplatformnativeinterface.h>
17#include <QtWaylandCompositor/private/qwaylandcompositor_p.h>
18#include <QtWaylandCompositor/private/qwlbuffermanager_p.h>
19#include <QtWaylandCompositor/private/qwltextureorphanage_p.h>
22#include <EGL/eglext.h>
25#ifndef GL_TEXTURE_EXTERNAL_OES
26#define GL_TEXTURE_EXTERNAL_OES 0x8D65
30#define EGL_WAYLAND_BUFFER_WL 0x31D5
33#ifndef EGL_WAYLAND_EGLSTREAM_WL
34#define EGL_WAYLAND_EGLSTREAM_WL 0x334B
38#define EGL_WAYLAND_PLANE_WL 0x31D6
42#define EGL_WAYLAND_Y_INVERTED_WL 0x31DB
46#define EGL_TEXTURE_RGB 0x305D
50#define EGL_TEXTURE_RGBA 0x305E
54#define EGL_TEXTURE_EXTERNAL_WL 0x31DA
58#define EGL_TEXTURE_Y_U_V_WL 0x31D7
62#define EGL_TEXTURE_Y_UV_WL 0x31D8
66#define EGL_TEXTURE_Y_XUXV_WL 0x31D9
70#define EGL_PLATFORM_X11_KHR 0x31D5
78#ifndef EGL_WL_bind_wayland_display
79typedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDWAYLANDDISPLAYWL) (EGLDisplay dpy,
struct wl_display *display);
80typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNBINDWAYLANDDISPLAYWL) (EGLDisplay dpy,
struct wl_display *display);
86#define MYERRCODE(x) case x: return #x;
149 return shuttingDown ?
nullptr : integration->d_ptr.data();
159 bool localContextNeeded =
false;
160 if (!QOpenGLContext::currentContext()) {
161 if (!localContext && QOpenGLContext::globalShareContext()) {
162 localContext =
new QOpenGLContext;
163 localContext->setShareContext(QOpenGLContext::globalShareContext());
164 localContext->create();
167 if (!offscreenSurface) {
168 offscreenSurface =
new QOffscreenSurface;
169 offscreenSurface->setFormat(localContext->format());
170 offscreenSurface->create();
172 localContext->makeCurrent(offscreenSurface);
173 localContextNeeded =
true;
176 return localContextNeeded;
182 QMutexLocker locker(&bs->texturesLock);
184 bs->textures[plane] = texture;
185 bs->texturesContext[plane] = QOpenGLContext::currentContext();
187 Q_ASSERT(bs->texturesContext[plane] !=
nullptr);
189 qCDebug(qLcWaylandCompositorHardwareIntegration)
191 <<
"(eglstream) creating a cleanup-lambda for QOpenGLContext::aboutToBeDestroyed!"
192 <<
", texture: " << bs->textures[plane]
193 <<
", ctx: " << (
void*)bs->texturesContext[plane];
195 bs->texturesAboutToBeDestroyedConnection[plane] =
196 QObject::connect(bs->texturesContext[plane], &QOpenGLContext::aboutToBeDestroyed,
197 bs->texturesContext[plane], [bs, plane]() {
199 QMutexLocker locker(&bs->texturesLock);
203 if (bs->textures[plane] ==
nullptr)
206 delete bs->textures[plane];
208 qCDebug(qLcWaylandCompositorHardwareIntegration)
210 <<
"texture deleted due to QOpenGLContext::aboutToBeDestroyed!"
211 <<
"Pointer (now dead) was:" << (
void*)(bs->textures[plane])
212 <<
" Associated context (about to die too) is: " << (
void*)(bs->texturesContext[plane]);
214 bs->textures[plane] =
nullptr;
215 bs->texturesContext[plane] =
nullptr;
217 QObject::disconnect(bs->texturesAboutToBeDestroyedConnection[plane]);
218 bs->texturesAboutToBeDestroyedConnection[plane] = QMetaObject::Connection();
220 }, Qt::DirectConnection);
232 state.egl_stream = funcs->create_stream_from_file_descriptor(egl_display, streamFd);
235 EGLAttrib stream_attribs[] = {
239 state.egl_stream = funcs->create_stream_attrib_nv(egl_display, stream_attribs);
243 qWarning(
"%s:%d: eglCreateStreamFromFileDescriptorKHR failed: 0x%x", Q_FUNC_INFO, __LINE__, eglGetError());
249 Q_ASSERT(QOpenGLContext::currentContext());
253 setupBufferAndCleanup(buffer->d, texture, 0);
257 auto newStream = funcs->stream_consumer_gltexture(egl_display, state.egl_stream);
258 if (usingLocalContext)
259 localContext->doneCurrent();
262 EGLint code = eglGetError();
263 qWarning() <<
"Could not initialize EGLStream:" << egl_error_string(code) << Qt::hex << (
long)code;
264 funcs->destroy_stream(egl_display, state.egl_stream);
276 auto texture = state.textures[0];
284 if (funcs->stream_consumer_acquire(egl_display, state.egl_stream) != EGL_TRUE)
285 qWarning(
"%s:%d: eglStreamConsumerAcquireKHR failed: 0x%x", Q_FUNC_INFO, __LINE__, eglGetError());
288 if (usingLocalContext)
289 localContext->doneCurrent();
294 : d_ptr(
new WaylandEglStreamClientBufferIntegrationPrivate)
300 Q_D(WaylandEglStreamClientBufferIntegration);
302 if (d->egl_unbind_wayland_display !=
nullptr && d->display_bound) {
303 Q_ASSERT(d->wlDisplay !=
nullptr);
304 if (!d->egl_unbind_wayland_display(d->egl_display, d->wlDisplay))
305 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"eglUnbindWaylandDisplayWL failed";
311 Q_D(WaylandEglStreamClientBufferIntegration);
312 Q_UNUSED(wl_surface);
314 auto *clientBuffer =
new WaylandEglStreamClientBuffer(
this, wl_buffer);
315 auto *bufferManager = QWaylandCompositorPrivate::get(m_compositor)->bufferManager();
316 bufferManager->registerBuffer(wl_buffer, clientBuffer);
318 d->initEglStream(clientBuffer, wl_buffer);
323 Q_D(WaylandEglStreamClientBufferIntegration);
325 const bool ignoreBindDisplay = !qgetenv(
"QT_WAYLAND_IGNORE_BIND_DISPLAY").isEmpty();
327 QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
328 if (!nativeInterface) {
329 qWarning(
"QtCompositor: Failed to initialize EGL display. No native platform interface available.");
333 d->egl_display = nativeInterface->nativeResourceForIntegration(
"EglDisplay");
334 if (!d->egl_display) {
335 qWarning(
"QtCompositor: Failed to initialize EGL display. Could not get EglDisplay for window.");
339 const char *extensionString = eglQueryString(d->egl_display, EGL_EXTENSIONS);
340 if ((!extensionString || !strstr(extensionString,
"EGL_WL_bind_wayland_display")) && !ignoreBindDisplay) {
341 qWarning(
"QtCompositor: Failed to initialize EGL display. There is no EGL_WL_bind_wayland_display extension.");
345 d->egl_bind_wayland_display =
reinterpret_cast<PFNEGLBINDWAYLANDDISPLAYWL>(eglGetProcAddress(
"eglBindWaylandDisplayWL"));
346 d->egl_unbind_wayland_display =
reinterpret_cast<PFNEGLUNBINDWAYLANDDISPLAYWL>(eglGetProcAddress(
"eglUnbindWaylandDisplayWL"));
347 if ((!d->egl_bind_wayland_display || !d->egl_unbind_wayland_display) && !ignoreBindDisplay) {
348 qWarning(
"QtCompositor: Failed to initialize EGL display. Could not find eglBindWaylandDisplayWL and eglUnbindWaylandDisplayWL.");
352 d->egl_query_wayland_buffer =
reinterpret_cast<PFNEGLQUERYWAYLANDBUFFERWL_compat>(eglGetProcAddress(
"eglQueryWaylandBufferWL"));
353 if (!d->egl_query_wayland_buffer) {
354 qWarning(
"QtCompositor: Failed to initialize EGL display. Could not find eglQueryWaylandBufferWL.");
358 if (d->egl_bind_wayland_display && d->egl_unbind_wayland_display) {
359 d->display_bound = d->egl_bind_wayland_display(d->egl_display, display);
360 if (!d->display_bound)
361 qCDebug(qLcWaylandCompositorHardwareIntegration) <<
"Wayland display already bound by other client buffer integration.";
363 d->wlDisplay = display;
366 d->eglStreamController =
new WaylandEglStreamController(display,
this);
368 d->funcs =
new QEGLStreamConvenience;
369 d->funcs->initialize(d->egl_display);
374 if (wl_shm_buffer_get(buffer))
377 return new WaylandEglStreamClientBuffer(
this, buffer);
382 : ClientBuffer(buffer)
383 , m_integration(integration)
387 if (buffer && !wl_shm_buffer_get(buffer)) {
388 EGLint width, height;
389 p->egl_query_wayland_buffer(p->egl_display, buffer, EGL_WIDTH, &width);
390 p->egl_query_wayland_buffer(p->egl_display, buffer, EGL_HEIGHT, &height);
391 d->size = QSize(width, height);
401 p->funcs->destroy_stream(p->egl_display, d
->egl_stream);
405 QMutexLocker locker(&d->texturesLock);
407 for (
int i=0; i<3; i++) {
408 if (d->textures[i] !=
nullptr) {
410 qCDebug(qLcWaylandCompositorHardwareIntegration)
411 << Q_FUNC_INFO <<
" handing over texture!"
412 << (
void*)d->textures[i] <<
"; " << (
void*)d->texturesContext[i]
413 <<
" ... current context might be the same: " << QOpenGLContext::currentContext();
415 QtWayland::QWaylandTextureOrphanage::instance()->admitTexture(
416 d->textures[i], d->texturesContext[i]);
417 d->textures[i] =
nullptr;
418 d->texturesContext[i] =
nullptr;
419 QObject::disconnect(d->texturesAboutToBeDestroyedConnection[i]);
420 d->texturesAboutToBeDestroyedConnection[i] = QMetaObject::Connection();
431 return QWaylandBufferRef::BufferFormatEgl_EXTERNAL_OES;
442 return d->isYInverted ? QWaylandSurface::OriginTopLeft : QWaylandSurface::OriginBottomLeft;
448 QtWayland::QWaylandTextureOrphanage::instance()->deleteTextures();
453 return d->textures[plane];
458 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