Move client hardware integration sources into the plugin folder

Change-Id: I49629ce1d55d8762ab30c33062fb78b05fdb05d4
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
This commit is contained in:
David Redondo 2025-02-28 12:14:06 +01:00
parent ab73b6c286
commit 58e68f1981
31 changed files with 2885 additions and 24 deletions

View File

@ -11,12 +11,10 @@ qt_internal_add_plugin(QWaylandBrcmEglClientBufferPlugin
OUTPUT_NAME brcm-egl
PLUGIN_TYPE wayland-graphics-integration-client
SOURCES
../../../../hardwareintegration/client/brcm-egl/qwaylandbrcmeglintegration.cpp ../../../../hardwareintegration/client/brcm-egl/qwaylandbrcmeglintegration.h
../../../../hardwareintegration/client/brcm-egl/qwaylandbrcmeglwindow.cpp ../../../../hardwareintegration/client/brcm-egl/qwaylandbrcmeglwindow.h
../../../../hardwareintegration/client/brcm-egl/qwaylandbrcmglcontext.cpp ../../../../hardwareintegration/client/brcm-egl/qwaylandbrcmglcontext.h
qwaylandbrcmeglintegration.cpp qwaylandbrcmeglintegration.h
qwaylandbrcmeglwindow.cpp qwaylandbrcmeglwindow.h
qwaylandbrcmglcontext.cpp qwaylandbrcmglcontext.h
main.cpp
INCLUDE_DIRECTORIES
../../../../hardwareintegration/client/brcm-egl
PUBLIC_LIBRARIES
${CMAKE_DL_LIBS}
EGL::EGL
@ -30,7 +28,7 @@ qt_internal_add_plugin(QWaylandBrcmEglClientBufferPlugin
qt6_generate_wayland_protocol_client_sources(QWaylandBrcmEglClientBufferPlugin
PRIVATE_CODE
FILES
${CMAKE_CURRENT_SOURCE_DIR}/../../../../hardwareintegration/client/brcm-egl/../../../extensions/brcm.xml
${CMAKE_CURRENT_SOURCE_DIR}/../../../extensions/brcm.xml
)
#### Keys ignored in scope 1:.:.:brcm-egl.pro:<TRUE>:

View File

@ -0,0 +1,121 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwaylandbrcmeglintegration.h"
#include <QtWaylandClient/private/qwaylandclientbufferintegration_p.h>
#include "qwaylandbrcmeglwindow.h"
#include "qwaylandbrcmglcontext.h"
#include <QtCore/QDebug>
#include "wayland-brcm-client-protocol.h"
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
QWaylandBrcmEglIntegration::QWaylandBrcmEglIntegration()
{
qDebug() << "Using Brcm-EGL";
}
void QWaylandBrcmEglIntegration::wlDisplayHandleGlobal(void *data, struct ::wl_registry *registry, uint32_t id, const QString &interface, uint32_t version)
{
Q_UNUSED(version);
if (interface == "qt_brcm") {
QWaylandBrcmEglIntegration *integration = static_cast<QWaylandBrcmEglIntegration *>(data);
integration->m_waylandBrcm = static_cast<struct qt_brcm *>(wl_registry_bind(registry, id, &qt_brcm_interface, 1));
}
}
qt_brcm *QWaylandBrcmEglIntegration::waylandBrcm() const
{
return m_waylandBrcm;
}
QWaylandBrcmEglIntegration::~QWaylandBrcmEglIntegration()
{
eglTerminate(m_eglDisplay);
}
void QWaylandBrcmEglIntegration::initialize(QWaylandDisplay *waylandDisplay)
{
m_display = waylandDisplay;
m_waylandDisplay = waylandDisplay->wl_display();
waylandDisplay->addRegistryListener(wlDisplayHandleGlobal, this);
EGLint major,minor;
m_eglDisplay = eglGetDisplay((EGLNativeDisplayType)EGL_DEFAULT_DISPLAY);
if (m_eglDisplay == NULL) {
qWarning("EGL not available");
} else {
if (!eglInitialize(m_eglDisplay, &major, &minor)) {
qWarning("failed to initialize EGL display");
return;
}
eglFlushBRCM = (PFNEGLFLUSHBRCMPROC)eglGetProcAddress("eglFlushBRCM");
if (!eglFlushBRCM) {
qWarning("failed to resolve eglFlushBRCM, performance will suffer");
}
eglCreateGlobalImageBRCM = (PFNEGLCREATEGLOBALIMAGEBRCMPROC)eglGetProcAddress("eglCreateGlobalImageBRCM");
if (!eglCreateGlobalImageBRCM) {
qWarning("failed to resolve eglCreateGlobalImageBRCM");
return;
}
eglDestroyGlobalImageBRCM = (PFNEGLDESTROYGLOBALIMAGEBRCMPROC)eglGetProcAddress("eglDestroyGlobalImageBRCM");
if (!eglDestroyGlobalImageBRCM) {
qWarning("failed to resolve eglDestroyGlobalImageBRCM");
return;
}
}
}
QWaylandWindow *QWaylandBrcmEglIntegration::createEglWindow(QWindow *window)
{
return new QWaylandBrcmEglWindow(window, m_display);
}
QPlatformOpenGLContext *QWaylandBrcmEglIntegration::createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const
{
return new QWaylandBrcmGLContext(m_eglDisplay, glFormat, share);
}
EGLDisplay QWaylandBrcmEglIntegration::eglDisplay() const
{
return m_eglDisplay;
}
void *QWaylandBrcmEglIntegration::nativeResource(NativeResource resource)
{
switch (resource) {
case EglDisplay:
return m_eglDisplay;
default:
break;
}
return nullptr;
}
void *QWaylandBrcmEglIntegration::nativeResourceForContext(NativeResource resource, QPlatformOpenGLContext *context)
{
Q_ASSERT(context);
switch (resource) {
case EglConfig:
return static_cast<QWaylandBrcmGLContext *>(context)->eglConfig();
case EglContext:
return static_cast<QWaylandBrcmGLContext *>(context)->eglContext();
case EglDisplay:
return m_eglDisplay;
default:
break;
}
return nullptr;
}
}
QT_END_NAMESPACE

View File

@ -0,0 +1,68 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWAYLANDBRCMEGLINTEGRATION_H
#define QWAYLANDBRCMEGLINTEGRATION_H
#include <QtWaylandClient/private/qwaylandclientbufferintegration_p.h>
#include <QtWaylandClient/private/wayland-wayland-client-protocol.h>
#include <wayland-client-core.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <EGL/eglext_brcm.h>
#include <QtCore/qglobal.h>
struct qt_brcm;
QT_BEGIN_NAMESPACE
class QWindow;
namespace QtWaylandClient {
class QWaylandWindow;
class QWaylandBrcmEglIntegration : public QWaylandClientBufferIntegration
{
public:
QWaylandBrcmEglIntegration();
~QWaylandBrcmEglIntegration();
void initialize(QWaylandDisplay *waylandDisplay) override;
bool supportsThreadedOpenGL() const override { return true; }
bool supportsWindowDecoration() const override { return false; }
QWaylandWindow *createEglWindow(QWindow *window);
QPlatformOpenGLContext *createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const override;
EGLDisplay eglDisplay() const;
struct qt_brcm *waylandBrcm() const;
PFNEGLFLUSHBRCMPROC eglFlushBRCM;
PFNEGLCREATEGLOBALIMAGEBRCMPROC eglCreateGlobalImageBRCM;
PFNEGLDESTROYGLOBALIMAGEBRCMPROC eglDestroyGlobalImageBRCM;
void *nativeResource(NativeResource resource) override;
void *nativeResourceForContext(NativeResource resource, QPlatformOpenGLContext *context) override;
private:
static void wlDisplayHandleGlobal(void *data, struct ::wl_registry *registry, uint32_t id, const QString &interface, uint32_t version);
struct wl_display *m_waylandDisplay = nullptr;
struct qt_brcm *m_waylandBrcm = nullptr;
EGLDisplay m_eglDisplay = EGL_NO_DISPLAY;
QWaylandDisplay *m_display = nullptr;
};
}
QT_END_NAMESPACE
#endif // QWAYLANDBRCMEGLINTEGRATION_H

View File

@ -0,0 +1,230 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwaylandbrcmeglwindow.h"
#include <QtWaylandClient/private/qwaylandbuffer_p.h>
#include <QtWaylandClient/private/qwaylandscreen_p.h>
#include "qwaylandbrcmglcontext.h"
#include <QtGui/private/qeglconvenience_p.h>
#include <QtGui/QWindow>
#include <qpa/qwindowsysteminterface.h>
#include <EGL/eglext_brcm.h>
#include "wayland-brcm-client-protocol.h"
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
class QWaylandBrcmBuffer : public QWaylandBuffer
{
public:
QWaylandBrcmBuffer(QWaylandDisplay *display,
struct qt_brcm *brcm,
const QSize &size,
EGLint *data,
int count,
struct wl_event_queue *eventQueue)
: m_size(size)
, m_display(display)
, m_eventQueue(eventQueue)
{
wl_array_init(&m_array);
m_data = static_cast<EGLint *>(wl_array_add(&m_array, count * sizeof(EGLint)));
for (int i = 0; i < count; ++i)
m_data[i] = data[i];
mBuffer = qt_brcm_create_buffer(brcm, size.width(), size.height(), &m_array);
wl_proxy_set_queue(reinterpret_cast<struct wl_proxy*>(mBuffer), m_eventQueue);
static const struct wl_buffer_listener buffer_listener = {
QWaylandBrcmBuffer::buffer_release
};
wl_buffer_add_listener(mBuffer, &buffer_listener, this);
}
~QWaylandBrcmBuffer()
{
wl_array_release(&m_array);
wl_buffer_destroy(mBuffer);
mBuffer = nullptr;
}
QSize size() const { return m_size; }
void bind()
{
m_released = false;
}
void waitForRelease()
{
if (m_released)
return;
while (!m_released) {
wl_display_dispatch_queue(m_display->wl_display(), m_eventQueue);
}
}
static void buffer_release(void *data, wl_buffer *buffer)
{
Q_UNUSED(buffer);
static_cast<QWaylandBrcmBuffer *>(data)->m_released = true;
}
private:
QSize m_size;
bool m_released = true;
wl_array m_array;
EGLint *m_data = nullptr;
QWaylandDisplay *m_display = nullptr;
struct wl_event_queue *m_eventQueue = nullptr;
};
QWaylandBrcmEglWindow::QWaylandBrcmEglWindow(QWindow *window, QWaylandDisplay *display)
: QWaylandWindow(window, display)
, m_eglIntegration(static_cast<QWaylandBrcmEglIntegration *>(mDisplay->clientBufferIntegration()))
, m_format(window->format())
, m_eventQueue(wl_display_create_queue(mDisplay->wl_display()))
{
}
QWaylandBrcmEglWindow::~QWaylandBrcmEglWindow()
{
destroyEglSurfaces();
}
QWaylandWindow::WindowType QWaylandBrcmEglWindow::windowType() const
{
return QWaylandWindow::Egl;
}
void QWaylandBrcmEglWindow::setGeometry(const QRect &rect)
{
destroyEglSurfaces();
QWaylandWindow::setGeometry(rect);
}
QSurfaceFormat QWaylandBrcmEglWindow::format() const
{
return m_format;
}
void QWaylandBrcmEglWindow::destroyEglSurfaces()
{
for (int i = 0; i < m_count; ++i) {
if (m_eglSurfaces[i]) {
eglDestroySurface(m_eglIntegration->eglDisplay(), m_eglSurfaces[i]);
m_eglSurfaces[i] = 0;
// the server does this
//m_eglIntegration->eglDestroyGlobalImageBRCM(&m_globalImages[5*i]);
delete m_buffers[i];
}
}
m_count = 0;
m_current = 0;
}
QSurfaceFormat brcmFixFormat(const QSurfaceFormat &f)
{
QSurfaceFormat format = f;
format.setRedBufferSize(8);
format.setGreenBufferSize(8);
format.setBlueBufferSize(8);
format.setAlphaBufferSize(8);
return format;
}
void QWaylandBrcmEglWindow::createEglSurfaces()
{
QSize size(geometry().size());
m_count = window()->format().swapBehavior() == QSurfaceFormat::TripleBuffer ? 3 : 2;
EGLConfig eglConfig = q_configFromGLFormat(m_eglIntegration->eglDisplay(), brcmFixFormat(window()->format()), true, EGL_PIXMAP_BIT);
m_format = q_glFormatFromConfig(m_eglIntegration->eglDisplay(), eglConfig);
EGLint pixel_format = EGL_PIXEL_FORMAT_ARGB_8888_BRCM;
EGLint rt;
eglGetConfigAttrib(m_eglIntegration->eglDisplay(), eglConfig, EGL_RENDERABLE_TYPE, &rt);
if (rt & EGL_OPENGL_ES_BIT) {
pixel_format |= EGL_PIXEL_FORMAT_RENDER_GLES_BRCM;
pixel_format |= EGL_PIXEL_FORMAT_GLES_TEXTURE_BRCM;
}
if (rt & EGL_OPENGL_ES2_BIT) {
pixel_format |= EGL_PIXEL_FORMAT_RENDER_GLES2_BRCM;
pixel_format |= EGL_PIXEL_FORMAT_GLES2_TEXTURE_BRCM;
}
if (rt & EGL_OPENVG_BIT) {
pixel_format |= EGL_PIXEL_FORMAT_RENDER_VG_BRCM;
pixel_format |= EGL_PIXEL_FORMAT_VG_IMAGE_BRCM;
}
if (rt & EGL_OPENGL_BIT) {
pixel_format |= EGL_PIXEL_FORMAT_RENDER_GL_BRCM;
}
memset(m_globalImages, 0, 5 * m_count * sizeof(EGLint));
for (int i = 0; i < m_count; ++i) {
m_eglIntegration->eglCreateGlobalImageBRCM(size.width(), size.height(), pixel_format,
0, size.width() * 4, &m_globalImages[5*i]);
m_globalImages[5*i+2] = size.width();
m_globalImages[5*i+3] = size.height();
m_globalImages[5*i+4] = pixel_format;
EGLint attrs[] = {
EGL_VG_COLORSPACE, EGL_VG_COLORSPACE_sRGB,
EGL_VG_ALPHA_FORMAT, pixel_format & EGL_PIXEL_FORMAT_ARGB_8888_PRE_BRCM ? EGL_VG_ALPHA_FORMAT_PRE : EGL_VG_ALPHA_FORMAT_NONPRE,
EGL_NONE
};
m_eglSurfaces[i] = eglCreatePixmapSurface(m_eglIntegration->eglDisplay(), eglConfig, (EGLNativePixmapType)&m_globalImages[5*i], attrs);
if (m_eglSurfaces[i] == EGL_NO_SURFACE)
qFatal("eglCreatePixmapSurface failed: %x, global image id: %d %d\n", eglGetError(), m_globalImages[5*i], m_globalImages[5*i+1]);
m_buffers[i] = new QWaylandBrcmBuffer(mDisplay, m_eglIntegration->waylandBrcm(), size, &m_globalImages[5*i], 5, m_eventQueue);
}
}
void QWaylandBrcmEglWindow::swapBuffers()
{
if (m_eglIntegration->eglFlushBRCM) {
m_eglIntegration->eglFlushBRCM();
} else {
glFlush();
glFinish();
}
if (!m_count)
return;
m_buffers[m_current]->bind();
commit(m_buffers[m_current], QRegion(0, 0, geometry().size().width(), geometry().size().height()));
m_current = (m_current + 1) % m_count;
m_buffers[m_current]->waitForRelease();
}
bool QWaylandBrcmEglWindow::makeCurrent(EGLContext context)
{
if (!m_count)
const_cast<QWaylandBrcmEglWindow *>(this)->createEglSurfaces();
return eglMakeCurrent(m_eglIntegration->eglDisplay(), m_eglSurfaces[m_current], m_eglSurfaces[m_current], context);
}
}
QT_END_NAMESPACE

