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:
parent
ab73b6c286
commit
58e68f1981
@ -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>:
|
||||
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
||||
|
@ -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
|
@ -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
|
@ -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
|
||||
|
@ -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
|
@ -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
|
@ -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>:
|
||||
|
@ -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
|
@ -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
|
@ -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
|
||||
|
@ -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
|
@ -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
|
@ -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
|
||||
|
@ -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
|
@ -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
|
@ -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
|
||||
)
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
@ -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
|
@ -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
|
@ -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, ¤t_width, ¤t_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"
|
@ -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
|
@ -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
|
@ -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
|
Loading…
x
Reference in New Issue
Block a user