Lighthouse: Wayland: Added a xpixmap readback glcontext
authorJørgen Lind <jorgen.lind@nokia.com>
Wed, 23 Mar 2011 15:57:11 +0000 (16:57 +0100)
committerJørgen Lind <jorgen.lind@nokia.com>
Wed, 23 Mar 2011 16:00:22 +0000 (17:00 +0100)
It uses a x11 pixmap to render all gl content into, then reads it back
using glReadPixels. Then it sends it over the wire like any other shm
surface.

17 files changed:
src/plugins/platforms/wayland/gl_integration/gl_integration.pri
src/plugins/platforms/wayland/gl_integration/qwaylandglintegration.h
src/plugins/platforms/wayland/gl_integration/qwaylandglwindowsurface.cpp
src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglintegration.cpp
src/plugins/platforms/wayland/gl_integration/xpixmap_egl/qwaylandxpixmapeglcontext.cpp [new file with mode: 0644]
src/plugins/platforms/wayland/gl_integration/xpixmap_egl/qwaylandxpixmapeglcontext.h [new file with mode: 0644]
src/plugins/platforms/wayland/gl_integration/xpixmap_egl/qwaylandxpixmapeglintegration.cpp [new file with mode: 0644]
src/plugins/platforms/wayland/gl_integration/xpixmap_egl/qwaylandxpixmapeglintegration.h [new file with mode: 0644]
src/plugins/platforms/wayland/gl_integration/xpixmap_egl/qwaylandxpixmapwindow.cpp [new file with mode: 0644]
src/plugins/platforms/wayland/gl_integration/xpixmap_egl/qwaylandxpixmapwindow.h [new file with mode: 0644]
src/plugins/platforms/wayland/gl_integration/xpixmap_egl/xpixmap_egl.pri [new file with mode: 0644]
src/plugins/platforms/wayland/qwaylanddisplay.cpp
src/plugins/platforms/wayland/qwaylanddisplay.h
src/plugins/platforms/wayland/qwaylandshmsurface.h
src/plugins/platforms/wayland/qwaylandshmwindow.cpp
src/plugins/platforms/wayland/qwaylandshmwindow.h
src/plugins/platforms/wayland/wayland.pro

index 8a792a5..ed2b021 100644 (file)
@@ -10,4 +10,8 @@ wayland_egl {
     include ($$PWD/wayland_egl/wayland_egl.pri)
 }
 
+xpixmap_egl {
+    include ($$PWD/xpixmap_egl/xpixmap_egl.pri)
+}
+
 
index a1f6b2c..52a663f 100644 (file)
@@ -2,6 +2,7 @@
 #define QWAYLANDGLINTEGRATION_H
 
 class QWaylandWindow;
+class QWaylandDisplay;
 class QWidget;
 
 class QWaylandGLIntegration
@@ -14,7 +15,7 @@ public:
 
     virtual QWaylandWindow *createEglWindow(QWidget *widget) = 0;
 
-    static QWaylandGLIntegration *createEglIntegration(struct wl_display *waylandDisplay);
+    static QWaylandGLIntegration *createEglIntegration(QWaylandDisplay *waylandDisplay);
 };
 
 #endif // QWAYLANDGLINTEGRATION_H
index ca9fb97..8c83128 100644 (file)
@@ -175,7 +175,7 @@ void QWaylandGLWindowSurface::resize(const QSize &size)
     QWindowSurface::resize(size);
     window()->platformWindow()->glContext()->makeCurrent();
     delete mPaintDevice;
-    mPaintDevice = new QGLFramebufferObject(size,QGLFramebufferObject::CombinedDepthStencil,GL_TEXTURE_2D,GL_RGBA);
+    mPaintDevice = new QGLFramebufferObject(size);
 }
 
 QT_END_NAMESPACE
index eb46bc7..255fbfe 100644 (file)
@@ -1,5 +1,7 @@
 #include "qwaylandeglintegration.h"
 
+#include "gl_integration/qwaylandglintegration.h"
+
 #include "qwaylandeglwindow.h"
 
 QWaylandEglIntegration::QWaylandEglIntegration(struct wl_display *waylandDisplay)
@@ -42,7 +44,7 @@ wl_egl_display * QWaylandEglIntegration::nativeDisplay() const
     return mNativeEglDisplay;
 }
 