View File

@ -0,0 +1,59 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWAYLANDBRCMEGLWINDOW_H
#define QWAYLANDBRCMEGLWINDOW_H
#include <QtWaylandClient/private/qwaylandwindow_p.h>
#include "qwaylandbrcmeglintegration.h"
#include <QMutex>
#include <EGL/egl.h>
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
class QWaylandBrcmBuffer;
class QWaylandBrcmEglWindow : public QWaylandWindow
{
Q_OBJECT
public:
QWaylandBrcmEglWindow(QWindow *window, QWaylandDisplay *display);
~QWaylandBrcmEglWindow();
WindowType windowType() const override;
void setGeometry(const QRect &rect) override;
QSurfaceFormat format() const override;
bool makeCurrent(EGLContext context);
void swapBuffers();
private:
void createEglSurfaces();
void destroyEglSurfaces();
QWaylandBrcmEglIntegration *m_eglIntegration = nullptr;
struct wl_egl_window *m_waylandEglWindow = nullptr;
const QWaylandWindow *m_parentWindow = nullptr;
EGLint m_globalImages[3*5];
EGLSurface m_eglSurfaces[3];
QWaylandBrcmBuffer *m_buffers[3];
QSurfaceFormat m_format;
struct wl_event_queue *m_eventQueue = nullptr;
int m_current = 0;
int m_count = 0;
};
}
QT_END_NAMESPACE
#endif // QWAYLANDBRCMEGLWINDOW_H

View File

@ -0,0 +1,76 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwaylandbrcmglcontext.h"
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QtWaylandClient/private/qwaylandwindow_p.h>
#include "qwaylandbrcmeglwindow.h"
#include <QtGui/private/qeglconvenience_p.h>
#include <qpa/qplatformopenglcontext.h>
#include <QtGui/QSurfaceFormat>
#include <dlfcn.h>
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
extern QSurfaceFormat brcmFixFormat(const QSurfaceFormat &format);
QWaylandBrcmGLContext::QWaylandBrcmGLContext(EGLDisplay eglDisplay, const QSurfaceFormat &format, QPlatformOpenGLContext *share)
: QPlatformOpenGLContext()
, m_eglDisplay(eglDisplay)
, m_config(q_configFromGLFormat(m_eglDisplay, brcmFixFormat(format), true))
, m_format(q_glFormatFromConfig(m_eglDisplay, m_config))
{
EGLContext shareEGLContext = share ? static_cast<QWaylandBrcmGLContext *>(share)->eglContext() : EGL_NO_CONTEXT;
eglBindAPI(EGL_OPENGL_ES_API);
QList<EGLint> eglContextAttrs;
eglContextAttrs.append(EGL_CONTEXT_CLIENT_VERSION);
eglContextAttrs.append(format.majorVersion() == 1 ? 1 : 2);
eglContextAttrs.append(EGL_NONE);
m_context = eglCreateContext(m_eglDisplay, m_config, shareEGLContext, eglContextAttrs.constData());
}
QWaylandBrcmGLContext::~QWaylandBrcmGLContext()
{
eglDestroyContext(m_eglDisplay, m_context);
}
bool QWaylandBrcmGLContext::makeCurrent(QPlatformSurface *surface)
{
return static_cast<QWaylandBrcmEglWindow *>(surface)->makeCurrent(m_context);
}
void QWaylandBrcmGLContext::doneCurrent()
{
eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
void QWaylandBrcmGLContext::swapBuffers(QPlatformSurface *surface)
{
static_cast<QWaylandBrcmEglWindow *>(surface)->swapBuffers();
}
QFunctionPointer QWaylandBrcmGLContext::getProcAddress(const char *procName)
{
QFunctionPointer proc = (QFunctionPointer) eglGetProcAddress(procName);
if (!proc)
proc = (QFunctionPointer) dlsym(RTLD_DEFAULT, procName);
return proc;
}
EGLConfig QWaylandBrcmGLContext::eglConfig() const
{
return m_config;
}
}
QT_END_NAMESPACE

View File

@ -0,0 +1,48 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWAYLANDBRCMGLCONTEXT_H
#define QWAYLANDBRCMGLCONTEXT_H
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <qpa/qplatformopenglcontext.h>
#include <EGL/egl.h>
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
class QWaylandWindow;
class QWaylandBrcmGLContext : public QPlatformOpenGLContext {
public:
QWaylandBrcmGLContext(EGLDisplay eglDisplay, const QSurfaceFormat &format, QPlatformOpenGLContext *share);
~QWaylandBrcmGLContext();
void swapBuffers(QPlatformSurface *surface) override;
bool makeCurrent(QPlatformSurface *surface) override;
void doneCurrent() override;
QFunctionPointer getProcAddress(const char *procName) override;
QSurfaceFormat format() const override { return m_format; }
EGLConfig eglConfig() const;
EGLContext eglContext() const { return m_context; }
private:
EGLDisplay m_eglDisplay = EGL_NO_DISPLAY;
EGLContext m_context;
EGLConfig m_config;
QSurfaceFormat m_format;
};
}
QT_END_NAMESPACE
#endif // QWAYLANDBRCMGLCONTEXT_H

View File

@ -11,10 +11,8 @@ qt_internal_add_plugin(DmaBufServerBufferPlugin
OUTPUT_NAME dmabuf-server
PLUGIN_TYPE wayland-graphics-integration-client
SOURCES
../../../../hardwareintegration/client/dmabuf-server/dmabufserverbufferintegration.cpp ../../../../hardwareintegration/client/dmabuf-server/dmabufserverbufferintegration.h
dmabufserverbufferintegration.cpp dmabufserverbufferintegration.h
main.cpp
INCLUDE_DIRECTORIES
../../../../hardwareintegration/client/dmabuf-server
LIBRARIES
EGL::EGL
Qt::Core

View File

@ -0,0 +1,152 @@
// Copyright (C) 2018 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "dmabufserverbufferintegration.h"
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QDebug>
#include <QtOpenGL/QOpenGLTexture>
#include <QtGui/QOpenGLContext>
#include <EGL/egl.h>
#include <EGL/eglext.h>
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
DmaBufServerBuffer::DmaBufServerBuffer(DmaBufServerBufferIntegration *integration
, struct ::qt_server_buffer *id
, int32_t fd
, int32_t width
, int32_t height
, int32_t stride
, int32_t offset
, int32_t fourcc_format)
: m_integration(integration)
, m_server_buffer(id)
{
m_size = QSize(width, height);
EGLint import_attribs[] = {
EGL_WIDTH, width,
EGL_HEIGHT, height,
EGL_LINUX_DRM_FOURCC_EXT, fourcc_format,
EGL_DMA_BUF_PLANE0_FD_EXT, fd,
EGL_DMA_BUF_PLANE0_OFFSET_EXT, offset,
EGL_DMA_BUF_PLANE0_PITCH_EXT, stride,
EGL_NONE
};
m_image = integration->eglCreateImageKHR(
EGL_NO_CONTEXT,
EGL_LINUX_DMA_BUF_EXT,
(EGLClientBuffer)nullptr,
import_attribs);
int err = eglGetError();
qCDebug(lcQpaWayland) << "imported egl image" << m_image;
if (m_image == EGL_NO_IMAGE_KHR || err != EGL_SUCCESS)
qCWarning(lcQpaWayland) << "DmaBufServerBuffer error importing image. EGL error code" << Qt::hex << err;
qt_server_buffer_set_user_data(id, this);
}
DmaBufServerBuffer::~DmaBufServerBuffer()
{
int err = m_integration->eglDestroyImageKHR(m_image);
if (err != EGL_SUCCESS)
qCWarning(lcQpaWayland) << "~DmaBufServerBuffer error destroying image" << m_image << "error code " << Qt::hex << err;
qt_server_buffer_release(m_server_buffer);
qt_server_buffer_destroy(m_server_buffer);
}
QOpenGLTexture *DmaBufServerBuffer::toOpenGlTexture()
{
if (!QOpenGLContext::currentContext())
qCWarning(lcQpaWayland) <<"DmaBufServerBuffer: creating texture with no current context";
if (!m_texture) {
m_texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
m_texture->create();
}
m_texture->bind();
m_integration->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_image);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
m_texture->release();
m_texture->setSize(m_size.width(), m_size.height());
return m_texture;
}
void DmaBufServerBufferIntegration::initializeEgl()
{
if (m_egl_initialized)
return;
m_egl_initialized = true;
m_egl_display = eglGetDisplay((EGLNativeDisplayType) m_display->wl_display());
if (m_egl_display == EGL_NO_DISPLAY) {
qCWarning(lcQpaWayland) << "Failed to initialize drm egl server buffer integration. Could not get egl display from wl_display.";
return;
}
const char *extensionString = eglQueryString(m_egl_display, EGL_EXTENSIONS);
if (!extensionString || !strstr(extensionString, "EGL_KHR_image")) {
qCWarning(lcQpaWayland) << "Failed to initialize dmabuf server buffer integration. There is no EGL_KHR_image extension.\n";
return;
}
m_egl_create_image = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress("eglCreateImageKHR"));
m_egl_destroy_image = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(eglGetProcAddress("eglDestroyImageKHR"));
if (!m_egl_create_image || !m_egl_destroy_image) {
qCWarning(lcQpaWayland) << "Failed to initialize dmabuf server buffer integration. Could not resolve eglCreateImageKHR or eglDestroyImageKHR";
return;
}
m_gl_egl_image_target_texture = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES"));
if (!m_gl_egl_image_target_texture) {
qCWarning(lcQpaWayland) << "Failed to initialize dmabuf server buffer integration. Could not resolve glEGLImageTargetTexture2DOES";
return;
}
}
void DmaBufServerBufferIntegration::initialize(QWaylandDisplay *display)
{
m_display = display;
display->addRegistryListener(&wlDisplayHandleGlobal, this);
}
QWaylandServerBuffer *DmaBufServerBufferIntegration::serverBuffer(struct qt_server_buffer *buffer)
{
return static_cast<QWaylandServerBuffer *>(qt_server_buffer_get_user_data(buffer));
}
void DmaBufServerBufferIntegration::wlDisplayHandleGlobal(void *data, ::wl_registry *registry, uint32_t id, const QString &interface, uint32_t version)
{
Q_UNUSED(version);
if (interface == QStringLiteral("qt_dmabuf_server_buffer")) {
auto *integration = static_cast<DmaBufServerBufferIntegration *>(data);
integration->QtWayland::qt_dmabuf_server_buffer::init(registry, id, 1);
}
}
void DmaBufServerBufferIntegration::dmabuf_server_buffer_server_buffer_created(struct ::qt_server_buffer *id
, int32_t name
, int32_t width
, int32_t height
, int32_t stride
, int32_t offset
, int32_t format)
{
(void) new DmaBufServerBuffer(this, id, name, width, height, stride, offset, format);
}
}
QT_END_NAMESPACE

