summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/platformsupport/eglconvenience/qeglplatformintegration.cpp13
-rw-r--r--src/platformsupport/eglconvenience/qeglplatformintegration_p.h4
-rw-r--r--src/plugins/platforms/eglfs/qeglfscontext.cpp4
-rw-r--r--src/plugins/platforms/eglfs/qeglfshooks.h8
-rw-r--r--src/plugins/platforms/eglfs/qeglfshooks_kms.cpp839
-rw-r--r--src/plugins/platforms/eglfs/qeglfshooks_stub.cpp23
-rw-r--r--src/plugins/platforms/eglfs/qeglfsintegration.cpp24
-rw-r--r--src/plugins/platforms/eglfs/qeglfsintegration.h4
-rw-r--r--src/plugins/platforms/eglfs/qeglfswindow.cpp5
9 files changed, 574 insertions, 350 deletions
diff --git a/src/platformsupport/eglconvenience/qeglplatformintegration.cpp b/src/platformsupport/eglconvenience/qeglplatformintegration.cpp
index fa1ec9e1be..a9f0c0f448 100644
--- a/src/platformsupport/eglconvenience/qeglplatformintegration.cpp
+++ b/src/platformsupport/eglconvenience/qeglplatformintegration.cpp
@@ -84,8 +84,7 @@ QT_BEGIN_NAMESPACE
*/
QEGLPlatformIntegration::QEGLPlatformIntegration()
- : m_screen(0),
- m_display(EGL_NO_DISPLAY),
+ : m_display(EGL_NO_DISPLAY),
m_inputContext(0),
m_fontDb(new QGenericUnixFontDatabase),
m_services(new QGenericUnixServices),
@@ -95,7 +94,6 @@ QEGLPlatformIntegration::QEGLPlatformIntegration()
QEGLPlatformIntegration::~QEGLPlatformIntegration()
{
-
}
void QEGLPlatformIntegration::initialize()
@@ -108,9 +106,6 @@ void QEGLPlatformIntegration::initialize()
if (!eglInitialize(m_display, &major, &minor))
qFatal("Could not initialize egl display");
- m_screen = createScreen();
- screenAdded(m_screen);
-
m_inputContext = QPlatformInputContextFactory::create();
m_vtHandler.reset(new QFbVtHandler);
@@ -121,8 +116,6 @@ void QEGLPlatformIntegration::destroy()
foreach (QWindow *w, qGuiApp->topLevelWindows())
w->destroy();
- delete m_screen;
-
if (m_display != EGL_NO_DISPLAY)
eglTerminate(m_display);
}
@@ -228,7 +221,7 @@ void *QEGLPlatformIntegration::nativeResourceForIntegration(const QByteArray &re
switch (resourceType(resource)) {
case EglDisplay:
- result = m_screen->display();
+ result = display();
break;
case NativeDisplay:
result = reinterpret_cast<void*>(nativeDisplay());
@@ -266,7 +259,7 @@ void *QEGLPlatformIntegration::nativeResourceForWindow(const QByteArray &resourc
if (window && window->handle())
result = static_cast<QEGLPlatformScreen *>(window->handle()->screen())->display();
else
- result = m_screen->display();
+ result = display();
break;
case EglWindow:
if (window && window->handle())
diff --git a/src/platformsupport/eglconvenience/qeglplatformintegration_p.h b/src/platformsupport/eglconvenience/qeglplatformintegration_p.h
index 2080ff0352..7f0037db92 100644
--- a/src/platformsupport/eglconvenience/qeglplatformintegration_p.h
+++ b/src/platformsupport/eglconvenience/qeglplatformintegration_p.h
@@ -52,7 +52,6 @@
QT_BEGIN_NAMESPACE
-class QEGLPlatformScreen;
class QEGLPlatformWindow;
class QEGLPlatformContext;
class QFbVtHandler;
@@ -67,7 +66,6 @@ public:
void initialize() Q_DECL_OVERRIDE;
void destroy() Q_DECL_OVERRIDE;
- QEGLPlatformScreen *screen() const { return m_screen; }
EGLDisplay display() const { return m_display; }
QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE;
@@ -93,7 +91,6 @@ public:
QFunctionPointer platformFunction(const QByteArray &function) const Q_DECL_OVERRIDE;
protected:
- virtual QEGLPlatformScreen *createScreen() const = 0;
virtual QEGLPlatformWindow *createWindow(QWindow *window) const = 0;
virtual QEGLPlatformContext *createContext(const QSurfaceFormat &format,
QPlatformOpenGLContext *shareContext,
@@ -110,7 +107,6 @@ protected:
private:
static void loadKeymapStatic(const QString &filename);
- QEGLPlatformScreen *m_screen;
EGLDisplay m_display;
QPlatformInputContext *m_inputContext;
QScopedPointer<QPlatformFontDatabase> m_fontDb;
diff --git a/src/plugins/platforms/eglfs/qeglfscontext.cpp b/src/plugins/platforms/eglfs/qeglfscontext.cpp
index 310b460087..00778373ae 100644
--- a/src/plugins/platforms/eglfs/qeglfscontext.cpp
+++ b/src/plugins/platforms/eglfs/qeglfscontext.cpp
@@ -94,9 +94,9 @@ void QEglFSContext::swapBuffers(QPlatformSurface *surface)
cursor->paintOnScreen();
}
- QEglFSHooks::hooks()->waitForVSync();
+ QEglFSHooks::hooks()->waitForVSync(surface);
QEGLPlatformContext::swapBuffers(surface);
- QEglFSHooks::hooks()->presentBuffer();
+ QEglFSHooks::hooks()->presentBuffer(surface);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/qeglfshooks.h b/src/plugins/platforms/eglfs/qeglfshooks.h
index 078a174a16..b2b8d46741 100644
--- a/src/plugins/platforms/eglfs/qeglfshooks.h
+++ b/src/plugins/platforms/eglfs/qeglfshooks.h
@@ -43,6 +43,8 @@
QT_BEGIN_NAMESPACE
class QEglFSScreen;
+class QEglFSIntegration;
+class QPlatformSurface;
class QEglFSHooks
{
@@ -51,6 +53,8 @@ public:
virtual void platformInit();
virtual void platformDestroy();
virtual EGLNativeDisplayType platformDisplay() const;
+ virtual void screenInit();
+ virtual void screenDestroy();
virtual QSizeF physicalScreenSize() const;
virtual QSize screenSize() const;
virtual QDpi logicalDpi() const;
@@ -67,8 +71,8 @@ public:
virtual bool hasCapability(QPlatformIntegration::Capability cap) const;
virtual QPlatformCursor *createCursor(QPlatformScreen *screen) const;
virtual bool filterConfig(EGLDisplay display, EGLConfig config) const;
- virtual void waitForVSync() const;
- virtual void presentBuffer();
+ virtual void waitForVSync(QPlatformSurface *surface) const;
+ virtual void presentBuffer(QPlatformSurface *surface);
virtual QByteArray fbDeviceName() const;
virtual int framebufferIndex() const;
diff --git a/src/plugins/platforms/eglfs/qeglfshooks_kms.cpp b/src/plugins/platforms/eglfs/qeglfshooks_kms.cpp
index 61a1ee7a87..a14de922f4 100644
--- a/src/plugins/platforms/eglfs/qeglfshooks_kms.cpp
+++ b/src/plugins/platforms/eglfs/qeglfshooks_kms.cpp
@@ -40,6 +40,9 @@
****************************************************************************/
#include "qeglfshooks.h"
+#include "qeglfsintegration.h"
+#include "qeglfsscreen.h"
+
#include <QtPlatformSupport/private/qdevicediscovery_p.h>
#include <QtCore/private/qcore_unix_p.h>
#include <QtCore/QScopedPointer>
@@ -49,6 +52,7 @@
#include <QtGui/qpa/qplatformwindow.h>
#include <QtGui/qpa/qplatformcursor.h>
#include <QtGui/QPainter>
+#include <QtGui/private/qguiapplication_p.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
@@ -56,12 +60,106 @@
QT_USE_NAMESPACE
-class QKmsCursor : public QPlatformCursor
+struct QEglFSKmsOutput {
+ uint32_t conn_id;
+ uint32_t crtc_id;
+ QSizeF physical_size;
+ drmModeModeInfo mode;
+ bool mode_set;
+ drmModeCrtc *saved_crtc;
+};
+
+class QEglFSKmsDevice
+{
+ Q_DISABLE_COPY(QEglFSKmsDevice)
+
+ QString m_path;
+ int m_dri_fd;
+ gbm_device *m_gbm_device;
+
+ QList<QEglFSKmsOutput> m_validOutputs;
+
+ bool setup_kms();
+ static void pageFlipHandler(int fd,
+ unsigned int sequence,
+ unsigned int tv_sec,
+ unsigned int tv_usec,
+ void *user_data);
+public:
+ QEglFSKmsDevice(const QString &path);
+
+ bool open();
+ void close();
+
+ void createScreens();
+
+ gbm_device *device() const;
+ int fd() const;
+
+ void handleDrmEvent();
+};
+
+class QEglFSKmsCursor;
+class QEglFSKmsScreen : public QEglFSScreen
+{
+ QEglFSKmsDevice *m_device;
+ gbm_surface *m_gbm_surface;
+
+ gbm_bo *m_gbm_bo_current;
+ gbm_bo *m_gbm_bo_next;
+
+ bool m_mode_set;
+
+ QEglFSKmsOutput m_output;
+ QPoint m_pos;
+ QScopedPointer<QEglFSKmsCursor> m_cursor;
+
+ struct FrameBuffer {
+ FrameBuffer() : fb(0) {}
+ uint32_t fb;
+ };
+ static void bufferDestroyedHandler(gbm_bo *bo, void *data);
+ FrameBuffer *framebufferForBufferObject(gbm_bo *bo);
+
+ static QMutex m_waitForFlipMutex;
+
+public:
+ QEglFSKmsScreen(QEglFSKmsDevice *device, QEglFSKmsOutput output, QPoint position);
+ ~QEglFSKmsScreen();
+
+ QRect geometry() const Q_DECL_OVERRIDE;
+ int depth() const Q_DECL_OVERRIDE;
+ QImage::Format format() const Q_DECL_OVERRIDE;
+
+ QSizeF physicalSize() const Q_DECL_OVERRIDE;
+ QDpi logicalDpi() const Q_DECL_OVERRIDE;
+ Qt::ScreenOrientation nativeOrientation() const Q_DECL_OVERRIDE;
+ Qt::ScreenOrientation orientation() const Q_DECL_OVERRIDE;
+
+ QPlatformCursor *cursor() const Q_DECL_OVERRIDE;
+
+ QEglFSKmsDevice *device() const { return m_device; }
+
+ gbm_surface *surface() const { return m_gbm_surface; }
+ gbm_surface *createSurface();
+ void destroySurface();
+
+ void waitForFlip();
+ void flip();
+ void flipFinished();
+
+ QEglFSKmsOutput &output() { return m_output; }
+ void restoreMode();
+};
+
+QMutex QEglFSKmsScreen::m_waitForFlipMutex;
+
+class QEglFSKmsCursor : public QPlatformCursor
{
Q_OBJECT
public:
- QKmsCursor(gbm_device *gbm_device, int dri_fd, uint32_t crtcId);
- ~QKmsCursor();
+ QEglFSKmsCursor(QEglFSKmsScreen *screen);
+ ~QEglFSKmsCursor();
// input methods
void pointerEvent(const QMouseEvent & event) Q_DECL_OVERRIDE;
@@ -74,9 +172,7 @@ public:
private:
void initCursorAtlas();
- gbm_device *m_gbm_device;
- int m_dri_fd;
- uint32_t m_crtc;
+ QEglFSKmsScreen *m_screen;
gbm_bo *m_bo;
QPoint m_pos;
QPlatformCursorImage m_cursorImage;
@@ -101,9 +197,7 @@ public:
void platformInit() Q_DECL_OVERRIDE;
void platformDestroy() Q_DECL_OVERRIDE;
EGLNativeDisplayType platformDisplay() const Q_DECL_OVERRIDE;
- QSizeF physicalScreenSize() const Q_DECL_OVERRIDE;
- QSize screenSize() const Q_DECL_OVERRIDE;
- int screenDepth() const Q_DECL_OVERRIDE;
+ void screenInit() Q_DECL_OVERRIDE;
QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &inputFormat) const Q_DECL_OVERRIDE;
EGLNativeWindowType createNativeWindow(QPlatformWindow *platformWindow,
const QSize &size,
@@ -112,62 +206,20 @@ public:
void destroyNativeWindow(EGLNativeWindowType window) Q_DECL_OVERRIDE;
bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE;
QPlatformCursor *createCursor(QPlatformScreen *screen) const Q_DECL_OVERRIDE;
- void presentBuffer() Q_DECL_OVERRIDE;
+ void waitForVSync(QPlatformSurface *surface) const Q_DECL_OVERRIDE;
+ void presentBuffer(QPlatformSurface *surface) Q_DECL_OVERRIDE;
bool supportsPBuffers() const Q_DECL_OVERRIDE;
private:
- bool setup_kms();
-
- struct FrameBuffer {
- FrameBuffer() : fb(0) {}
- uint32_t fb;
- };
- static void bufferDestroyedHandler(gbm_bo *bo, void *data);
- FrameBuffer *framebufferForBufferObject(gbm_bo *bo);
-
- static void pageFlipHandler(int fd,
- unsigned int sequence,
- unsigned int tv_sec,
- unsigned int tv_usec,
- void *user_data);
-
-private:
- // device bits
- QByteArray m_device;
- int m_dri_fd;
- gbm_device *m_gbm_device;
-
- // KMS bits
- drmModeConnector *m_drm_connector;
- drmModeEncoder *m_drm_encoder;
- drmModeModeInfo m_drm_mode;
- quint32 m_drm_crtc;
-
- // Drawing bits
- gbm_surface *m_gbm_surface;
- gbm_bo *m_gbm_bo_current;
- gbm_bo *m_gbm_bo_next;
- bool m_flipping;
- bool m_mode_set;
+ QEglFSKmsDevice *m_device;
};
static QEglKmsHooks kms_hooks;
QEglFSHooks *platformHooks = &kms_hooks;
QEglKmsHooks::QEglKmsHooks()
- : m_dri_fd(-1)
- , m_gbm_device(Q_NULLPTR)
- , m_drm_connector(Q_NULLPTR)
- , m_drm_encoder(Q_NULLPTR)
- , m_drm_crtc(0)
- , m_gbm_surface(Q_NULLPTR)
- , m_gbm_bo_current(Q_NULLPTR)
- , m_gbm_bo_next(Q_NULLPTR)
- , m_flipping(false)
- , m_mode_set(false)
-{
-
-}
+ : m_device(Q_NULLPTR)
+{}
void QEglKmsHooks::platformInit()
{
@@ -178,52 +230,27 @@ void QEglKmsHooks::platformInit()
if (devices.isEmpty())
qFatal("Could not find DRM device!");
- m_device = devices.first().toLocal8Bit();
- m_dri_fd = qt_safe_open(m_device.constData(), O_RDWR | O_CLOEXEC);
- if (m_dri_fd == -1) {
- qErrnoWarning("Could not open DRM device %s", m_device.constData());
- qFatal("DRM device required, aborting.");
- }
-
- if (!setup_kms())
- qFatal("Could not set up KMS on device %s!", m_device.constData());
-
- m_gbm_device = gbm_create_device(m_dri_fd);
- if (!m_gbm_device)
- qFatal("Could not initialize gbm on device %s!", m_device.constData());
+ m_device = new QEglFSKmsDevice(devices.first());
+ if (!m_device->open())
+ qFatal("DRM device required, aborting");
}
void QEglKmsHooks::platformDestroy()
{
- gbm_device_destroy(m_gbm_device);
- m_gbm_device = Q_NULLPTR;
-
- if (qt_safe_close(m_dri_fd) == -1)
- qErrnoWarning("Could not close DRM device %s", m_device.constData());
-
- m_dri_fd = -1;
+ m_device->close();
+ delete m_device;
+ m_device = Q_NULLPTR;
}
EGLNativeDisplayType QEglKmsHooks::platformDisplay() const
{
- return static_cast<EGLNativeDisplayType>(m_gbm_device);
-}
-
-QSizeF QEglKmsHooks::physicalScreenSize() const
-{
- return QSizeF(m_drm_connector->mmWidth,
- m_drm_connector->mmHeight);
+ Q_ASSERT(m_device);
+ return static_cast<EGLNativeDisplayType>(m_device->device());
}
-QSize QEglKmsHooks::screenSize() const
+void QEglKmsHooks::screenInit()
{
- return QSize(m_drm_mode.hdisplay,
- m_drm_mode.vdisplay);
-}
-
-int QEglKmsHooks::screenDepth() const
-{
- return 32;
+ m_device->createScreens();
}
QSurfaceFormat QEglKmsHooks::surfaceFormatFor(const QSurfaceFormat &inputFormat) const
@@ -241,31 +268,24 @@ EGLNativeWindowType QEglKmsHooks::createNativeWindow(QPlatformWindow *platformWi
const QSize &size,
const QSurfaceFormat &format)
{
- Q_UNUSED(platformWindow);
Q_UNUSED(size);
Q_UNUSED(format);
- if (m_gbm_surface) {
- qWarning("Only single window apps supported!");
+ QEglFSKmsScreen *screen = static_cast<QEglFSKmsScreen *>(platformWindow->screen());
+ if (screen->surface()) {
+ qWarning("Only single window per screen supported!");
return 0;
}
- m_gbm_surface = gbm_surface_create(m_gbm_device,
- screenSize().width(),
- screenSize().height(),
- GBM_FORMAT_XRGB8888,
- GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
- if (!m_gbm_surface)
- qFatal("Could not initialize GBM surface");
-
- return reinterpret_cast<EGLNativeWindowType>(m_gbm_surface);
+ return reinterpret_cast<EGLNativeWindowType>(screen->createSurface());
}
EGLNativeWindowType QEglKmsHooks::createNativeOffscreenWindow(const QSurfaceFormat &format)
{
Q_UNUSED(format);
+ Q_ASSERT(m_device);
- gbm_surface *surface = gbm_surface_create(m_gbm_device,
+ gbm_surface *surface = gbm_surface_create(m_device->device(),
1, 1,
GBM_FORMAT_XRGB8888,
GBM_BO_USE_RENDERING);
@@ -276,8 +296,6 @@ EGLNativeWindowType QEglKmsHooks::createNativeOffscreenWindow(const QSurfaceForm
void QEglKmsHooks::destroyNativeWindow(EGLNativeWindowType window)
{
gbm_surface *surface = reinterpret_cast<gbm_surface *>(window);
- if (surface == m_gbm_surface)
- m_gbm_surface = Q_NULLPTR;
gbm_surface_destroy(surface);
}
@@ -296,135 +314,23 @@ bool QEglKmsHooks::hasCapability(QPlatformIntegration::Capability cap) const
QPlatformCursor *QEglKmsHooks::createCursor(QPlatformScreen *screen) const
{
Q_UNUSED(screen);
- return new QKmsCursor(m_gbm_device, m_dri_fd, m_drm_crtc);
+ return Q_NULLPTR;
}
-void QEglKmsHooks::bufferDestroyedHandler(gbm_bo *bo, void *data)
+void QEglKmsHooks::waitForVSync(QPlatformSurface *surface) const
{
- QEglKmsHooks::FrameBuffer *fb = static_cast<QEglKmsHooks::FrameBuffer *>(data);
-
- if (fb->fb) {
- gbm_device *device = gbm_bo_get_device(bo);
- drmModeRmFB(gbm_device_get_fd(device), fb->fb);
- }
+ QWindow *window = static_cast<QWindow *>(surface->surface());
+ QEglFSKmsScreen *screen = static_cast<QEglFSKmsScreen *>(window->screen()->handle());
- delete fb;
+ screen->waitForFlip();
}
-QEglKmsHooks::FrameBuffer *QEglKmsHooks::framebufferForBufferObject(gbm_bo *bo)
+void QEglKmsHooks::presentBuffer(QPlatformSurface *surface)
{
- {
- FrameBuffer *fb = static_cast<FrameBuffer *>(gbm_bo_get_user_data(bo));
- if (fb)
- return fb;
- }
-
- uint32_t width = gbm_bo_get_width(bo);
- uint32_t height = gbm_bo_get_height(bo);
- uint32_t stride = gbm_bo_get_stride(bo);
- uint32_t handle = gbm_bo_get_handle(bo).u32;
-
- QScopedPointer<FrameBuffer> fb(new FrameBuffer);
-
- int ret = drmModeAddFB(m_dri_fd, width, height, 24, 32,
- stride, handle, &fb->fb);
-
- if (ret) {
- qWarning("Failed to create KMS FB!");
- return Q_NULLPTR;
- }
-
- gbm_bo_set_user_data(bo, fb.data(), bufferDestroyedHandler);
- return fb.take();
-}
-
-void QEglKmsHooks::pageFlipHandler(int fd,
- unsigned int sequence,
- unsigned int tv_sec,
- unsigned int tv_usec,
- void *user_data)
-{
- Q_UNUSED(fd);
- Q_UNUSED(sequence);
- Q_UNUSED(tv_sec);
- Q_UNUSED(tv_usec);
-
- QEglKmsHooks *hooks = static_cast<QEglKmsHooks *>(user_data);
+ QWindow *window = static_cast<QWindow *>(surface->surface());
+ QEglFSKmsScreen *screen = static_cast<QEglFSKmsScreen *>(window->screen()->handle());
- if (hooks->m_gbm_bo_current)
- gbm_surface_release_buffer(hooks->m_gbm_surface,
- hooks->m_gbm_bo_current);
-
- hooks->m_gbm_bo_current = hooks->m_gbm_bo_next;
- hooks->m_gbm_bo_next = Q_NULLPTR;
-
- // We are no longer flipping
- hooks->m_flipping = false;
-}
-
-void QEglKmsHooks::presentBuffer()
-{
- if (!m_gbm_surface) {
- qWarning("Cannot sync before platform init!");
- return;
- }
-
- m_gbm_bo_next = gbm_surface_lock_front_buffer(m_gbm_surface);
- if (!m_gbm_bo_next) {
- qWarning("Could not lock GBM surface front buffer!");
- return;
- }
-
- QEglKmsHooks::FrameBuffer *fb = framebufferForBufferObject(m_gbm_bo_next);
-
- if (!m_mode_set) {
- int ret = drmModeSetCrtc(m_dri_fd,
- m_drm_crtc,
- fb->fb,
- 0, 0,
- &m_drm_connector->connector_id, 1,
- &m_drm_mode);
- if (ret) {
- qErrnoWarning("Could not set DRM mode!");
- } else {
- m_mode_set = true;
- }
- }
-
- int ret = drmModePageFlip(m_dri_fd,
- m_drm_encoder->crtc_id,
- fb->fb,
- DRM_MODE_PAGE_FLIP_EVENT,
- this);
- if (ret) {
- qErrnoWarning("Could not queue DRM page flip!");
- return;
- }
-
- m_flipping = true;
-
- drmEventContext drmEvent = {
- DRM_EVENT_CONTEXT_VERSION,
- Q_NULLPTR, // vblank handler
- pageFlipHandler // page flip handler
- };
-
- fd_set fds;
- FD_ZERO(&fds);
- FD_SET(m_dri_fd, &fds);
-
- while (m_flipping) {
- ret = qt_safe_select(m_dri_fd + 1, &fds, Q_NULLPTR, Q_NULLPTR, Q_NULLPTR);
-
- if (ret == 0) {
- // timeout
- } else if (ret == -1) {
- qErrnoWarning("Error while selecting on DRM fd");
- break;
- } else if (drmHandleEvent(m_dri_fd, &drmEvent)) {
- qWarning("Could not handle DRM event!");
- }
- }
+ screen->flip();
}
bool QEglKmsHooks::supportsPBuffers() const
@@ -432,76 +338,9 @@ bool QEglKmsHooks::supportsPBuffers() const
return false;
}
-bool QEglKmsHooks::setup_kms()
-{
- drmModeRes *resources;
- drmModeConnector *connector;
- drmModeEncoder *encoder;
- quint32 crtc = 0;
- int i;
-
- resources = drmModeGetResources(m_dri_fd);
- if (!resources) {
- qWarning("drmModeGetResources failed");
- return false;
- }
-
- for (i = 0; i < resources->count_connectors; i++) {
- connector = drmModeGetConnector(m_dri_fd, resources->connectors[i]);
- if (connector == NULL)
- continue;
-
- if (connector->connection == DRM_MODE_CONNECTED &&
- connector->count_modes > 0) {
- break;
- }
-
- drmModeFreeConnector(connector);
- }
-
- if (i == resources->count_connectors) {
- qWarning("No currently active connector found.");
- return false;
- }
-
- for (i = 0; i < resources->count_encoders; i++) {
- encoder = drmModeGetEncoder(m_dri_fd, resources->encoders[i]);
-
- if (encoder == NULL)
- continue;
-
- if (encoder->encoder_id == connector->encoder_id)
- break;
-
- drmModeFreeEncoder(encoder);
- }
-
- for (int j = 0; j < resources->count_crtcs; j++) {
- if ((encoder->possible_crtcs & (1 << j))) {
- crtc = resources->crtcs[j];
- break;
- }
- }
-
- if (crtc == 0)
- qFatal("No suitable CRTC available");
-
- m_drm_connector = connector;
- m_drm_encoder = encoder;
- m_drm_mode = connector->modes[0];
- m_drm_crtc = crtc;
-
- drmModeFreeResources(resources);
-
- return true;
-}
-
-
-QKmsCursor::QKmsCursor(gbm_device *gbm_device, int dri_fd, uint32_t crtcId)
- : m_gbm_device(gbm_device)
- , m_dri_fd(dri_fd)
- , m_crtc(crtcId)
- , m_bo(gbm_bo_create(gbm_device, 64, 64, GBM_FORMAT_ARGB8888,
+QEglFSKmsCursor::QEglFSKmsCursor(QEglFSKmsScreen *screen)
+ : m_screen(screen)
+ , m_bo(gbm_bo_create(m_screen->device()->device(), 64, 64, GBM_FORMAT_ARGB8888,
GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE))
, m_cursorImage(0, 0, 0, 0, 0, 0)
, m_visible(true)
@@ -512,25 +351,25 @@ QKmsCursor::QKmsCursor(gbm_device *gbm_device, int dri_fd, uint32_t crtcId)
initCursorAtlas();
}
- drmModeMoveCursor(m_dri_fd, m_crtc, 0, 0);
+ drmModeMoveCursor(m_screen->device()->fd(), m_screen->output().crtc_id, 0, 0);
}
-QKmsCursor::~QKmsCursor()
+QEglFSKmsCursor::~QEglFSKmsCursor()
{
- drmModeSetCursor(m_dri_fd, m_crtc, 0, 0, 0);
- drmModeMoveCursor(m_dri_fd, m_crtc, 0, 0);
+ drmModeSetCursor(m_screen->device()->fd(), m_screen->output().crtc_id, 0, 0, 0);
+ drmModeMoveCursor(m_screen->device()->fd(), m_screen->output().crtc_id, 0, 0);
gbm_bo_destroy(m_bo);
m_bo = Q_NULLPTR;
}
-void QKmsCursor::pointerEvent(const QMouseEvent &event)
+void QEglFSKmsCursor::pointerEvent(const QMouseEvent &event)
{
setPos(event.screenPos().toPoint());
}
#ifndef QT_NO_CURSOR
-void QKmsCursor::changeCursor(QCursor *windowCursor, QWindow *window)
+void QEglFSKmsCursor::changeCursor(QCursor *windowCursor, QWindow *window)
{
Q_UNUSED(window);
@@ -574,21 +413,21 @@ void QKmsCursor::changeCursor(QCursor *windowCursor, QWindow *window)
uint32_t handle = gbm_bo_get_handle(m_bo).u32;
QPoint hot = m_cursorImage.hotspot();
- int status = drmModeSetCursor2(m_dri_fd, m_crtc, handle, 64, 64, hot.x(), hot.y());
+ int status = drmModeSetCursor2(m_screen->device()->fd(), m_screen->output().crtc_id, handle, 64, 64, hot.x(), hot.y());
if (status != 0)
qWarning("Could not set cursor: %d", status);
}
#endif // QT_NO_CURSOR
-QPoint QKmsCursor::pos() const
+QPoint QEglFSKmsCursor::pos() const
{
return m_pos;
}
-void QKmsCursor::setPos(const QPoint &pos)
+void QEglFSKmsCursor::setPos(const QPoint &pos)
{
QPoint adjustedPos = pos - m_cursorImage.hotspot();
- int ret = drmModeMoveCursor(m_dri_fd, m_crtc, adjustedPos.x(), adjustedPos.y());
+ int ret = drmModeMoveCursor(m_screen->device()->fd(), m_screen->output().crtc_id, adjustedPos.x(), adjustedPos.y());
if (ret == 0) {
m_pos = pos;
} else {
@@ -596,7 +435,7 @@ void QKmsCursor::setPos(const QPoint &pos)
}
}
-void QKmsCursor::initCursorAtlas()
+void QEglFSKmsCursor::initCursorAtlas()
{
static QByteArray json = qgetenv("QT_QPA_EGLFS_CURSOR");
if (json.isEmpty())
@@ -604,8 +443,8 @@ void QKmsCursor::initCursorAtlas()
QFile file(QString::fromUtf8(json));
if (!file.open(QFile::ReadOnly)) {
- drmModeSetCursor(m_dri_fd, m_crtc, 0, 0, 0);
- drmModeMoveCursor(m_dri_fd, m_crtc, 0, 0);
+ drmModeSetCursor(m_screen->device()->fd(), m_screen->output().crtc_id, 0, 0, 0);
+ drmModeMoveCursor(m_screen->device()->fd(), m_screen->output().crtc_id, 0, 0);
m_visible = false;
return;
}
@@ -635,4 +474,384 @@ void QKmsCursor::initCursorAtlas()
m_cursorAtlas.image = image;
}
+void QEglFSKmsScreen::bufferDestroyedHandler(gbm_bo *bo, void *data)
+{
+ FrameBuffer *fb = static_cast<FrameBuffer *>(data);
+
+ if (fb->fb) {
+ gbm_device *device = gbm_bo_get_device(bo);
+ drmModeRmFB(gbm_device_get_fd(device), fb->fb);
+ }
+
+ delete fb;
+}
+
+QEglFSKmsScreen::FrameBuffer *QEglFSKmsScreen::framebufferForBufferObject(gbm_bo *bo)
+{
+ {
+ FrameBuffer *fb = static_cast<FrameBuffer *>(gbm_bo_get_user_data(bo));
+ if (fb)
+ return fb;
+ }
+
+ uint32_t width = gbm_bo_get_width(bo);
+ uint32_t height = gbm_bo_get_height(bo);
+ uint32_t stride = gbm_bo_get_stride(bo);
+ uint32_t handle = gbm_bo_get_handle(bo).u32;
+
+ QScopedPointer<FrameBuffer> fb(new FrameBuffer);
+
+ int ret = drmModeAddFB(m_device->fd(), width, height, 24, 32,
+ stride, handle, &fb->fb);
+
+ if (ret) {
+ qWarning("Failed to create KMS FB!");
+ return Q_NULLPTR;
+ }
+
+ gbm_bo_set_user_data(bo, fb.data(), bufferDestroyedHandler);
+ return fb.take();
+
+}
+
+QEglFSKmsScreen::QEglFSKmsScreen(QEglFSKmsDevice *device, QEglFSKmsOutput output, QPoint position)
+ : QEglFSScreen(eglGetDisplay(device->device()))
+ , m_device(device)
+ , m_gbm_surface(Q_NULLPTR)
+ , m_gbm_bo_current(Q_NULLPTR)
+ , m_gbm_bo_next(Q_NULLPTR)
+ , m_output(output)
+ , m_pos(position)
+ , m_cursor(new QEglFSKmsCursor(this))
+{
+}
+
+QEglFSKmsScreen::~QEglFSKmsScreen()
+{
+ restoreMode();
+}
+
+QRect QEglFSKmsScreen::geometry() const
+{
+ return QRect(m_pos.x(), m_pos.y(),
+ m_output.mode.hdisplay,
+ m_output.mode.vdisplay);
+}
+
+int QEglFSKmsScreen::depth() const
+{
+ return 32;
+}
+
+QImage::Format QEglFSKmsScreen::format() const
+{
+ return QImage::Format_RGB32;
+}
+
+QSizeF QEglFSKmsScreen::physicalSize() const
+{
+ return m_output.physical_size;
+}
+
+QDpi QEglFSKmsScreen::logicalDpi() const
+{
+ QSizeF ps = physicalSize();
+ QSize s = geometry().size();
+
+ if (ps.isValid() && s.isValid())
+ return QDpi(25.4 * s.width() / ps.width(),
+ 25.4 * s.height() / ps.height());
+ else
+ return QDpi(100, 100);
+}
+
+Qt::ScreenOrientation QEglFSKmsScreen::nativeOrientation() const
+{
+ return Qt::PrimaryOrientation;
+}
+
+Qt::ScreenOrientation QEglFSKmsScreen::orientation() const
+{
+ return Qt::PrimaryOrientation;
+}
+
+QPlatformCursor *QEglFSKmsScreen::cursor() const
+{
+ return m_cursor.data();
+}
+
+gbm_surface *QEglFSKmsScreen::createSurface()
+{
+ if (!m_gbm_surface)
+ m_gbm_surface = gbm_surface_create(m_device->device(),
+ geometry().width(),
+ geometry().height(),
+ GBM_FORMAT_XRGB8888,
+ GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
+ return m_gbm_surface;
+}
+
+void QEglFSKmsScreen::destroySurface()
+{
+ if (m_gbm_bo_current) {
+ gbm_bo_destroy(m_gbm_bo_current);
+ m_gbm_bo_current = Q_NULLPTR;
+ }
+
+ if (m_gbm_bo_next) {
+ gbm_bo_destroy(m_gbm_bo_next);
+ m_gbm_bo_next = Q_NULLPTR;
+ }
+
+ if (m_gbm_surface) {
+ gbm_surface_destroy(m_gbm_surface);
+ m_gbm_surface = Q_NULLPTR;
+ }
+}
+
+void QEglFSKmsScreen::waitForFlip()
+{
+ // Don't lock the mutex unless we actually need to
+ if (!m_gbm_bo_next)
+ return;
+
+ QMutexLocker lock(&m_waitForFlipMutex);
+ while (m_gbm_bo_next)
+ m_device->handleDrmEvent();
+}
+
+void QEglFSKmsScreen::flip()
+{
+ if (!m_gbm_surface) {
+ qWarning("Cannot sync before platform init!");
+ return;
+ }
+
+ m_gbm_bo_next = gbm_surface_lock_front_buffer(m_gbm_surface);
+ if (!m_gbm_bo_next) {
+ qWarning("Could not lock GBM surface front buffer!");
+ return;
+ }
+
+ FrameBuffer *fb = framebufferForBufferObject(m_gbm_bo_next);
+
+ if (!m_mode_set) {
+ m_output.saved_crtc = drmModeGetCrtc(m_device->fd(), m_output.crtc_id);
+ int ret = drmModeSetCrtc(m_device->fd(),
+ m_output.crtc_id,
+ fb->fb,
+ 0, 0,
+ &m_output.conn_id, 1,
+ &m_output.mode);
+ if (ret) {
+ qErrnoWarning("Could not set DRM mode!");
+ } else {
+ m_mode_set = true;
+ }
+ }
+
+ int ret = drmModePageFlip(m_device->fd(),
+ m_output.crtc_id,
+ fb->fb,
+ DRM_MODE_PAGE_FLIP_EVENT,
+ this);
+ if (ret) {
+ qErrnoWarning("Could not queue DRM page flip!");
+ gbm_surface_release_buffer(m_gbm_surface, m_gbm_bo_next);
+ m_gbm_bo_next = Q_NULLPTR;
+ }
+}
+
+void QEglFSKmsScreen::flipFinished()
+{
+ if (m_gbm_bo_current)
+ gbm_surface_release_buffer(m_gbm_surface,
+ m_gbm_bo_current);
+
+ m_gbm_bo_current = m_gbm_bo_next;
+ m_gbm_bo_next = Q_NULLPTR;
+}
+
+void QEglFSKmsScreen::restoreMode()
+{
+ if (m_mode_set && m_output.saved_crtc) {
+ drmModeSetCrtc(m_device->fd(),
+ m_output.saved_crtc->crtc_id,
+ m_output.saved_crtc->buffer_id,
+ 0, 0,
+ &m_output.conn_id, 1,
+ &m_output.saved_crtc->mode);
+ drmModeFreeCrtc(m_output.saved_crtc);
+ m_output.saved_crtc = Q_NULLPTR;
+ m_mode_set = false;
+ }
+}
+
+static QList<drmModeConnector *> findConnectors(int dri_fd, drmModeRes *resources)
+{
+ QList<drmModeConnector *> connectors;
+
+ for (int i = 0; i < resources->count_connectors; i++) {
+ drmModeConnector *connector = drmModeGetConnector(dri_fd, resources->connectors[i]);
+ if (!connector)
+ continue;
+
+ if (connector->connection == DRM_MODE_CONNECTED && connector->count_modes > 0) {
+ connectors.append(connector);
+ continue;
+ }
+
+ drmModeFreeConnector(connector);
+ }
+
+ return connectors;
+}
+
+static drmModeEncoder *findEncoder(int dri_fd, drmModeRes *resources, uint32_t encoder_id)
+{
+ for (int i = 0; i < resources->count_encoders; i++) {
+ drmModeEncoder *encoder = drmModeGetEncoder(dri_fd, resources->encoders[i]);
+
+ if (!encoder)
+ continue;
+
+ if (encoder->encoder_id == encoder_id)
+ return encoder;
+
+ drmModeFreeEncoder(encoder);
+ }
+
+ return Q_NULLPTR;
+}
+
+bool QEglFSKmsDevice::setup_kms()
+{
+ drmModeRes *resources = drmModeGetResources(m_dri_fd);
+ if (!resources) {
+ qWarning("drmModeGetResources failed");
+ return false;
+ }
+
+ QList<drmModeConnector *> connectors = findConnectors(m_dri_fd, resources);
+ if (connectors.isEmpty()) {
+ qWarning("No currently active connectors found");
+ return false;
+ }
+
+ while (!connectors.isEmpty()) {
+ drmModeConnector *connector = connectors.takeFirst();
+ drmModeEncoder *encoder = findEncoder(m_dri_fd, resources, connector->encoder_id);
+
+ if (!encoder) {
+ drmModeFreeConnector(connector);
+ continue;
+ }
+
+ QEglFSKmsOutput output = {
+ connector->connector_id,
+ encoder->crtc_id,
+ QSizeF(connector->mmWidth, connector->mmHeight),
+ connector->modes[0],
+ false,
+ Q_NULLPTR
+ };
+
+ drmModeFreeEncoder(encoder);
+ drmModeFreeConnector(connector);
+
+ m_validOutputs.append(output);
+ }
+
+ drmModeFreeResources(resources);
+
+ return m_validOutputs.size() > 0;
+}
+
+void QEglFSKmsDevice::pageFlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data)
+{
+ Q_UNUSED(fd);
+ Q_UNUSED(sequence);
+ Q_UNUSED(tv_sec);
+ Q_UNUSED(tv_usec);
+
+ QEglFSKmsScreen *screen = static_cast<QEglFSKmsScreen *>(user_data);
+ screen->flipFinished();
+}
+
+QEglFSKmsDevice::QEglFSKmsDevice(const QString &path)
+ : m_path(path)
+ , m_dri_fd(-1)
+ , m_gbm_device(Q_NULLPTR)
+{
+}
+
+bool QEglFSKmsDevice::open()
+{
+ Q_ASSERT(m_dri_fd == -1);
+ Q_ASSERT(m_gbm_device == Q_NULLPTR);
+
+ m_dri_fd = qt_safe_open(m_path.toLocal8Bit().constData(), O_RDWR | O_CLOEXEC);
+ if (m_dri_fd == -1) {
+ qErrnoWarning("Could not open DRM device %s", qPrintable(m_path));
+ return false;
+ }
+
+ m_gbm_device = gbm_create_device(m_dri_fd);
+ if (!m_gbm_device) {
+ qErrnoWarning("Could not create GBM device");
+ qt_safe_close(m_dri_fd);
+ m_dri_fd = -1;
+ return false;
+ }
+
+ return true;
+}
+
+void QEglFSKmsDevice::close()
+{
+ if (m_gbm_device) {
+ gbm_device_destroy(m_gbm_device);
+ m_gbm_device = Q_NULLPTR;
+ }
+
+ if (m_dri_fd != -1) {
+ qt_safe_close(m_dri_fd);
+ m_dri_fd = -1;
+ }
+}
+
+void QEglFSKmsDevice::createScreens()
+{
+ if (!setup_kms())
+ return;
+
+ QEglFSIntegration *integration = static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration());
+ QPoint pos;
+ foreach (const QEglFSKmsOutput &output, m_validOutputs) {
+ integration->addScreen(new QEglFSKmsScreen(this, output, pos));
+ pos.rx() += output.mode.hdisplay;
+ }
+}
+
+gbm_device *QEglFSKmsDevice::device() const
+{
+ return m_gbm_device;
+}
+
+int QEglFSKmsDevice::fd() const
+{
+ return m_dri_fd;
+}
+
+void QEglFSKmsDevice::handleDrmEvent()
+{
+ drmEventContext drmEvent = {
+ DRM_EVENT_CONTEXT_VERSION,
+ Q_NULLPTR, // vblank handler
+ pageFlipHandler // page flip handler
+ };
+
+ drmHandleEvent(m_dri_fd, &drmEvent);
+}
+
#include "qeglfshooks_kms.moc"
diff --git a/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp b/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp
index 04acc4c759..ddf19face6 100644
--- a/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp
+++ b/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp
@@ -32,9 +32,13 @@
****************************************************************************/
#include "qeglfshooks.h"
+#include "qeglfsintegration.h"
+#include "qeglfsscreen.h"
+
#include <QtPlatformSupport/private/qeglplatformcursor_p.h>
#include <QtPlatformSupport/private/qeglconvenience_p.h>
#include <QtCore/QRegularExpression>
+#include <QtGui/private/qguiapplication_p.h>
#if defined(Q_OS_LINUX)
#include <fcntl.h>
@@ -94,6 +98,18 @@ EGLNativeDisplayType QEglFSHooks::platformDisplay() const
return EGL_DEFAULT_DISPLAY;
}
+void QEglFSHooks::screenInit()
+{
+ QEglFSIntegration *integration = static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration());
+ integration->addScreen(new QEglFSScreen(integration->display()));
+}
+
+void QEglFSHooks::screenDestroy()
+{
+ while (!qApp->screens().isEmpty())
+ delete qApp->screens().last()->handle();
+}
+
QSizeF QEglFSHooks::physicalScreenSize() const
{
return q_physicalScreenSizeFromFb(framebuffer, screenSize());
@@ -184,8 +200,10 @@ QPlatformCursor *QEglFSHooks::createCursor(QPlatformScreen *screen) const
return new QEGLPlatformCursor(screen);
}
-void QEglFSHooks::waitForVSync() const
+void QEglFSHooks::waitForVSync(QPlatformSurface *surface) const
{
+ Q_UNUSED(surface);
+
#if defined(FBIO_WAITFORVSYNC)
static const bool forceSync = qEnvironmentVariableIntValue("QT_QPA_EGLFS_FORCEVSYNC");
if (forceSync && framebuffer != -1) {
@@ -196,8 +214,9 @@ void QEglFSHooks::waitForVSync() const
#endif
}
-void QEglFSHooks::presentBuffer()
+void QEglFSHooks::presentBuffer(QPlatformSurface *surface)
{
+ Q_UNUSED(surface);
}
bool QEglFSHooks::supportsPBuffers() const
diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/qeglfsintegration.cpp
index 16a113691f..ffae64d31c 100644
--- a/src/plugins/platforms/eglfs/qeglfsintegration.cpp
+++ b/src/plugins/platforms/eglfs/qeglfsintegration.cpp
@@ -77,6 +77,11 @@ bool QEglFSIntegration::hasCapability(QPlatformIntegration::Capability cap) cons
return QEGLPlatformIntegration::hasCapability(cap);
}
+void QEglFSIntegration::addScreen(QPlatformScreen *screen)
+{
+ screenAdded(screen);
+}
+
void QEglFSIntegration::initialize()
{
QEglFSHooks::hooks()->platformInit();
@@ -85,10 +90,13 @@ void QEglFSIntegration::initialize()
if (!mDisableInputHandlers)
createInputHandlers();
+
+ QEglFSHooks::hooks()->screenInit();
}
void QEglFSIntegration::destroy()
{
+ QEglFSHooks::hooks()->screenDestroy();
QEGLPlatformIntegration::destroy();
QEglFSHooks::hooks()->platformDestroy();
}
@@ -98,11 +106,6 @@ EGLNativeDisplayType QEglFSIntegration::nativeDisplay() const
return QEglFSHooks::hooks()->platformDisplay();
}
-QEGLPlatformScreen *QEglFSIntegration::createScreen() const
-{
- return new QEglFSScreen(display());
-}
-
QEGLPlatformWindow *QEglFSIntegration::createWindow(QWindow *window) const
{
return new QEglFSWindow(window);
@@ -138,17 +141,6 @@ QPlatformOffscreenSurface *QEglFSIntegration::createOffscreenSurface(EGLDisplay
// Never return null. Multiple QWindows are not supported by this plugin.
}
-QVariant QEglFSIntegration::styleHint(QPlatformIntegration::StyleHint hint) const
-{
- switch (hint)
- {
- case QPlatformIntegration::ShowIsFullScreen:
- return screen()->compositingWindow() == 0;
- default:
- return QPlatformIntegration::styleHint(hint);
- }
-}
-
EGLConfig QEglFSIntegration::chooseConfig(EGLDisplay display, const QSurfaceFormat &format)
{
class Chooser : public QEglConfigChooser {
diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.h b/src/plugins/platforms/eglfs/qeglfsintegration.h
index 59aabebb7a..86038910ca 100644
--- a/src/plugins/platforms/eglfs/qeglfsintegration.h
+++ b/src/plugins/platforms/eglfs/qeglfsintegration.h
@@ -45,16 +45,16 @@ class QEglFSIntegration : public QEGLPlatformIntegration
public:
QEglFSIntegration();
+ void addScreen(QPlatformScreen *screen);
+
void initialize() Q_DECL_OVERRIDE;
void destroy() Q_DECL_OVERRIDE;
bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE;
- QVariant styleHint(QPlatformIntegration::StyleHint hint) const Q_DECL_OVERRIDE;
static EGLConfig chooseConfig(EGLDisplay display, const QSurfaceFormat &format);
protected:
- QEGLPlatformScreen *createScreen() const Q_DECL_OVERRIDE;
QEGLPlatformWindow *createWindow(QWindow *window) const Q_DECL_OVERRIDE;
QEGLPlatformContext *createContext(const QSurfaceFormat &format,
QPlatformOpenGLContext *shareContext,
diff --git a/src/plugins/platforms/eglfs/qeglfswindow.cpp b/src/plugins/platforms/eglfs/qeglfswindow.cpp
index 1645d81878..ef1f496b29 100644
--- a/src/plugins/platforms/eglfs/qeglfswindow.cpp
+++ b/src/plugins/platforms/eglfs/qeglfswindow.cpp
@@ -147,8 +147,9 @@ void QEglFSWindow::invalidateSurface()
void QEglFSWindow::resetSurface()
{
- EGLDisplay display = static_cast<QEglFSScreen *>(screen())->display();
- m_window = QEglFSHooks::hooks()->createNativeWindow(this, QEglFSHooks::hooks()->screenSize(), m_format);
+ QEglFSScreen *nativeScreen = static_cast<QEglFSScreen *>(screen());
+ EGLDisplay display = nativeScreen->display();
+ m_window = QEglFSHooks::hooks()->createNativeWindow(this, nativeScreen->geometry().size(), m_format);
m_surface = eglCreateWindowSurface(display, m_config, m_window, NULL);
if (m_surface == EGL_NO_SURFACE) {
EGLint error = eglGetError();