-QWaylandGLIntegration *QWaylandGLIntegration::createEglIntegration(wl_display *waylandDisplay)
+QWaylandGLIntegration *QWaylandGLIntegration::createEglIntegration(QWaylandDisplay *waylandDisplay)
 {
-    return new QWaylandEglIntegration(waylandDisplay);
+    return new QWaylandEglIntegration(waylandDisplay->wl_display());
 }
diff --git a/src/plugins/platforms/wayland/gl_integration/xpixmap_egl/qwaylandxpixmapeglcontext.cpp b/src/plugins/platforms/wayland/gl_integration/xpixmap_egl/qwaylandxpixmapeglcontext.cpp
new file mode 100644 (file)
index 0000000..e29ad97
--- /dev/null
@@ -0,0 +1,109 @@
+#include "qwaylandxpixmapeglcontext.h"
+
+#include "../../../eglconvenience/qeglconvenience.h"
+
+#include <QtOpenGL/QGLContext>
+
+#include "qwaylandshmsurface.h"
+
+#include <QtCore/QDebug>
+
+QXPixmapReadbackGLContext::QXPixmapReadbackGLContext(QWaylandXPixmapEglIntegration *eglIntegration, QWaylandXPixmapWindow *window)
+    : mEglIntegration(eglIntegration)
+    , mWindow(window)
+    , mBuffer(0)
+    , mPixmap(0)
+    , mConfig(q_configFromQPlatformWindowFormat(eglIntegration->eglDisplay(),window->widget()->platformWindowFormat(),true,EGL_PIXMAP_BIT))
+    , mPixmapSurface(EGL_NO_SURFACE)
+{
+    QVector<EGLint> eglContextAttrs;
+    eglContextAttrs.append(EGL_CONTEXT_CLIENT_VERSION);
+    eglContextAttrs.append(2);
+    eglContextAttrs.append(EGL_NONE);
+
+    mContext = eglCreateContext(eglIntegration->eglDisplay(),mConfig,0,eglContextAttrs.constData());
+
+    geometryChanged();
+}
+
+QXPixmapReadbackGLContext::~QXPixmapReadbackGLContext()
+{
+    eglDestroyContext(mEglIntegration->eglDisplay(),mContext);
+}
+
+void QXPixmapReadbackGLContext::makeCurrent()
+{
+    QPlatformGLContext::makeCurrent();
+
+    while(mWindow->waitingForFrameSync()) {
+        mEglIntegration->waylandDisplay()->iterate();
+    }
+
+    eglMakeCurrent(mEglIntegration->eglDisplay(),mPixmapSurface,mPixmapSurface,mContext);
+}
+
+void QXPixmapReadbackGLContext::doneCurrent()
+{
+    QPlatformGLContext::doneCurrent();
+    eglMakeCurrent(mEglIntegration->eglDisplay(),EGL_NO_SURFACE,EGL_NO_SURFACE,EGL_NO_CONTEXT);
+}
+
+void QXPixmapReadbackGLContext::swapBuffers()
+{
+    eglSwapBuffers(mEglIntegration->eglDisplay(),mPixmapSurface);
+
+    if (QPlatformGLContext::currentContext() != this) {
+        makeCurrent();
+    }
+
+    QSize size = mWindow->geometry().size();
+
+    QImage img(size,QImage::Format_ARGB32);
+    const uchar *constBits = img.bits();
+    void *pixels = const_cast<uchar *>(constBits);
+
+    glReadPixels(0,0, size.width(), size.height(), GL_RGBA,GL_UNSIGNED_BYTE, pixels);
+
+    img = img.mirrored();
+    constBits = img.bits();
+
+    const uchar *constDstBits = mBuffer->image()->bits();
+    uchar *dstBits = const_cast<uchar *>(constDstBits);
+    memcpy(dstBits,constBits,(img.width()*4) * img.height());
+
+
+    mWindow->damage(QRegion(QRect(QPoint(0,0),size)));
+}
+
+void * QXPixmapReadbackGLContext::getProcAddress(const QString &procName)
+{
+    return (void *) eglGetProcAddress(procName.toLatin1().data());
+}
+
+QPlatformWindowFormat QXPixmapReadbackGLContext::platformWindowFormat() const
+{
+    return qt_qPlatformWindowFormatFromConfig(mEglIntegration->eglDisplay(),mConfig);
+}
+
+void QXPixmapReadbackGLContext::geometryChanged()
+{
+    while (mWindow->waitingForFrameSync())
+        mEglIntegration->waylandDisplay()->iterate();
+
+    QSize size(mWindow->geometry().size());
+    delete mBuffer;
+    if (mPixmap)
+        XFreePixmap(mEglIntegration->xDisplay(),mPixmap);
+    if (mPixmapSurface != EGL_NO_SURFACE)
+        eglDestroySurface(mEglIntegration->eglDisplay(),mPixmapSurface);
+
+    mBuffer = new QWaylandShmBuffer(mEglIntegration->waylandDisplay(),size,QImage::Format_ARGB32);
+    mWindow->attach(mBuffer);
+    mPixmap = XCreatePixmap(mEglIntegration->xDisplay(),mEglIntegration->rootWindow(),size.width(),size.height(),mEglIntegration->depth());
+    XSync(mEglIntegration->xDisplay(),False);
+
+    mPixmapSurface = eglCreatePixmapSurface(mEglIntegration->eglDisplay(),mConfig,mPixmap,0);
+    if (mPixmapSurface == EGL_NO_SURFACE) {
+        qDebug() << "Could not make egl surface out of pixmap :(";
+    }
+}
diff --git a/src/plugins/platforms/wayland/gl_integration/xpixmap_egl/qwaylandxpixmapeglcontext.h b/src/plugins/platforms/wayland/gl_integration/xpixmap_egl/qwaylandxpixmapeglcontext.h
new file mode 100644 (file)
index 0000000..e6c6e8d
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef QXPIXMAPREADBACKGLCONTEXT_H
+#define QXPIXMAPREADBACKGLCONTEXT_H
+
+#include <QPlatformGLContext>
+#include <QtGui/QWidget>
+
+#include "qwaylandxpixmapeglintegration.h"
+#include "qwaylandxpixmapwindow.h"
+
+class QWaylandShmBuffer;
+
+class QXPixmapReadbackGLContext : public QPlatformGLContext
+{
+public:
+    QXPixmapReadbackGLContext(QWaylandXPixmapEglIntegration *eglIntegration, QWaylandXPixmapWindow *window);
+    ~QXPixmapReadbackGLContext();
+
+    void makeCurrent();
+    void doneCurrent();
+    void swapBuffers();
+    void* getProcAddress(const QString& procName);
+
+    virtual QPlatformWindowFormat platformWindowFormat() const;
+
+    void geometryChanged();
+
+private:
+    QWaylandXPixmapEglIntegration *mEglIntegration;
+    QWaylandXPixmapWindow *mWindow;
+    QWaylandShmBuffer *mBuffer;
+
+    Pixmap mPixmap;
+
+    EGLConfig mConfig;
+    EGLContext mContext;
+    EGLSurface mPixmapSurface;
+};
+
+#endif // QXPIXMAPREADBACKGLCONTEXT_H
diff --git a/src/plugins/platforms/wayland/gl_integration/xpixmap_egl/qwaylandxpixmapeglintegration.cpp b/src/plugins/platforms/wayland/gl_integration/xpixmap_egl/qwaylandxpixmapeglintegration.cpp
new file mode 100644 (file)
index 0000000..c9f244c
--- /dev/null
@@ -0,0 +1,70 @@
+#include "qwaylandxpixmapeglintegration.h"
+
+#include <QDebug>
+
+#include "qwaylandxpixmapwindow.h"
+
+QWaylandXPixmapEglIntegration::QWaylandXPixmapEglIntegration(QWaylandDisplay *display)
+    : QWaylandGLIntegration()
+    , mWaylandDisplay(display)
+{
+    char *display_name = getenv("DISPLAY");
+    mDisplay = XOpenDisplay(display_name);
+    mScreen = XDefaultScreen(mDisplay);
+    mRootWindow = XDefaultRootWindow(mDisplay);
+    XSync(mDisplay, False);
+}
+
+QWaylandXPixmapEglIntegration::~QWaylandXPixmapEglIntegration()
+{
+    XCloseDisplay(mDisplay);
+}
+
+
+QWaylandGLIntegration *QWaylandGLIntegration::createEglIntegration(QWaylandDisplay *waylandDisplay)
+{
+    return new QWaylandXPixmapEglIntegration(waylandDisplay);
+}
+
+void QWaylandXPixmapEglIntegration::initialize()
+{
+    eglBindAPI(EGL_OPENGL_ES_API);
+    mEglDisplay = eglGetDisplay(mDisplay);
+    EGLint major, minor;
+    EGLBoolean initialized = eglInitialize(mEglDisplay,&major,&minor);
+    if (initialized) {
+        qDebug() << "EGL initialized successfully" << major << "," << minor;
+    } else {
+        qDebug() << "EGL could not initialized. All EGL and GL operations will fail";
+    }
+}
+
+QWaylandWindow * QWaylandXPixmapEglIntegration::createEglWindow(QWidget *widget)
+{
+    return new QWaylandXPixmapWindow(widget,this);
+}
+
+EGLDisplay QWaylandXPixmapEglIntegration::eglDisplay()
+{
+    return mEglDisplay;
+}
+
+Window QWaylandXPixmapEglIntegration::rootWindow() const
+{
+    return mRootWindow;
+}
+
+int QWaylandXPixmapEglIntegration::depth() const
+{
+    return XDefaultDepth(mDisplay,mScreen);
+}
+
+Display * QWaylandXPixmapEglIntegration::xDisplay() const
+{
+    return mDisplay;
+}
+
+QWaylandDisplay * QWaylandXPixmapEglIntegration::waylandDisplay() const
+{
+    return mWaylandDisplay;
+}
diff --git a/src/plugins/platforms/wayland/gl_integration/xpixmap_egl/qwaylandxpixmapeglintegration.h b/src/plugins/platforms/wayland/gl_integration/xpixmap_egl/qwaylandxpixmapeglintegration.h
new file mode 100644 (file)
index 0000000..534494b
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef QWAYLANDXPIXMAPEGLINTEGRATION_H
+#define QWAYLANDXPIXMAPEGLINTEGRATION_H
+
+#include "gl_integration/qwaylandglintegration.h"
+
+#include <QtCore/QTextStream>
+#include <QtCore/QDataStream>
+#include <QtCore/QMetaType>
+#include <QtCore/QVariant>
+#include <QtGui/QWidget>
+
+#include <X11/Xlib.h>
+
+#include <EGL/egl.h>
+//#include <EGL
+
+class QWaylandXPixmapEglIntegration : public QWaylandGLIntegration
+{
+public:
+    QWaylandXPixmapEglIntegration(QWaylandDisplay *display);
+    ~QWaylandXPixmapEglIntegration();
+
+    void initialize();
+    QWaylandWindow *createEglWindow(QWidget *widget);
+
+    QWaylandDisplay *waylandDisplay() const;
+    Display *xDisplay() const;
+    Window rootWindow() const;
+    int depth() const;
+
+    EGLDisplay eglDisplay();
+
+private:
+    QWaylandDisplay *mWaylandDisplay;
+    Display *mDisplay;
+    int mScreen;
+    Window mRootWindow;
+    EGLDisplay mEglDisplay;
+
+};
+
+#endif // QWAYLANDXPIXMAPEGLINTEGRATION_H
diff --git a/src/plugins/platforms/wayland/gl_integration/xpixmap_egl/qwaylandxpixmapwindow.cpp b/src/plugins/platforms/wayland/gl_integration/xpixmap_egl/qwaylandxpixmapwindow.cpp
new file mode 100644 (file)
index 0000000..add30d8
--- /dev/null
@@ -0,0 +1,38 @@
+#include "qwaylandxpixmapwindow.h"
+
+#include "qwaylandxpixmapeglcontext.h"
+QWaylandXPixmapWindow::QWaylandXPixmapWindow(QWidget *window, QWaylandXPixmapEglIntegration *eglIntegration)
+    : QWaylandShmWindow(window)
+    , mEglIntegration(eglIntegration)
+    , mContext(0)
+{
+}
+
+QWaylandWindow::WindowType QWaylandXPixmapWindow::windowType() const
+{
+    //We'r lying, maybe we should add a type, but for now it will do
+    //since this is primarly used by the windowsurface.
+    return QWaylandWindow::Egl;
+}
+
+QPlatformGLContext *QWaylandXPixmapWindow::glContext() const
+{
+    if (!mContext) {
+        QWaylandXPixmapWindow *that = const_cast<QWaylandXPixmapWindow *>(this);
+        that->mContext = new QXPixmapReadbackGLContext(mEglIntegration,that);
+    }
+    return mContext;
+}
+
+void QWaylandXPixmapWindow::newSurfaceCreated()
+{
+}
+
+void QWaylandXPixmapWindow::setGeometry(const QRect &rect)
+{
+    QPlatformWindow::setGeometry(rect);
+
+    if (mContext)
+        mContext->geometryChanged();
+}
+
diff --git a/src/plugins/platforms/wayland/gl_integration/xpixmap_egl/qwaylandxpixmapwindow.h b/src/plugins/platforms/wayland/gl_integration/xpixmap_egl/qwaylandxpixmapwindow.h
new file mode 100644 (file)
index 0000000..919e29d
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef QWAYLANDXPIXMAPWINDOW_H
+#define QWAYLANDXPIXMAPWINDOW_H
+
+#include "qwaylandshmwindow.h"
+#include "qwaylandxpixmapeglintegration.h"
+
+class QXPixmapReadbackGLContext;
+
+class QWaylandXPixmapWindow : public QWaylandShmWindow
+{
+public:
+    QWaylandXPixmapWindow(QWidget *window, QWaylandXPixmapEglIntegration *eglIntegration);
+
+    WindowType windowType() const;
+
+    QPlatformGLContext *glContext() const;
+
+    void setGeometry(const QRect &rect);
+protected:
+    void newSurfaceCreated();
+
+private:
+    QWaylandXPixmapEglIntegration *mEglIntegration;
+    QXPixmapReadbackGLContext *mContext;
+};
+
+#endif // QWAYLANDXPIXMAPWINDOW_H
diff --git a/src/plugins/platforms/wayland/gl_integration/xpixmap_egl/xpixmap_egl.pri b/src/plugins/platforms/wayland/gl_integration/xpixmap_egl/xpixmap_egl.pri
new file mode 100644 (file)
index 0000000..87e2d28
--- /dev/null
@@ -0,0 +1,14 @@
+
+LIBS += -lX11 -lXext -lEGL
+
+HEADERS += \
+    gl_integration/xpixmap_egl/qwaylandxpixmapeglintegration.h \
+    gl_integration/xpixmap_egl/qwaylandxpixmapwindow.h \
+    gl_integration/xpixmap_egl/qwaylandxpixmapeglcontext.h \
+    $$PWD/../../../eglconvenience/qeglconvenience.h
+
+SOURCES += \
+    gl_integration/xpixmap_egl/qwaylandxpixmapeglintegration.cpp \
+    gl_integration/xpixmap_egl/qwaylandxpixmapwindow.cpp \
+    gl_integration/xpixmap_egl/qwaylandxpixmapeglcontext.cpp \
+    $$PWD/../../../eglconvenience/qeglconvenience.cpp
index eebc9de..22e38eb 100644 (file)
@@ -190,7 +190,7 @@ QWaylandDisplay::QWaylandDisplay(void)
                                    QWaylandDisplay::displayHandleGlobal, this);
 
 #ifdef QT_WAYLAND_GL_SUPPORT