View File

@ -0,0 +1,111 @@
// Copyright (C) 2018 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef DMABUFSERVERBUFFERINTEGRATION_H
#define DMABUFSERVERBUFFERINTEGRATION_H
#include <QtCore/QVariant>
#include <QtWaylandClient/private/qwayland-wayland.h>
#include "qwayland-qt-dmabuf-server-buffer.h"
#include <QtWaylandClient/private/qwaylandserverbufferintegration_p.h>
#include "dmabufserverbufferintegration.h"
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QtCore/QTextStream>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#ifndef EGL_KHR_image
typedef void *EGLImageKHR;
typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image);
#endif
#ifndef GL_OES_EGL_image
typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
#endif
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
class DmaBufServerBufferIntegration;
class DmaBufServerBuffer : public QWaylandServerBuffer
{
public:
DmaBufServerBuffer(DmaBufServerBufferIntegration *integration, struct ::qt_server_buffer *id, int32_t fd,
int32_t width, int32_t height, int32_t stride, int32_t offset, int32_t fourcc_format);
~DmaBufServerBuffer() override;
QOpenGLTexture* toOpenGlTexture() override;
private:
DmaBufServerBufferIntegration *m_integration = nullptr;
EGLImageKHR m_image = EGL_NO_IMAGE_KHR;
QOpenGLTexture *m_texture = nullptr;
struct ::qt_server_buffer *m_server_buffer = nullptr;
};
class DmaBufServerBufferIntegration
: public QWaylandServerBufferIntegration
, public QtWayland::qt_dmabuf_server_buffer
{
public:
void initialize(QWaylandDisplay *display) override;
QWaylandServerBuffer *serverBuffer(struct qt_server_buffer *buffer) override;
inline EGLImageKHR eglCreateImageKHR(EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
inline EGLBoolean eglDestroyImageKHR(EGLImageKHR image);
inline void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image);
protected:
void dmabuf_server_buffer_server_buffer_created(struct ::qt_server_buffer *id, int32_t fd,
int32_t width, int32_t height, int32_t stride,
int32_t offset, int32_t fourcc_format) override;
private:
static void wlDisplayHandleGlobal(void *data, struct ::wl_registry *registry, uint32_t id,
const QString &interface, uint32_t version);
void initializeEgl();
PFNEGLCREATEIMAGEKHRPROC m_egl_create_image = nullptr;
PFNEGLDESTROYIMAGEKHRPROC m_egl_destroy_image = nullptr;
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC m_gl_egl_image_target_texture = nullptr;
QWaylandDisplay *m_display = nullptr;
EGLDisplay m_egl_display = EGL_NO_DISPLAY;
bool m_egl_initialized = false;
};
EGLImageKHR DmaBufServerBufferIntegration::eglCreateImageKHR(EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list)
{
if (!m_egl_initialized)
initializeEgl();
if (!m_egl_create_image) {
qCWarning(lcQpaWayland) << "DmaBufServerBufferIntegration: Trying to use unresolved function eglCreateImageKHR";
return EGL_NO_IMAGE_KHR;
}
return m_egl_create_image(m_egl_display, ctx, target, buffer, attrib_list);
}
EGLBoolean DmaBufServerBufferIntegration::eglDestroyImageKHR(EGLImageKHR image)
{
if (!m_egl_destroy_image) {
qCWarning(lcQpaWayland) << "DmaBufServerBufferIntegration: Trying to use unresolved function eglDestroyImageKHR";
return false;
}
return m_egl_destroy_image(m_egl_display, image);
}
void DmaBufServerBufferIntegration::glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
{
if (!m_gl_egl_image_target_texture) {
qCWarning(lcQpaWayland) << "DmaBufServerBufferIntegration: Trying to use unresolved function glEGLImageTargetTexture2DOES";
return;
}
m_gl_egl_image_target_texture(target, image);
}
}
QT_END_NAMESPACE
#endif

View File

@ -11,10 +11,8 @@ qt_internal_add_plugin(DrmEglServerBufferPlugin
OUTPUT_NAME drm-egl-server
PLUGIN_TYPE wayland-graphics-integration-client
SOURCES
../../../../hardwareintegration/client/drm-egl-server/drmeglserverbufferintegration.cpp ../../../../hardwareintegration/client/drm-egl-server/drmeglserverbufferintegration.h
drmeglserverbufferintegration.cpp drmeglserverbufferintegration.h
main.cpp
INCLUDE_DIRECTORIES
../../../../hardwareintegration/client/drm-egl-server
LIBRARIES
EGL::EGL
Qt::Core

View File

@ -0,0 +1,155 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "drmeglserverbufferintegration.h"
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QDebug>
#include <QtOpenGL/QOpenGLTexture>
#include <QtGui/QOpenGLContext>
#include <EGL/egl.h>
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
DrmServerBuffer::DrmServerBuffer(DrmEglServerBufferIntegration *integration
, int32_t name
, int32_t width
, int32_t height
, int32_t stride
, int32_t format)
: m_integration(integration)
{
m_size = QSize(width, height);
EGLint egl_format;
int32_t format_stride;
switch (format) {
case QtWayland::qt_drm_egl_server_buffer::format_RGBA32:
m_format = QWaylandServerBuffer::RGBA32;
egl_format = EGL_DRM_BUFFER_FORMAT_ARGB32_MESA;
format_stride = stride / 4;
break;
#ifdef EGL_DRM_BUFFER_FORMAT_A8_MESA
case QtWayland::qt_drm_egl_server_buffer::format_A8:
m_format = QWaylandServerBuffer::A8;
egl_format = EGL_DRM_BUFFER_FORMAT_A8_MESA;
format_stride = stride;
break;
#endif
default:
qWarning("DrmServerBuffer: unknown format");
m_format = QWaylandServerBuffer::RGBA32;
egl_format = EGL_DRM_BUFFER_FORMAT_ARGB32_MESA;
format_stride = stride / 4;
break;
}
EGLint attribs[] = {
EGL_WIDTH, width,
EGL_HEIGHT, height,
EGL_DRM_BUFFER_STRIDE_MESA, format_stride,
EGL_DRM_BUFFER_FORMAT_MESA, egl_format,
EGL_NONE
};
qintptr name_pointer = name;
m_image = integration->eglCreateImageKHR(EGL_NO_CONTEXT, EGL_DRM_BUFFER_MESA, (EGLClientBuffer) name_pointer, attribs);
}
DrmServerBuffer::~DrmServerBuffer()
{
m_integration->eglDestroyImageKHR(m_image);
}
QOpenGLTexture *DrmServerBuffer::toOpenGlTexture()
{
if (!QOpenGLContext::currentContext())
qWarning("DrmServerBuffer: creating texture with no current context");
if (!m_texture) {
m_texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
m_texture->create();
}
m_texture->bind();
m_integration->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_image);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
m_texture->release();
m_texture->setSize(m_size.width(), m_size.height());
return m_texture;
}
void DrmEglServerBufferIntegration::initializeEgl()
{
if (m_egl_initialized)
return;
m_egl_initialized = true;
#if QT_CONFIG(egl_extension_platform_wayland)
m_egl_display = eglGetPlatformDisplay(EGL_PLATFORM_WAYLAND_EXT, m_display->wl_display(), nullptr);
#else
m_egl_display = eglGetDisplay((EGLNativeDisplayType) m_display->wl_display());
#endif
if (m_egl_display == EGL_NO_DISPLAY) {
qWarning("Failed to initialize drm egl server buffer integration. Could not get egl display from wl_display.");
return;
}
const char *extensionString = eglQueryString(m_egl_display, EGL_EXTENSIONS);
if (!extensionString || !strstr(extensionString, "EGL_KHR_image")) {
qWarning("Failed to initialize drm egl server buffer integration. There is no EGL_KHR_image extension.\n");
return;
}
m_egl_create_image = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress("eglCreateImageKHR"));
m_egl_destroy_image = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(eglGetProcAddress("eglDestroyImageKHR"));
if (!m_egl_create_image || !m_egl_destroy_image) {
qWarning("Failed to initialize drm egl server buffer integration. Could not resolve eglCreateImageKHR or eglDestroyImageKHR");
return;
}
m_gl_egl_image_target_texture = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES"));
if (!m_gl_egl_image_target_texture) {
qWarning("Failed to initialize drm egl server buffer integration. Could not resolve glEGLImageTargetTexture2DOES");
return;
}
m_egl_initialized = true;
}
void DrmEglServerBufferIntegration::initialize(QWaylandDisplay *display)
{
m_display = display;
display->addRegistryListener(&wlDisplayHandleGlobal, this);
}
QWaylandServerBuffer *DrmEglServerBufferIntegration::serverBuffer(struct qt_server_buffer *buffer)
{
return static_cast<QWaylandServerBuffer *>(qt_server_buffer_get_user_data(buffer));
}
void DrmEglServerBufferIntegration::wlDisplayHandleGlobal(void *data, ::wl_registry *registry, uint32_t id, const QString &interface, uint32_t version)
{
Q_UNUSED(version);
if (interface == QStringLiteral("qt_drm_egl_server_buffer")) {
auto *integration = static_cast<DrmEglServerBufferIntegration *>(data);
integration->QtWayland::qt_drm_egl_server_buffer::init(registry, id, 1);
}
}
void DrmEglServerBufferIntegration::drm_egl_server_buffer_server_buffer_created(struct ::qt_server_buffer *id
, int32_t name
, int32_t width
, int32_t height
, int32_t stride
, int32_t format)
{
DrmServerBuffer *server_buffer = new DrmServerBuffer(this, name, width, height, stride, format);
qt_server_buffer_set_user_data(id, server_buffer);
}
}
QT_END_NAMESPACE

View File

@ -0,0 +1,106 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef DRMEGLSERVERBUFFERINTEGRATION_H
#define DRMEGLSERVERBUFFERINTEGRATION_H
#include <QtWaylandClient/private/qwayland-wayland.h>
#include <QtCore/QVariant>
#include "qwayland-drm-egl-server-buffer.h"
#include <QtWaylandClient/private/qwaylandserverbufferintegration_p.h>
#include "drmeglserverbufferintegration.h"
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QtCore/QTextStream>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#ifndef EGL_KHR_image
typedef void *EGLImageKHR;
typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image);
#endif
#ifndef GL_OES_EGL_image
typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
#endif
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
class DrmEglServerBufferIntegration;
class DrmServerBuffer : public QWaylandServerBuffer
{
public:
DrmServerBuffer(DrmEglServerBufferIntegration *integration, int32_t name, int32_t width, int32_t height, int32_t stride, int32_t format);
~DrmServerBuffer() override;
QOpenGLTexture* toOpenGlTexture() override;
private:
DrmEglServerBufferIntegration *m_integration = nullptr;
EGLImageKHR m_image;
QOpenGLTexture *m_texture = nullptr;
};
class DrmEglServerBufferIntegration
: public QWaylandServerBufferIntegration
, public QtWayland::qt_drm_egl_server_buffer
{
public:
void initialize(QWaylandDisplay *display) override;
QWaylandServerBuffer *serverBuffer(struct qt_server_buffer *buffer) override;
inline EGLImageKHR eglCreateImageKHR(EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
inline EGLBoolean eglDestroyImageKHR (EGLImageKHR image);
inline void glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image);
protected:
void drm_egl_server_buffer_server_buffer_created(struct ::qt_server_buffer *id, int32_t name, int32_t width, int32_t height, int32_t stride, int32_t format) override;
private:
static void wlDisplayHandleGlobal(void *data, struct ::wl_registry *registry, uint32_t id,
const QString &interface, uint32_t version);
void initializeEgl();
PFNEGLCREATEIMAGEKHRPROC m_egl_create_image;
PFNEGLDESTROYIMAGEKHRPROC m_egl_destroy_image;
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC m_gl_egl_image_target_texture;
QWaylandDisplay *m_display = nullptr;
EGLDisplay m_egl_display = EGL_NO_DISPLAY;
bool m_egl_initialized = false;
};
EGLImageKHR DrmEglServerBufferIntegration::eglCreateImageKHR(EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list)
{
if (!m_egl_initialized)
initializeEgl();
if (!m_egl_create_image) {
qWarning("DrmEglServerBufferIntegration: Trying to used unresolved function eglCreateImageKHR");
return EGL_NO_IMAGE_KHR;
}
return m_egl_create_image(m_egl_display, ctx, target, buffer,attrib_list);
}
EGLBoolean DrmEglServerBufferIntegration::eglDestroyImageKHR (EGLImageKHR image)
{
if (!m_egl_destroy_image) {
qWarning("DrmEglServerBufferIntegration: Trying to use unresolved function eglDestroyImageKHR");
return false;
}
return m_egl_destroy_image(m_egl_display, image);
}
void DrmEglServerBufferIntegration::glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image)
{
if (!m_gl_egl_image_target_texture) {
qWarning("DrmEglServerBufferIntegration: Trying to use unresolved function glEGLImageTargetRenderbufferStorageOES");
return;
}
m_gl_egl_image_target_texture(target,image);
}
}
QT_END_NAMESPACE
#endif

View File

@ -11,10 +11,8 @@ qt_internal_add_plugin(LibHybrisEglServerBufferPlugin
OUTPUT_NAME libhybris-egl-server
PLUGIN_TYPE wayland-graphics-integration-client
SOURCES
../../../../hardwareintegration/client/libhybris-egl-server/libhybriseglserverbufferintegration.cpp ../../../../hardwareintegration/client/libhybris-egl-server/libhybriseglserverbufferintegration.h
libhybriseglserverbufferintegration.cpp libhybriseglserverbufferintegration.h
main.cpp
INCLUDE_DIRECTORIES
../../../../hardwareintegration/client/libhybris-egl-server
PUBLIC_LIBRARIES
EGL::EGL
Qt::Core
@ -27,7 +25,7 @@ qt_internal_add_plugin(LibHybrisEglServerBufferPlugin
qt6_generate_wayland_protocol_client_sources(LibHybrisEglServerBufferPlugin
PRIVATE_CODE
FILES
${CMAKE_CURRENT_SOURCE_DIR}/../../../../hardwareintegration/client/libhybris-egl-server/../../../extensions/libhybris-egl-server-buffer.xml
${CMAKE_CURRENT_SOURCE_DIR}/../../../extensions/libhybris-egl-server-buffer.xml
)
#### Keys ignored in scope 1:.:.:libhybris-egl-server.pro:<TRUE>:

View File

@ -0,0 +1,167 @@
// Copyright (C) 2016 Jolla Ltd, author: <giulio.camuffo@jollamobile.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "libhybriseglserverbufferintegration.h"
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QDebug>
#include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLTexture>
#include <hybris/eglplatformcommon/hybris_nativebufferext.h>
#include <EGL/egl.h>
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
LibHybrisServerBuffer::LibHybrisServerBuffer(LibHybrisEglServerBufferIntegration *integration
, int32_t numFds
, wl_array *ints
, int32_t name
, int32_t width
, int32_t height
, int32_t stride
, int32_t format)
: QWaylandServerBuffer()
, m_integration(integration)
, m_stride(stride)
, m_hybrisFormat(format)
{
m_numFds = numFds;
m_fds.reserve(numFds);
m_ints.resize(ints->size / sizeof(int32_t));
memcpy(m_ints.data(), ints->data, ints->size);
m_image = 0;
m_size = QSize(width, height);
}
LibHybrisServerBuffer::~LibHybrisServerBuffer()
{
m_integration->eglDestroyImageKHR(m_image);
}
QOpenGLTexture * LibHybrisServerBuffer::toOpenGlTexture()
{
if (!QOpenGLContext::currentContext()) {
qWarning("LibHybrisServerBuffer: creating texture with no current context");
}
if (!m_texture) {
m_texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
m_texture->create();
}
m_texture->bind();
m_integration->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_image);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
m_texture->release();
m_texture->setSize(m_size.width(), m_size.height());
return m_texture;
}
void LibHybrisServerBuffer::libhybris_buffer_add_fd(int32_t fd)
{
m_fds << fd;
if (m_fds.size() == m_numFds) {
EGLint egl_format;
switch (m_hybrisFormat) {
case QtWayland::qt_libhybris_egl_server_buffer::format_RGBA32:
m_format = QWaylandServerBuffer::RGBA32;
egl_format = HYBRIS_PIXEL_FORMAT_RGBA_8888;
break;
default:
qWarning("LibHybrisServerBuffer: unknown format");
m_format = QWaylandServerBuffer::RGBA32;
egl_format = HYBRIS_PIXEL_FORMAT_RGBA_8888;
break;
}
EGLClientBuffer buf;
m_integration->eglHybrisCreateRemoteBuffer(m_size.width(), m_size.height(), HYBRIS_USAGE_HW_TEXTURE, egl_format, m_stride, m_ints.size(), m_ints.data(), m_fds.size(), m_fds.data(), &buf);
m_image = m_integration->eglCreateImageKHR(EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, buf, 0);
}
}
void LibHybrisEglServerBufferIntegration::initializeEgl()
{
if (m_egl_initialized)
return;
m_egl_initialized = true;
m_egl_display = eglGetDisplay((EGLNativeDisplayType) m_display->wl_display());
if (m_egl_display == EGL_NO_DISPLAY) {
qWarning("Failed to initialize libhybris egl server buffer integration. Could not get egl display from wl_display.");
return;
}
const char *extensionString = eglQueryString(m_egl_display, EGL_EXTENSIONS);
if (!extensionString || !strstr(extensionString, "EGL_KHR_image")) {
qWarning("Failed to initialize libhybris egl server buffer integration. There is no EGL_KHR_image extension.\n");
return;
}
m_egl_create_image = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress("eglCreateImageKHR"));
m_egl_destroy_image = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(eglGetProcAddress("eglDestroyImageKHR"));
if (!m_egl_create_image || !m_egl_destroy_image) {
qWarning("Failed to initialize libhybris egl server buffer integration. Could not resolve eglCreateImageKHR or eglDestroyImageKHR");
return;
}
m_gl_egl_image_target_texture = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES"));
if (!m_gl_egl_image_target_texture) {
qWarning("Failed to initialize libhybris egl server buffer integration. Could not resolve glEGLImageTargetTexture2DOES");
return;
}
m_egl_create_buffer = reinterpret_cast<PFNEGLHYBRISCREATEREMOTEBUFFERPROC>(eglGetProcAddress("eglHybrisCreateRemoteBuffer"));
if (!m_egl_create_buffer) {
qWarning("Failed to initialize libhybris egl server buffer integration. Could not resolve eglHybrisCreateRemoteBuffer");
return;
}
m_egl_initialized = true;
}
void LibHybrisEglServerBufferIntegration::initialize(QWaylandDisplay *display)
{
m_display = display;
display->addRegistryListener(&wlDisplayHandleGlobal, this);
}
QWaylandServerBuffer *LibHybrisEglServerBufferIntegration::serverBuffer(struct qt_server_buffer *buffer)
{
return static_cast<QWaylandServerBuffer *>(qt_server_buffer_get_user_data(buffer));
}
void LibHybrisEglServerBufferIntegration::wlDisplayHandleGlobal(void *data, ::wl_registry *registry, uint32_t id, const QString &interface, uint32_t version)
{
Q_UNUSED(version);
if (interface == QStringLiteral("qt_libhybris_egl_server_buffer")) {
auto *integration = static_cast<LibHybrisEglServerBufferIntegration *>(data);
integration->QtWayland::qt_libhybris_egl_server_buffer::init(registry, id, 1);
}
}
void LibHybrisEglServerBufferIntegration::libhybris_egl_server_buffer_server_buffer_created(struct ::qt_libhybris_buffer *id
, struct ::qt_server_buffer *qid
, int32_t numFds
, wl_array *ints
, int32_t name
, int32_t width
, int32_t height
, int32_t stride
, int32_t format)
{
LibHybrisServerBuffer *server_buffer = new LibHybrisServerBuffer(this, numFds, ints, name, width, height, stride, format);
server_buffer->QtWayland::qt_libhybris_buffer::init(id);
qt_server_buffer_set_user_data(qid, server_buffer);
}
}
QT_END_NAMESPACE

View File

@ -0,0 +1,133 @@
// Copyright (C) 2016 Jolla Ltd, author: <giulio.camuffo@jollamobile.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef LIBHYBRISEGLSERVERBUFFERINTEGRATION_H
#define LIBHYBRISEGLSERVERBUFFERINTEGRATION_H
#include <QtWaylandClient/private/qwayland-wayland.h>
#include "qwayland-libhybris-egl-server-buffer.h"
#include <QtWaylandClient/private/qwaylandserverbufferintegration_p.h>
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QtCore/QList>
#include <QtCore/QTextStream>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#ifndef EGL_KHR_image
typedef void *EGLImageKHR;
typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image);
#endif
#ifndef GL_OES_EGL_image
typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
#endif
#ifndef EGL_HYBRIS_native_buffer
typedef EGLBoolean (EGLAPIENTRYP PFNEGLHYBRISCREATEREMOTEBUFFERPROC)(EGLint width, EGLint height, EGLint usage, EGLint format, EGLint stride,
int num_ints, int *ints, int num_fds, int *fds, EGLClientBuffer *buffer);
#endif
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
class LibHybrisEglServerBufferIntegration;
class LibHybrisServerBuffer : public QWaylandServerBuffer, public QtWayland::qt_libhybris_buffer
{
public:
LibHybrisServerBuffer(LibHybrisEglServerBufferIntegration *integration, int32_t numFds, wl_array *ints, int32_t name, int32_t width, int32_t height, int32_t stride, int32_t format);
~LibHybrisServerBuffer();
QOpenGLTexture* toOpenGlTexture() override;
protected:
void libhybris_buffer_add_fd(int32_t fd) override;
private:
LibHybrisEglServerBufferIntegration *m_integration = nullptr;
EGLImageKHR m_image;
QOpenGLTexture *m_texture = nullptr;
int m_numFds;
QList<int32_t> m_ints;
QList<int32_t> m_fds;
int32_t m_stride;
int32_t m_hybrisFormat;
};
class LibHybrisEglServerBufferIntegration
: public QWaylandServerBufferIntegration
, public QtWayland::qt_libhybris_egl_server_buffer
{
public:
void initialize(QWaylandDisplay *display) override;
virtual QWaylandServerBuffer *serverBuffer(struct qt_server_buffer *buffer) override;
inline EGLImageKHR eglCreateImageKHR(EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
inline EGLBoolean eglDestroyImageKHR (EGLImageKHR image);
inline void glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image);
inline EGLBoolean eglHybrisCreateRemoteBuffer(EGLint width, EGLint height, EGLint usage, EGLint format, EGLint stride, int num_ints, int *ints, int num_fds, int *fds, EGLClientBuffer *buffer);
protected:
void libhybris_egl_server_buffer_server_buffer_created(struct ::qt_libhybris_buffer *id, struct ::qt_server_buffer *qid,
int32_t numFds, wl_array *ints, int32_t name, int32_t width, int32_t height, int32_t stride, int32_t format) override;
private:
static void wlDisplayHandleGlobal(void *data, struct ::wl_registry *registry, uint32_t id,
const QString &interface, uint32_t version);
void initializeEgl();
PFNEGLCREATEIMAGEKHRPROC m_egl_create_image;
PFNEGLDESTROYIMAGEKHRPROC m_egl_destroy_image;
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC m_gl_egl_image_target_texture;
PFNEGLHYBRISCREATEREMOTEBUFFERPROC m_egl_create_buffer;
QWaylandDisplay *m_display = nullptr;
EGLDisplay m_egl_display = EGL_NO_DISPLAY;
bool m_egl_initialized = false;
};
EGLImageKHR LibHybrisEglServerBufferIntegration::eglCreateImageKHR(EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list)
{
if (!m_egl_initialized)
initializeEgl();
if (!m_egl_create_image) {
qWarning("LibHybrisEglServerBufferIntegration: Trying to used unresolved function eglCreateImageKHR");
return EGL_NO_IMAGE_KHR;
}
return m_egl_create_image(m_egl_display, ctx, target, buffer,attrib_list);
}
EGLBoolean LibHybrisEglServerBufferIntegration::eglDestroyImageKHR (EGLImageKHR image)
{
if (!m_egl_destroy_image) {
qWarning("LibHybrisEglServerBufferIntegration: Trying to use unresolved function eglDestroyImageKHR");
return false;
}
return m_egl_destroy_image(m_egl_display, image);
}
void LibHybrisEglServerBufferIntegration::glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image)
{
if (!m_gl_egl_image_target_texture) {
qWarning("LibHybrisEglServerBufferIntegration: Trying to use unresolved function glEGLImageTargetRenderbufferStorageOES");
return;
}
m_gl_egl_image_target_texture(target,image);
}
EGLBoolean LibHybrisEglServerBufferIntegration::eglHybrisCreateRemoteBuffer(EGLint width, EGLint height, EGLint usage, EGLint format, EGLint stride,
int num_ints, int *ints, int num_fds, int *fds, EGLClientBuffer *buffer)
{
if (!m_egl_create_buffer) {
qWarning("LibHybrisEglServerBufferIntegration: Trying to use unresolved function eglHybrisCreateRemoteBuffer");
return false;
}
return m_egl_create_buffer(width, height, usage, format, stride, num_ints, ints, num_fds, fds, buffer);
}
}
QT_END_NAMESPACE
#endif