-    mEglIntegration = QWaylandGLIntegration::createEglIntegration(mDisplay);
+    mEglIntegration = QWaylandGLIntegration::createEglIntegration(this);
 #endif
 
     readEvents();
index 535dcd6..fc26ad2 100644 (file)
@@ -81,6 +81,7 @@ public:
 
     void iterate();
 
+    struct wl_display *wl_display() const { return mDisplay; }
 public slots:
     void readEvents(void);
     void flushRequests(void);
index 02b324a..b29ceaf 100644 (file)
@@ -74,11 +74,8 @@ public:
     void beginPaint(const QRegion &);
 
 private:
-    static void frameCallback(void *data, uint32_t time);\
-
     QWaylandShmBuffer *mBuffer;
     QWaylandDisplay *mDisplay;
-    bool mWaitingForFrameSync;
 };
 
 QT_END_NAMESPACE
index d7c44a4..2808ed6 100644 (file)
@@ -43,6 +43,8 @@
 
 #include "qwaylandbuffer.h"
 
+#include <QtCore/QVector>
+
 QWaylandShmWindow::QWaylandShmWindow(QWidget *widget)
     : QWaylandWindow(widget)
     , mBuffer(0)
index 669533c..3876c52 100644 (file)
@@ -43,6 +43,7 @@
 #define QWAYLANDSHMWINDOW_H
 
 #include "qwaylandwindow.h"
+#include <QtGui/QRegion>
 
 class QWaylandShmWindow : public QWaylandWindow
 {
index b44857b..f2d9d6b 100644 (file)
@@ -36,6 +36,7 @@ contains(QT_CONFIG, opengles2) {
     QT += opengl
 
     CONFIG += wayland_egl
+#    CONFIG += xpixmap_egl
     include ($$PWD/gl_integration/gl_integration.pri)
 }