View File

@ -11,10 +11,8 @@ qt_internal_add_plugin(ShmServerBufferPlugin
OUTPUT_NAME shm-emulation-server
PLUGIN_TYPE wayland-graphics-integration-client
SOURCES
../../../../hardwareintegration/client/shm-emulation-server/shmserverbufferintegration.cpp ../../../../hardwareintegration/client/shm-emulation-server/shmserverbufferintegration.h
shmserverbufferintegration.cpp shmserverbufferintegration.h
main.cpp
INCLUDE_DIRECTORIES
../../../../hardwareintegration/client/shm-emulation-server
LIBRARIES
Qt::Core
Qt::Gui

View File

@ -0,0 +1,107 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "shmserverbufferintegration.h"
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QDebug>
#include <QtOpenGL/QOpenGLTexture>
#include <QtGui/QOpenGLContext>
#include <QtGui/QImage>
#include <QtCore/QSharedMemory>
QT_BEGIN_NAMESPACE
static QOpenGLTexture *createTextureFromShm(const QString &key, int w, int h, int bpl, int format)
{
QT_IGNORE_DEPRECATIONS(QSharedMemory shm(key);)
bool ok;
ok = shm.attach(QSharedMemory::ReadOnly);
if (!ok) {
qWarning() << "Could not attach to" << key;
return nullptr;
}
ok = shm.lock();
if (!ok) {
qWarning() << "Could not lock" << key << "for reading";
return nullptr;
}
QImage::Format imageFormat;
switch (format) {
case QtWayland::qt_shm_emulation_server_buffer::format_RGBA32:
imageFormat = QImage::Format_RGBA8888;
break;
case QtWayland::qt_shm_emulation_server_buffer::format_A8:
imageFormat = QImage::Format_Alpha8;
break;
default:
qWarning() << "ShmServerBuffer: unknown format" << format;
imageFormat = QImage::Format_RGBA8888;
break;
}
QImage image(static_cast<const uchar*>(shm.constData()), w, h, bpl, imageFormat);
if (!QOpenGLContext::currentContext())
qWarning("ShmServerBuffer: creating texture with no current context");
auto *tex = new QOpenGLTexture(image, QOpenGLTexture::DontGenerateMipMaps);
shm.unlock();
return tex;
}
namespace QtWaylandClient {
ShmServerBuffer::ShmServerBuffer(const QString &key, const QSize& size, int bytesPerLine, QWaylandServerBuffer::Format format)
: m_key(key)
, m_bpl(bytesPerLine)
{
m_format = format;
m_size = size;
}
ShmServerBuffer::~ShmServerBuffer()
{
}
QOpenGLTexture *ShmServerBuffer::toOpenGlTexture()
{
if (!m_texture)
m_texture = createTextureFromShm(m_key, m_size.width(), m_size.height(), m_bpl, m_format);
return m_texture;
}
void ShmServerBufferIntegration::initialize(QWaylandDisplay *display)
{
m_display = display;
display->addRegistryListener(&wlDisplayHandleGlobal, this);
}
QWaylandServerBuffer *ShmServerBufferIntegration::serverBuffer(struct qt_server_buffer *buffer)
{
return static_cast<QWaylandServerBuffer *>(qt_server_buffer_get_user_data(buffer));
}
void ShmServerBufferIntegration::wlDisplayHandleGlobal(void *data, ::wl_registry *registry, uint32_t id, const QString &interface, uint32_t version)
{
Q_UNUSED(version);
if (interface == "qt_shm_emulation_server_buffer") {
auto *integration = static_cast<ShmServerBufferIntegration *>(data);
integration->QtWayland::qt_shm_emulation_server_buffer::init(registry, id, 1);
}
}
void QtWaylandClient::ShmServerBufferIntegration::shm_emulation_server_buffer_server_buffer_created(qt_server_buffer *id, const QString &key, int32_t width, int32_t height, int32_t bytes_per_line, int32_t format)
{
QSize size(width, height);
auto fmt = QWaylandServerBuffer::Format(format);
auto *server_buffer = new ShmServerBuffer(key, size, bytes_per_line, fmt);
qt_server_buffer_set_user_data(id, server_buffer);
}
}
QT_END_NAMESPACE

View File

@ -0,0 +1,55 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef SHMSERVERBUFFERINTEGRATION_H
#define SHMSERVERBUFFERINTEGRATION_H
#include <QtWaylandClient/private/qwayland-wayland.h>
#include "qwayland-shm-emulation-server-buffer.h"
#include <QtWaylandClient/private/qwaylandserverbufferintegration_p.h>
#include "shmserverbufferintegration.h"
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QtCore/QTextStream>
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
class ShmServerBufferIntegration;
class ShmServerBuffer : public QWaylandServerBuffer
{
public:
ShmServerBuffer(const QString &key, const QSize &size, int bytesPerLine, QWaylandServerBuffer::Format format);
~ShmServerBuffer() override;
QOpenGLTexture* toOpenGlTexture() override;
private:
QOpenGLTexture *m_texture = nullptr;
QString m_key;
int m_bpl;
};
class ShmServerBufferIntegration
: public QWaylandServerBufferIntegration
, public QtWayland::qt_shm_emulation_server_buffer
{
public:
void initialize(QWaylandDisplay *display) override;
QWaylandServerBuffer *serverBuffer(struct qt_server_buffer *buffer) override;
protected:
void shm_emulation_server_buffer_server_buffer_created(qt_server_buffer *id, const QString &key, int32_t width, int32_t height, int32_t bytes_per_line, int32_t format) override;
private:
static void wlDisplayHandleGlobal(void *data, struct ::wl_registry *registry, uint32_t id,
const QString &interface, uint32_t version);
QWaylandDisplay *m_display = nullptr;
};
}
QT_END_NAMESPACE
#endif

View File

@ -11,10 +11,8 @@ qt_internal_add_plugin(VulkanServerBufferPlugin
OUTPUT_NAME vulkan-server
PLUGIN_TYPE wayland-graphics-integration-client
SOURCES
../../../../hardwareintegration/client/vulkan-server/vulkanserverbufferintegration.cpp ../../../../hardwareintegration/client/vulkan-server/vulkanserverbufferintegration.h
vulkanserverbufferintegration.cpp vulkanserverbufferintegration.h
main.cpp
INCLUDE_DIRECTORIES
../../../../hardwareintegration/client/vulkan-server
LIBRARIES
Qt::Core
Qt::Gui

View File

@ -0,0 +1,177 @@
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "vulkanserverbufferintegration.h"
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QDebug>
#include <QtOpenGL/QOpenGLTexture>
#include <QtGui/QOpenGLContext>
#include <QtGui/qopengl.h>
#include <QtGui/QImage>
#include <QtCore/QCoreApplication>
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
static constexpr bool sbiExtraDebug =
#ifdef VULKAN_SERVER_BUFFER_EXTRA_DEBUG
true;
#else
false;
#endif
#define DECL_GL_FUNCTION(name, type) \
type name
#define FIND_GL_FUNCTION(name, type) \
do { \
name = reinterpret_cast<type>(glContext->getProcAddress(#name)); \
if (!name) { \
qWarning() << "ERROR in GL proc lookup. Could not find " #name; \
return false; \
} \
} while (0)
struct VulkanServerBufferGlFunctions
{
DECL_GL_FUNCTION(glCreateMemoryObjectsEXT, PFNGLCREATEMEMORYOBJECTSEXTPROC);
DECL_GL_FUNCTION(glImportMemoryFdEXT, PFNGLIMPORTMEMORYFDEXTPROC);
DECL_GL_FUNCTION(glTextureStorageMem2DEXT, PFNGLTEXTURESTORAGEMEM2DEXTPROC);
DECL_GL_FUNCTION(glTexStorageMem2DEXT, PFNGLTEXSTORAGEMEM2DEXTPROC);
DECL_GL_FUNCTION(glDeleteMemoryObjectsEXT, PFNGLDELETEMEMORYOBJECTSEXTPROC);
bool init(QOpenGLContext *glContext)
{
FIND_GL_FUNCTION(glCreateMemoryObjectsEXT, PFNGLCREATEMEMORYOBJECTSEXTPROC);
FIND_GL_FUNCTION(glImportMemoryFdEXT, PFNGLIMPORTMEMORYFDEXTPROC);
FIND_GL_FUNCTION(glTextureStorageMem2DEXT, PFNGLTEXTURESTORAGEMEM2DEXTPROC);
FIND_GL_FUNCTION(glTexStorageMem2DEXT, PFNGLTEXSTORAGEMEM2DEXTPROC);
FIND_GL_FUNCTION(glDeleteMemoryObjectsEXT, PFNGLDELETEMEMORYOBJECTSEXTPROC);
return true;
}
static bool create(QOpenGLContext *glContext);
};
static VulkanServerBufferGlFunctions *funcs = nullptr;
bool VulkanServerBufferGlFunctions::create(QOpenGLContext *glContext)
{
if (funcs)
return true;
funcs = new VulkanServerBufferGlFunctions;
if (!funcs->init(glContext)) {
delete funcs;
funcs = nullptr;
return false;
}
return true;
}
VulkanServerBuffer::VulkanServerBuffer(VulkanServerBufferIntegration *integration, struct ::qt_server_buffer *id,
int32_t fd, uint32_t width, uint32_t height, uint32_t memory_size, uint32_t format)
: m_integration(integration)
, m_server_buffer(id)
, m_fd(fd)
, m_memorySize(memory_size)
, m_internalFormat(format)
{
m_size = QSize(width, height);
}
VulkanServerBuffer::~VulkanServerBuffer()
{
if (QCoreApplication::closingDown())
return; // can't trust anything at this point
if (m_texture) { //only do gl cleanup if import has been called
m_integration->deleteGLTextureWhenPossible(m_texture);
if (sbiExtraDebug) qDebug() << "glDeleteMemoryObjectsEXT" << m_memoryObject;
funcs->glDeleteMemoryObjectsEXT(1, &m_memoryObject);
}
qt_server_buffer_release(m_server_buffer);
qt_server_buffer_destroy(m_server_buffer);
}
void VulkanServerBuffer::import()
{
if (m_texture)
return;
if (sbiExtraDebug) qDebug() << "importing" << m_fd << Qt::hex << glGetError();
auto *glContext = QOpenGLContext::currentContext();
if (!glContext)
return;
if (!funcs && !VulkanServerBufferGlFunctions::create(glContext))
return;
funcs->glCreateMemoryObjectsEXT(1, &m_memoryObject);
if (sbiExtraDebug) qDebug() << "glCreateMemoryObjectsEXT" << Qt::hex << glGetError();
funcs->glImportMemoryFdEXT(m_memoryObject, m_memorySize, GL_HANDLE_TYPE_OPAQUE_FD_EXT, m_fd);
if (sbiExtraDebug) qDebug() << "glImportMemoryFdEXT" << Qt::hex << glGetError();
m_texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
m_texture->create();
if (sbiExtraDebug) qDebug() << "created texture" << m_texture->textureId() << Qt::hex << glGetError();
m_texture->bind();
if (sbiExtraDebug) qDebug() << "bound texture" << Qt::hex << glGetError();
funcs->glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, m_internalFormat, m_size.width(), m_size.height(), m_memoryObject, 0 );
if (sbiExtraDebug) qDebug() << "glTexStorageMem2DEXT" << Qt::hex << glGetError();
if (sbiExtraDebug) qDebug() << "format" << Qt::hex << m_internalFormat << GL_RGBA8;
}
QOpenGLTexture *VulkanServerBuffer::toOpenGlTexture()
{
m_integration->deleteOrphanedTextures();
if (!m_texture)
import();
return m_texture;
}
void VulkanServerBufferIntegration::initialize(QWaylandDisplay *display)
{
m_display = display;
display->addRegistryListener(&wlDisplayHandleGlobal, this);
}
QWaylandServerBuffer *VulkanServerBufferIntegration::serverBuffer(struct qt_server_buffer *buffer)
{
return static_cast<QWaylandServerBuffer *>(qt_server_buffer_get_user_data(buffer));
}
void VulkanServerBufferIntegration::wlDisplayHandleGlobal(void *data, ::wl_registry *registry, uint32_t id, const QString &interface, uint32_t version)
{
Q_UNUSED(version);
if (interface == "zqt_vulkan_server_buffer_v1") {
auto *integration = static_cast<VulkanServerBufferIntegration *>(data);
integration->QtWayland::zqt_vulkan_server_buffer_v1::init(registry, id, 1);
}
}
void VulkanServerBufferIntegration::zqt_vulkan_server_buffer_v1_server_buffer_created(qt_server_buffer *id, int32_t fd, uint32_t width, uint32_t height, uint32_t memory_size, uint32_t format)
{
if (sbiExtraDebug) qDebug() << "vulkan_server_buffer_server_buffer_created" << fd;
auto *server_buffer = new VulkanServerBuffer(this, id, fd, width, height, memory_size, format);
qt_server_buffer_set_user_data(id, server_buffer);
}
void VulkanServerBufferIntegration::deleteOrphanedTextures()
{
if (!QOpenGLContext::currentContext()) {
qWarning("VulkanServerBufferIntegration::deleteOrphanedTextures with no current context!");
return;
}
qDeleteAll(orphanedTextures);
orphanedTextures.clear();
}
}
QT_END_NAMESPACE

View File

@ -0,0 +1,66 @@
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef VULKANSERVERBUFFERINTEGRATION_H
#define VULKANSERVERBUFFERINTEGRATION_H
#include <QtWaylandClient/private/qwayland-wayland.h>
#include "qwayland-qt-vulkan-server-buffer-unstable-v1.h"
#include <QtWaylandClient/private/qwaylandserverbufferintegration_p.h>
#include "vulkanserverbufferintegration.h"
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QtCore/QTextStream>
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
class VulkanServerBufferIntegration;
class VulkanServerBuffer : public QWaylandServerBuffer
{
public:
VulkanServerBuffer(VulkanServerBufferIntegration *integration, struct ::qt_server_buffer *id, int32_t fd, uint32_t width, uint32_t height, uint32_t memory_size, uint32_t format);
~VulkanServerBuffer() override;
QOpenGLTexture* toOpenGlTexture() override;
private:
void import();
VulkanServerBufferIntegration *m_integration = nullptr;
struct ::qt_server_buffer *m_server_buffer = nullptr;
QOpenGLTexture *m_texture = nullptr;
int m_fd = -1;
uint m_memorySize = 0;
uint m_internalFormat = 0;
GLuint m_memoryObject = 0;
};
class VulkanServerBufferIntegration
: public QWaylandServerBufferIntegration
, public QtWayland::zqt_vulkan_server_buffer_v1
{
public:
void initialize(QWaylandDisplay *display) override;
QWaylandServerBuffer *serverBuffer(struct qt_server_buffer *buffer) override;
void deleteGLTextureWhenPossible(QOpenGLTexture *texture) { orphanedTextures << texture; }
void deleteOrphanedTextures();
protected:
void zqt_vulkan_server_buffer_v1_server_buffer_created(qt_server_buffer *id, int32_t fd, uint32_t width, uint32_t height, uint32_t memory_size, uint32_t format) override;
private:
static void wlDisplayHandleGlobal(void *data, struct ::wl_registry *registry, uint32_t id,
const QString &interface, uint32_t version);
QWaylandDisplay *m_display = nullptr;
QList<QOpenGLTexture *> orphanedTextures;
};
}
QT_END_NAMESPACE
#endif

View File

@ -13,11 +13,19 @@ qt_internal_add_plugin(QWaylandEglClientBufferPlugin
PLUGIN_TYPE wayland-graphics-integration-client
SOURCES
main.cpp
qwaylandeglclientbufferintegration.cpp qwaylandeglclientbufferintegration_p.h
qwaylandeglinclude_p.h
qwaylandeglwindow.cpp qwaylandeglwindow_p.h
qwaylandglcontext.cpp qwaylandglcontext_p.h
LIBRARIES
${CMAKE_DL_LIBS}
EGL::EGL
Qt::Core
Qt::Gui
Qt::OpenGLPrivate
Qt::WaylandClientPrivate
Qt::WaylandEglClientHwIntegrationPrivate
Wayland::Client
Wayland::Egl
QT_LICENSE_ID QT_COMMERCIAL_OR_LGPL3
)

View File

@ -2,7 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtWaylandClient/private/qwaylandclientbufferintegrationplugin_p.h>
#include <QtWaylandEglClientHwIntegration/private/qwaylandeglclientbufferintegration_p.h>
#include "qwaylandeglclientbufferintegration_p.h"
QT_BEGIN_NAMESPACE

View File

@ -0,0 +1,166 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwaylandeglclientbufferintegration_p.h"
#include "qwaylandeglwindow_p.h"
#include "qwaylandglcontext_p.h"
#include <wayland-client-core.h>
#include <QtCore/QDebug>
#include <private/qeglconvenience_p.h>
#ifndef EGL_EXT_platform_base
typedef EGLDisplay (*PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list);
#endif
#ifndef EGL_PLATFORM_WAYLAND_KHR
#define EGL_PLATFORM_WAYLAND_KHR 0x31D8
#endif
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
static const char *qwaylandegl_threadedgl_blacklist_vendor[] = {
0
};
QWaylandEglClientBufferIntegration::QWaylandEglClientBufferIntegration()
{
qCDebug(lcQpaWayland) << "Using Wayland-EGL";
}
QWaylandEglClientBufferIntegration::~QWaylandEglClientBufferIntegration()
{
eglTerminate(m_eglDisplay);
}
void QWaylandEglClientBufferIntegration::initialize(QWaylandDisplay *display)
{
#if QT_CONFIG(egl_extension_platform_wayland)
m_eglDisplay = eglGetPlatformDisplay(EGL_PLATFORM_WAYLAND_EXT, display->wl_display(), nullptr);
#else
if (q_hasEglExtension(EGL_NO_DISPLAY, "EGL_EXT_platform_base")) {
if (q_hasEglExtension(EGL_NO_DISPLAY, "EGL_KHR_platform_wayland") ||
q_hasEglExtension(EGL_NO_DISPLAY, "EGL_EXT_platform_wayland") ||
q_hasEglExtension(EGL_NO_DISPLAY, "EGL_MESA_platform_wayland")) {
static PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplay = nullptr;
if (!eglGetPlatformDisplay)
eglGetPlatformDisplay = (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
m_eglDisplay = eglGetPlatformDisplay(EGL_PLATFORM_WAYLAND_KHR, display->wl_display(), nullptr);
} else {
qCWarning(lcQpaWayland) << "The EGL implementation does not support the Wayland platform";
return;
}
} else {
QByteArray eglPlatform = qgetenv("EGL_PLATFORM");
if (eglPlatform.isEmpty()) {
setenv("EGL_PLATFORM","wayland",true);
}
m_eglDisplay = eglGetDisplay((EGLNativeDisplayType) display->wl_display());
}
#endif
m_display = display;
if (m_eglDisplay == EGL_NO_DISPLAY) {
qCWarning(lcQpaWayland) << "EGL not available";
return;
}
EGLint major,minor;
if (!eglInitialize(m_eglDisplay, &major, &minor)) {
qCWarning(lcQpaWayland) << "Failed to initialize EGL display" << Qt::hex << eglGetError();
m_eglDisplay = EGL_NO_DISPLAY;
return;
}
m_supportsThreading = true;
if (qEnvironmentVariableIsSet("QT_OPENGL_NO_SANITY_CHECK"))
return;
const char *vendor = eglQueryString(m_eglDisplay, EGL_VENDOR);
for (int i = 0; qwaylandegl_threadedgl_blacklist_vendor[i]; ++i) {
if (strstr(vendor, qwaylandegl_threadedgl_blacklist_vendor[i]) != 0) {
m_supportsThreading = false;
break;
}
}
// On desktop NVIDIA resizing QtQuick freezes them when using threaded rendering QTBUG-95817
// In order to support threaded rendering on embedded platforms where resizing is not needed
// we check if XDG_CURRENT_DESKTOP is set which desktop environments should set
if (qstrcmp(vendor, "NVIDIA") == 0 && qEnvironmentVariableIsSet("XDG_CURRENT_DESKTOP")) {
m_supportsThreading = false;
}
}
bool QWaylandEglClientBufferIntegration::isValid() const
{
return m_eglDisplay != EGL_NO_DISPLAY;
}
bool QWaylandEglClientBufferIntegration::supportsThreadedOpenGL() const
{
return m_supportsThreading;
}
bool QWaylandEglClientBufferIntegration::supportsWindowDecoration() const
{
return true;
}
QWaylandWindow *QWaylandEglClientBufferIntegration::createEglWindow(QWindow *window)
{
return new QWaylandEglWindow(window, m_display);
}
QPlatformOpenGLContext *QWaylandEglClientBufferIntegration::createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const
{
QSurfaceFormat fmt = glFormat;
if (m_display->supportsWindowDecoration())
fmt.setAlphaBufferSize(8);
return new QWaylandGLContext(m_eglDisplay, m_display, fmt, share);
}
void *QWaylandEglClientBufferIntegration::nativeResource(NativeResource resource)
{
switch (resource) {
case EglDisplay:
return m_eglDisplay;
default:
break;
}
return nullptr;
}
void *QWaylandEglClientBufferIntegration::nativeResourceForContext(NativeResource resource, QPlatformOpenGLContext *context)
{
Q_ASSERT(context);
switch (resource) {
case EglConfig:
return static_cast<QWaylandGLContext *>(context)->eglConfig();
case EglContext:
return static_cast<QWaylandGLContext *>(context)->eglContext();
case EglDisplay:
return m_eglDisplay;
default:
break;
}
return nullptr;
}
EGLDisplay QWaylandEglClientBufferIntegration::eglDisplay() const
{
return m_eglDisplay;
}
}
QT_END_NAMESPACE

View File

@ -0,0 +1,60 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#ifndef QWAYLANDEGLINTEGRATION_H
#define QWAYLANDEGLINTEGRATION_H
#include <QtWaylandClient/private/qwaylandclientbufferintegration_p.h>
#include "qwaylandeglinclude_p.h"
QT_BEGIN_NAMESPACE
class QWindow;
namespace QtWaylandClient {
class QWaylandWindow;
class Q_WAYLANDCLIENT_EXPORT QWaylandEglClientBufferIntegration : public QWaylandClientBufferIntegration
{
public:
QWaylandEglClientBufferIntegration();
~QWaylandEglClientBufferIntegration() override;
void initialize(QWaylandDisplay *display) override;
bool isValid() const override;
bool supportsThreadedOpenGL() const override;
bool supportsWindowDecoration() const override;
QWaylandWindow *createEglWindow(QWindow *window) override;
QPlatformOpenGLContext *createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const override;
void *nativeResource(NativeResource resource) override;
void *nativeResourceForContext(NativeResource resource, QPlatformOpenGLContext *context) override;
EGLDisplay eglDisplay() const;
private:
QWaylandDisplay *m_display = nullptr;
EGLDisplay m_eglDisplay = EGL_NO_DISPLAY;
bool m_supportsThreading = false;
};
QT_END_NAMESPACE
}
#endif // QWAYLANDEGLINTEGRATION_H

View File

@ -0,0 +1,27 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#ifndef QWAYLANDEGLINCLUDE_H
#define QWAYLANDEGLINCLUDE_H
#include <string.h>
#include <wayland-client-core.h>
#include <wayland-egl.h>
#define EGL_EGLEXT_PROTOTYPES
#include <QtGui/private/qt_egl_p.h>
#endif // QWAYLANDEGLINCLUDE_H

View File

@ -0,0 +1,201 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwaylandeglwindow_p.h"
#include <QtWaylandClient/private/qwaylandscreen_p.h>
#include <QtWaylandClient/private/qwaylandsurface_p.h>
#include "qwaylandglcontext_p.h"
#include <QtGui/private/qeglconvenience_p.h>
#include <QDebug>
#include <QtGui/QWindow>
#include <qpa/qwindowsysteminterface.h>
#include <QOpenGLFramebufferObject>
#include <QOpenGLContext>
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
QWaylandEglWindow::QWaylandEglWindow(QWindow *window, QWaylandDisplay *display)
: QWaylandWindow(window, display)
, m_clientBufferIntegration(static_cast<QWaylandEglClientBufferIntegration *>(mDisplay->clientBufferIntegration()))
{
connect(display, &QWaylandDisplay::connected, this, [this] {
m_clientBufferIntegration = static_cast<QWaylandEglClientBufferIntegration *>(
mDisplay->clientBufferIntegration());
});
ensureSize();
}
QWaylandEglWindow::~QWaylandEglWindow()
{
if (m_eglSurface) {
eglDestroySurface(m_clientBufferIntegration->eglDisplay(), m_eglSurface);
m_eglSurface = 0;
}
if (m_waylandEglWindow)
wl_egl_window_destroy(m_waylandEglWindow);
delete m_contentFBO;
}
QWaylandWindow::WindowType QWaylandEglWindow::windowType() const
{
return QWaylandWindow::Egl;
}
void QWaylandEglWindow::ensureSize()
{
// this is always called on the main thread
QRect rect = geometry();
QMargins margins = clientSideMargins();
QSize sizeWithMargins = (rect.size() + QSize(margins.left() + margins.right(), margins.top() + margins.bottom())) * scale();
{
QWriteLocker lock(&m_bufferSizeLock);
m_bufferSize = sizeWithMargins;
}
QMutexLocker lock (&m_eglSurfaceLock);
updateSurface(false);
}
void QWaylandEglWindow::updateSurface(bool create)
{
// eglSurfaceLock should be locked before calling this method
QSize sizeWithMargins;
{
QReadLocker lock(&m_bufferSizeLock);
sizeWithMargins = m_bufferSize;
}
// wl_egl_windows must have both width and height > 0
// mesa's egl returns NULL if we try to create a, invalid wl_egl_window, however not all EGL
// implementations may do that, so check the size ourself. Besides, we must deal with resizing
// a valid window to 0x0, which would make it invalid. Hence, destroy it.
if (sizeWithMargins.isEmpty()) {
if (m_eglSurface) {
eglDestroySurface(m_clientBufferIntegration->eglDisplay(), m_eglSurface);
m_eglSurface = 0;
}
if (m_waylandEglWindow) {
wl_egl_window_destroy(m_waylandEglWindow);
m_waylandEglWindow = 0;
}
mOffset = QPoint();
} else {
QReadLocker locker(&mSurfaceLock);
if (m_waylandEglWindow) {
int current_width = 0;
int current_height = 0;
static bool disableResizeCheck = qgetenv("QT_WAYLAND_DISABLE_RESIZECHECK").toInt();
if (!disableResizeCheck) {
wl_egl_window_get_attached_size(m_waylandEglWindow, &current_width, &current_height);
}
if (disableResizeCheck || (current_width != sizeWithMargins.width() || current_height != sizeWithMargins.height()) || m_requestedSize != sizeWithMargins) {
wl_egl_window_resize(m_waylandEglWindow, sizeWithMargins.width(), sizeWithMargins.height(), mOffset.x(), mOffset.y());
m_requestedSize = sizeWithMargins;
mOffset = QPoint();
m_resize = true;
}
} else if (create && mSurface) {
wl_egl_window *eglWindow = wl_egl_window_create(mSurface->object(), sizeWithMargins.width(), sizeWithMargins.height());
if (Q_UNLIKELY(!eglWindow)) {
qCWarning(lcQpaWayland, "Could not create wl_egl_window with size %dx%d\n", sizeWithMargins.width(), sizeWithMargins.height());
return;
}
QSurfaceFormat fmt = window()->requestedFormat();
if (mDisplay->supportsWindowDecoration())
fmt.setAlphaBufferSize(8);
EGLConfig eglConfig = q_configFromGLFormat(m_clientBufferIntegration->eglDisplay(), fmt);
setFormat(q_glFormatFromConfig(m_clientBufferIntegration->eglDisplay(), eglConfig, fmt));
EGLSurface eglSurface = eglCreateWindowSurface(m_clientBufferIntegration->eglDisplay(), eglConfig, (EGLNativeWindowType) eglWindow, 0);
if (Q_UNLIKELY(eglSurface == EGL_NO_SURFACE)) {
qCWarning(lcQpaWayland, "Could not create EGL surface (EGL error 0x%x)\n", eglGetError());
wl_egl_window_destroy(eglWindow);
return;
}
m_waylandEglWindow = eglWindow;
m_eglSurface = eglSurface;
m_requestedSize = sizeWithMargins;
}
}
}
QRect QWaylandEglWindow::contentsRect() const
{
QRect r = geometry();
QMargins m = clientSideMargins();
return QRect(m.left(), m.bottom(), r.width(), r.height());
}
void QWaylandEglWindow::invalidateSurface()
{
QMutexLocker lock (&m_eglSurfaceLock);
if (m_eglSurface) {
eglDestroySurface(m_clientBufferIntegration->eglDisplay(), m_eglSurface);
m_eglSurface = 0;
}
if (m_waylandEglWindow) {
wl_egl_window_destroy(m_waylandEglWindow);
m_waylandEglWindow = nullptr;
}
delete m_contentFBO;
m_contentFBO = nullptr;
}
EGLSurface QWaylandEglWindow::eglSurface() const
{
return m_eglSurface;
}
QMutex* QWaylandEglWindow::eglSurfaceLock()
{
return &m_eglSurfaceLock;
}
GLuint QWaylandEglWindow::contentFBO() const
{
if (!decoration())
return 0;
if (m_resize || !m_contentFBO) {
QOpenGLFramebufferObject *old = m_contentFBO;
QSize fboSize = geometry().size() * scale();
m_contentFBO = new QOpenGLFramebufferObject(fboSize.width(), fboSize.height(), QOpenGLFramebufferObject::CombinedDepthStencil);
delete old;
m_resize = false;
}
return m_contentFBO->handle();
}
GLuint QWaylandEglWindow::contentTexture() const
{
return m_contentFBO->texture();
}
void QWaylandEglWindow::bindContentFBO()
{
if (decoration()) {
contentFBO();
m_contentFBO->bind();
}
}
}
QT_END_NAMESPACE
#include "moc_qwaylandeglwindow_p.cpp"

View File

@ -0,0 +1,76 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#ifndef QWAYLANDEGLWINDOW_H
#define QWAYLANDEGLWINDOW_H
#include <QtWaylandClient/private/qwaylandwindow_p.h>
#include "qwaylandeglinclude_p.h"
#include "qwaylandeglclientbufferintegration_p.h"
QT_BEGIN_NAMESPACE
class QOpenGLFramebufferObject;
namespace QtWaylandClient {
class QWaylandGLContext;
class Q_WAYLANDCLIENT_EXPORT QWaylandEglWindow : public QWaylandWindow
{
Q_OBJECT
public:
QWaylandEglWindow(QWindow *window, QWaylandDisplay *display);
~QWaylandEglWindow();
WindowType windowType() const override;
void ensureSize() override;
void updateSurface(bool create);
QRect contentsRect() const;
EGLSurface eglSurface() const;
GLuint contentFBO() const;
GLuint contentTexture() const;
bool needToUpdateContentFBO() const { return decoration() && (m_resize || !m_contentFBO); }
void bindContentFBO();
void invalidateSurface() override;
QMutex* eglSurfaceLock();
private:
QWaylandEglClientBufferIntegration *m_clientBufferIntegration = nullptr;
struct wl_egl_window *m_waylandEglWindow = nullptr;
// Locks any manipulation of the eglSurface size
QMutex m_eglSurfaceLock;
EGLSurface m_eglSurface = EGL_NO_SURFACE;
mutable bool m_resize = false;
mutable QOpenGLFramebufferObject *m_contentFBO = nullptr;
// Size used in the last call to wl_egl_window_resize
QSize m_requestedSize;
// Size of the buffer used by QWaylandWindow
// This is always written to from the main thread, potentially read from the rendering thread
QReadWriteLock m_bufferSizeLock;
QSize m_bufferSize;
};
}
QT_END_NAMESPACE
#endif // QWAYLANDEGLWINDOW_H

View File

@ -0,0 +1,430 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwaylandglcontext_p.h"
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QtWaylandClient/private/qwaylandwindow_p.h>
#include <QtWaylandClient/private/qwaylandsubsurface_p.h>
#include <QtWaylandClient/private/qwaylandabstractdecoration_p.h>
#include <QtWaylandClient/private/qwaylandintegration_p.h>
#include "qwaylandeglwindow_p.h"
#include <QDebug>
#include <QtGui/private/qeglconvenience_p.h>
#include <QtGui/private/qopenglcontext_p.h>
#include <QtOpenGL/private/qopengltexturecache_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformopenglcontext.h>
#include <QtGui/QSurfaceFormat>
#include <QtOpenGL/QOpenGLShaderProgram>
#include <QtGui/QOpenGLFunctions>
#include <QOpenGLBuffer>
#include <QtCore/qmutex.h>
#include <dlfcn.h>
// Constants from EGL_KHR_create_context
#ifndef EGL_CONTEXT_MINOR_VERSION_KHR
#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB
#endif
#ifndef EGL_CONTEXT_FLAGS_KHR
#define EGL_CONTEXT_FLAGS_KHR 0x30FC
#endif
#ifndef EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR
#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD
#endif
#ifndef EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR
#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001
#endif
#ifndef EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR
#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002
#endif
#ifndef EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR
#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001
#endif
#ifndef EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR
#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002
#endif
// Constants for OpenGL which are not available in the ES headers.
#ifndef GL_CONTEXT_FLAGS
#define GL_CONTEXT_FLAGS 0x821E
#endif
#ifndef GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT
#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x0001
#endif
#ifndef GL_CONTEXT_FLAG_DEBUG_BIT
#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
#endif
#ifndef GL_CONTEXT_PROFILE_MASK
#define GL_CONTEXT_PROFILE_MASK 0x9126
#endif
#ifndef GL_CONTEXT_CORE_PROFILE_BIT
#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001
#endif
#ifndef GL_CONTEXT_COMPATIBILITY_PROFILE_BIT
#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
#endif
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
class DecorationsBlitter : public QOpenGLFunctions
{
public:
DecorationsBlitter(QWaylandGLContext *context)
: m_context(context)
{
initializeOpenGLFunctions();
m_blitProgram = new QOpenGLShaderProgram();
m_blitProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, "attribute vec4 position;\n\
attribute vec4 texCoords;\n\
varying vec2 outTexCoords;\n\
void main()\n\
{\n\
gl_Position = position;\n\
outTexCoords = texCoords.xy;\n\
}");
m_blitProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, "varying highp vec2 outTexCoords;\n\
uniform sampler2D texture;\n\
void main()\n\
{\n\
gl_FragColor = texture2D(texture, outTexCoords);\n\
}");
m_blitProgram->bindAttributeLocation("position", 0);
m_blitProgram->bindAttributeLocation("texCoords", 1);
if (!m_blitProgram->link()) {
qDebug() << "Shader Program link failed.";
qDebug() << m_blitProgram->log();
}
m_blitProgram->bind();
m_blitProgram->enableAttributeArray(0);
m_blitProgram->enableAttributeArray(1);
glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glDisable(GL_CULL_FACE);
glDisable(GL_SCISSOR_TEST);
glDepthMask(GL_FALSE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
m_buffer.create();
m_buffer.bind();
static const GLfloat squareVertices[] = {
-1.f, -1.f,
1.0f, -1.f,
-1.f, 1.0f,
1.0f, 1.0f
};
static const GLfloat inverseSquareVertices[] = {
-1.f, 1.f,
1.f, 1.f,
-1.f, -1.f,
1.f, -1.f
};
static const GLfloat textureVertices[] = {
0.0f, 0.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
};
m_squareVerticesOffset = 0;
m_inverseSquareVerticesOffset = sizeof(squareVertices);
m_textureVerticesOffset = sizeof(squareVertices) + sizeof(textureVertices);
m_buffer.allocate(sizeof(squareVertices) + sizeof(inverseSquareVertices) + sizeof(textureVertices));
m_buffer.write(m_squareVerticesOffset, squareVertices, sizeof(squareVertices));
m_buffer.write(m_inverseSquareVerticesOffset, inverseSquareVertices, sizeof(inverseSquareVertices));
m_buffer.write(m_textureVerticesOffset, textureVertices, sizeof(textureVertices));
m_blitProgram->setAttributeBuffer(1, GL_FLOAT, m_textureVerticesOffset, 2);
m_textureWrap = m_context->context()->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat) ? GL_REPEAT : GL_CLAMP_TO_EDGE;
}
~DecorationsBlitter()
{
delete m_blitProgram;
}
void blit(QWaylandEglWindow *window)
{
QOpenGLTextureCache *cache = QOpenGLTextureCache::cacheForContext(m_context->context());
QSize surfaceSize = window->surfaceSize();
qreal scale = window->scale() ;
glViewport(0, 0, surfaceSize.width() * scale, surfaceSize.height() * scale);
//Draw Decoration
if (auto *decoration = window->decoration()) {
m_blitProgram->setAttributeBuffer(0, GL_FLOAT, m_inverseSquareVerticesOffset, 2);
QImage decorationImage = decoration->contentImage();
cache->bindTexture(m_context->context(), decorationImage);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_textureWrap);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_textureWrap);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
//Draw Content
m_blitProgram->setAttributeBuffer(0, GL_FLOAT, m_squareVerticesOffset, 2);
glBindTexture(GL_TEXTURE_2D, window->contentTexture());
QRect r = window->contentsRect();
glViewport(r.x() * scale, r.y() * scale, r.width() * scale, r.height() * scale);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
QOpenGLShaderProgram *m_blitProgram = nullptr;
QWaylandGLContext *m_context = nullptr;
QOpenGLBuffer m_buffer;
int m_squareVerticesOffset;
int m_inverseSquareVerticesOffset;
int m_textureVerticesOffset;
int m_textureWrap;
};
QWaylandGLContext::QWaylandGLContext(EGLDisplay eglDisplay, QWaylandDisplay *display,
const QSurfaceFormat &fmt, QPlatformOpenGLContext *share)
: QEGLPlatformContext(fmt, share, eglDisplay)
, m_display(display)
, m_decorationsContext(EGL_NO_CONTEXT)
{
m_reconnectionWatcher = QObject::connect(m_display, &QWaylandDisplay::connected,
m_display, [this] { invalidateContext(); });
switch (format().renderableType()) {
case QSurfaceFormat::OpenVG:
m_api = EGL_OPENVG_API;
break;
#ifdef EGL_VERSION_1_4
case QSurfaceFormat::OpenGL:
m_api = EGL_OPENGL_API;
break;
#endif // EGL_VERSION_1_4
default:
m_api = EGL_OPENGL_ES_API;
break;
}
if (m_display->supportsWindowDecoration()) {
// Create an EGL context for the decorations blitter. By using a dedicated context we are free to
// change its state and we also use OpenGL ES 2 API independently to what the app is using to draw.
QList<EGLint> eglDecorationsContextAttrs = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
m_decorationsContext = eglCreateContext(eglDisplay, eglConfig(), eglContext(),
eglDecorationsContextAttrs.constData());
if (m_decorationsContext == EGL_NO_CONTEXT)
qWarning("QWaylandGLContext: Failed to create the decorations EGLContext. Decorations will not be drawn.");
}
EGLint a = EGL_MIN_SWAP_INTERVAL;
EGLint b = EGL_MAX_SWAP_INTERVAL;
if (!eglGetConfigAttrib(eglDisplay, eglConfig(), a, &a)
|| !eglGetConfigAttrib(eglDisplay, eglConfig(), b, &b) || a > 0) {
m_supportNonBlockingSwap = false;
}
{
bool ok;
int supportNonBlockingSwap = qEnvironmentVariableIntValue("QT_WAYLAND_FORCE_NONBLOCKING_SWAP_SUPPORT", &ok);
if (ok)
m_supportNonBlockingSwap = supportNonBlockingSwap != 0;
}
if (!m_supportNonBlockingSwap) {
qCWarning(lcQpaWayland) << "Non-blocking swap buffers not supported."
<< "Subsurface rendering can be affected."
<< "It may also cause the event loop to freeze in some situations";
}
}
EGLSurface QWaylandGLContext::createTemporaryOffscreenSurface()
{
m_wlSurface = m_display->createSurface(nullptr);
m_eglWindow = wl_egl_window_create(m_wlSurface, 1, 1);
#if QT_CONFIG(egl_extension_platform_wayland)
EGLSurface eglSurface =
eglCreatePlatformWindowSurface(eglDisplay(), eglConfig(), m_eglWindow, nullptr);
#else
EGLSurface eglSurface = eglCreateWindowSurface(eglDisplay(), eglConfig(), m_eglWindow, nullptr);
#endif
return eglSurface;
}
void QWaylandGLContext::destroyTemporaryOffscreenSurface(EGLSurface eglSurface)
{
eglDestroySurface(eglDisplay(), eglSurface);
wl_egl_window_destroy(m_eglWindow);
m_eglWindow = nullptr;
wl_surface_destroy(m_wlSurface);
m_wlSurface = nullptr;
}
void QWaylandGLContext::runGLChecks()
{
bool ok;
const int doneCurrentWorkAround = qEnvironmentVariableIntValue("QT_WAYLAND_ENABLE_DONECURRENT_WORKAROUND", &ok);
if (ok) {
m_doneCurrentWorkAround = doneCurrentWorkAround != 0;
if (m_doneCurrentWorkAround)
qCDebug(lcQpaWayland) << "Enabling doneCurrent() workaround on request.";
else
qCDebug(lcQpaWayland) << "Disabling doneCurrent() workaround on request.";
} else {
// Note that even though there is an EGL context current here,
// QOpenGLContext and QOpenGLFunctions are not yet usable at this stage.
const char *renderer = reinterpret_cast<const char *>(glGetString(GL_RENDERER));
if (renderer && strstr(renderer, "Mali")) {
qCDebug(lcQpaWayland) << "Enabling doneCurrent() workaround for Mali GPU."
<< "Set QT_WAYLAND_ENABLE_DONECURRENT_WORKAROUND=0 to disable.";
m_doneCurrentWorkAround = true;
}
}
QEGLPlatformContext::runGLChecks();
}
QWaylandGLContext::~QWaylandGLContext()
{
QObject::disconnect(m_reconnectionWatcher);
delete m_blitter;
m_blitter = nullptr;
if (m_decorationsContext != EGL_NO_CONTEXT)
eglDestroyContext(eglDisplay(), m_decorationsContext);
}
void QWaylandGLContext::beginFrame()
{
Q_ASSERT(m_currentWindow != nullptr);
if (m_supportNonBlockingSwap)
m_currentWindow->beginFrame();
}
void QWaylandGLContext::endFrame()
{
Q_ASSERT(m_currentWindow != nullptr);
if (m_doneCurrentWorkAround) {
doneCurrent();
QOpenGLContextPrivate::setCurrentContext(nullptr);
}
if (m_supportNonBlockingSwap)
m_currentWindow->endFrame();
}
bool QWaylandGLContext::makeCurrent(QPlatformSurface *surface)
{
if (!isValid()) {
return false;
}
// in QWaylandGLContext() we called eglBindAPI with the correct value. However,
// eglBindAPI's documentation says:
// "eglBindAPI defines the current rendering API for EGL in the thread it is called from"
// Since makeCurrent() can be called from a different thread than the one we created the
// context in make sure to call eglBindAPI in the correct thread.
if (eglQueryAPI() != m_api) {
eglBindAPI(m_api);
}
m_currentWindow = static_cast<QWaylandEglWindow *>(surface);
QMutexLocker lock(m_currentWindow->eglSurfaceLock());
EGLSurface eglSurface = m_currentWindow->eglSurface();
if (!m_currentWindow->needToUpdateContentFBO() && (eglSurface != EGL_NO_SURFACE)) {
if (!eglMakeCurrent(eglDisplay(), eglSurface, eglSurface, eglContext())) {
qWarning("QWaylandGLContext::makeCurrent: eglError: %#x, this: %p \n", eglGetError(), this);
return false;
}
return true;
}
if (eglSurface == EGL_NO_SURFACE) {
m_currentWindow->updateSurface(true);
eglSurface = m_currentWindow->eglSurface();
}
if (!eglMakeCurrent(eglDisplay(), eglSurface, eglSurface, eglContext())) {
qWarning("QWaylandGLContext::makeCurrent: eglError: %#x, this: %p \n", eglGetError(), this);
return false;
}
//### setCurrentContext will be called in QOpenGLContext::makeCurrent after this function
// returns, but that's too late, as we need a current context in order to bind the content FBO.
QOpenGLContextPrivate::setCurrentContext(context());
m_currentWindow->bindContentFBO();
return true;
}
void QWaylandGLContext::doneCurrent()
{
eglMakeCurrent(eglDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
void QWaylandGLContext::swapBuffers(QPlatformSurface *surface)
{
QWaylandEglWindow *window = static_cast<QWaylandEglWindow *>(surface);
EGLSurface eglSurface = window->eglSurface();
if (window->decoration()) {
if (m_api != EGL_OPENGL_ES_API)
eglBindAPI(EGL_OPENGL_ES_API);
// save the current EGL content and surface to set it again after the blitter is done
EGLDisplay currentDisplay = eglGetCurrentDisplay();
EGLContext currentContext = eglGetCurrentContext();
EGLSurface currentSurfaceDraw = eglGetCurrentSurface(EGL_DRAW);
EGLSurface currentSurfaceRead = eglGetCurrentSurface(EGL_READ);
eglMakeCurrent(eglDisplay(), eglSurface, eglSurface, m_decorationsContext);
if (!m_blitter)
m_blitter = new DecorationsBlitter(this);
m_blitter->blit(window);
if (m_api != EGL_OPENGL_ES_API)
eglBindAPI(m_api);
eglMakeCurrent(currentDisplay, currentSurfaceDraw, currentSurfaceRead, currentContext);
}
int swapInterval = m_supportNonBlockingSwap ? 0 : format().swapInterval();
eglSwapInterval(eglDisplay(), swapInterval);
if (swapInterval == 0 && format().swapInterval() > 0) {
// Emulating a blocking swap
glFlush(); // Flush before waiting so we can swap more quickly when the frame event arrives
window->waitForFrameSync(100);
}
window->handleUpdate();
if (!eglSwapBuffers(eglDisplay(), eglSurface))
qCWarning(lcQpaWayland, "eglSwapBuffers failed with %#x, surface: %p", eglGetError(), eglSurface);
}
GLuint QWaylandGLContext::defaultFramebufferObject(QPlatformSurface *surface) const
{
return static_cast<QWaylandEglWindow *>(surface)->contentFBO();
}
QFunctionPointer QWaylandGLContext::getProcAddress(const char *procName)
{
QFunctionPointer proc = (QFunctionPointer) eglGetProcAddress(procName);
if (!proc)
proc = (QFunctionPointer) dlsym(RTLD_DEFAULT, procName);
return proc;
}
EGLSurface QWaylandGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface)
{
return static_cast<QWaylandEglWindow *>(surface)->eglSurface();
}
}
QT_END_NAMESPACE

View File

@ -0,0 +1,74 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#ifndef QWAYLANDGLCONTEXT_H
#define QWAYLANDGLCONTEXT_H
#include "qwaylandeglinclude_p.h" //must be first
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QtGui/private/qeglplatformcontext_p.h>
#include <qpa/qplatformopenglcontext.h>
QT_BEGIN_NAMESPACE
class QOpenGLShaderProgram;
class QOpenGLTextureCache;
namespace QtWaylandClient {
class QWaylandEglWindow;
class DecorationsBlitter;
class Q_WAYLANDCLIENT_EXPORT QWaylandGLContext : public QEGLPlatformContext
{
public:
QWaylandGLContext(EGLDisplay eglDisplay, QWaylandDisplay *display, const QSurfaceFormat &format, QPlatformOpenGLContext *share);
~QWaylandGLContext();
void swapBuffers(QPlatformSurface *surface) override;
bool makeCurrent(QPlatformSurface *surface) override;
void doneCurrent() override;
void beginFrame() override;
void endFrame() override;
GLuint defaultFramebufferObject(QPlatformSurface *surface) const override;
QFunctionPointer getProcAddress(const char *procName) override;
protected:
EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface) override;
EGLSurface createTemporaryOffscreenSurface() override;
void destroyTemporaryOffscreenSurface(EGLSurface surface) override;
void runGLChecks() override;
private:
QWaylandDisplay *m_display = nullptr;
EGLContext m_decorationsContext;
DecorationsBlitter *m_blitter = nullptr;
bool m_supportNonBlockingSwap = true;
EGLenum m_api;
wl_surface *m_wlSurface = nullptr;
wl_egl_window *m_eglWindow = nullptr;
QWaylandEglWindow *m_currentWindow = nullptr;
QMetaObject::Connection m_reconnectionWatcher;
bool m_doneCurrentWorkAround = false;
};
}
QT_END_NAMESPACE
#endif // QWAYLANDGLCONTEXT_H