Wayland: add GL drawing support
authorJesse Barnes <jbarnes@virtuousgeek.org>
Fri, 22 Oct 2010 17:31:03 +0000 (10:31 -0700)
committerJørgen Lind <jorgen.lind@nokia.com>
Tue, 25 Jan 2011 17:56:26 +0000 (18:56 +0100)
Works with analogclock, draws upside down, fails to resize, and doesn't
show GL widget with hello_es2.

src/plugins/platforms/wayland/qwaylandintegration.cpp
src/plugins/platforms/wayland/qwaylandintegration.h
src/plugins/platforms/wayland/qwaylandwindowsurface.cpp
src/plugins/platforms/wayland/qwaylandwindowsurface.h

index 248158d..c433983 100644 (file)
@@ -3,6 +3,7 @@
 #include <QImageReader>
 #include <QWindowSystemInterface>
 #include <QPlatformCursor>
+#include <QPaintEngine>
 
 #include <QtGui/QPlatformGLContext>
 #include <QtGui/QPlatformWindowFormat>
@@ -10,6 +11,9 @@
 #include <QtGui/private/qpixmap_raster_p.h>
 #include <QtGui/QPlatformWindow>
 
+#include <private/qwindowsurface_gl_p.h>
+#include <private/qpixmapdata_gl_p.h>
+
 #include "qwaylandintegration.h"
 #include "qwaylandwindowsurface.h"
 
@@ -405,9 +409,10 @@ QWaylandDisplay::~QWaylandDisplay(void)
     wl_display_destroy(mDisplay);
 }
 
-QWaylandIntegration::QWaylandIntegration()
+QWaylandIntegration::QWaylandIntegration(bool useOpenGL)
     : mFontDb(new QFontconfigDatabase())
     , mDisplay(new QWaylandDisplay())
+    , mUseOpenGL(useOpenGL)
 {
 }
 
@@ -419,6 +424,8 @@ QWaylandIntegration::screens() const
 
 QPixmapData *QWaylandIntegration::createPixmapData(QPixmapData::PixelType type) const
 {
+    if (mUseOpenGL)
+       return new QGLPixmapData(type);
     return new QRasterPixmapData(type);
 }
 
@@ -426,6 +433,7 @@ QWaylandWindow::QWaylandWindow(QWidget *window, QWaylandDisplay *display)
     : QPlatformWindow(window)
     , mSurface(0)
     , mDisplay(display)
+    , mGLContext(0)
 {
     static WId id = 1;
 
@@ -434,6 +442,8 @@ QWaylandWindow::QWaylandWindow(QWidget *window, QWaylandDisplay *display)
 
 QWaylandWindow::~QWaylandWindow()
 {
+    if (mGLContext)
+       delete mGLContext;
 }
 
 WId QWaylandWindow::winId() const
@@ -508,6 +518,7 @@ QWaylandGLContext::QWaylandGLContext(QWaylandDisplay *wd, const QPlatformWindowF
     eglDisplay = mDisplay->eglDisplay();
     mContext = eglCreateContext(eglDisplay, NULL,
                                EGL_NO_CONTEXT, contextAttribs);
+    eglMakeCurrent(eglDisplay, NULL, NULL, mContext);
 }
 
 QWaylandGLContext::~QWaylandGLContext()
@@ -518,10 +529,12 @@ QWaylandGLContext::~QWaylandGLContext()
 
 void QWaylandGLContext::makeCurrent()
 {
+    eglMakeCurrent(mDisplay->eglDisplay(), 0, 0, mContext);
 }
 
 void QWaylandGLContext::doneCurrent()
 {
+    eglMakeCurrent(mDisplay->eglDisplay(), 0, 0, mContext);
 }
 
 void QWaylandGLContext::swapBuffers()
@@ -554,6 +567,8 @@ QWindowSurface *QWaylandIntegration::createWindowSurface(QWidget *widget, WId wi
     Q_UNUSED(winId);
     Q_UNUSED(winId);
 
+    if (mUseOpenGL)
+       return new QWaylandDrmWindowSurface(widget, mDisplay);
     return new QWaylandShmWindowSurface(widget, mDisplay);
 }
 
index 6267e9b..70fb538 100644 (file)
@@ -46,6 +46,7 @@
 #include <QObject>
 #include <QtGui/QPlatformIntegration>
 #include <QtGui/QPlatformScreen>
+#include "qgl.h"
 
 #include <wayland-client.h>
 #include "qwaylandinputdevice.h"
@@ -155,6 +156,7 @@ public:
     WId winId() const;
     QPlatformGLContext *glContext() const;
     void attach(QWaylandBuffer *buffer);
+    QWaylandBuffer *getBuffer(void) { return mBuffer; }
 
 private:
     struct wl_surface *mSurface;
@@ -168,7 +170,7 @@ private:
 class QWaylandIntegration : public QPlatformIntegration
 {
 public:
-    QWaylandIntegration();
+    QWaylandIntegration(bool useOpenGL = false);
 
     QPixmapData *createPixmapData(QPixmapData::PixelType type) const;
     QPlatformWindow *createPlatformWindow(QWidget *widget, WId winId) const;
@@ -181,6 +183,7 @@ public:
 private:
     QPlatformFontDatabase *mFontDb;
     QWaylandDisplay *mDisplay;
+    bool mUseOpenGL;
 };
 
 QT_END_NAMESPACE
index 0954bc5..78900ba 100644 (file)
 **
 ****************************************************************************/
 
-#include "qwaylandintegration.h"
-#include "qwaylandwindowsurface.h"
+#define GL_GLEXT_PROTOTYPES
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <QGLFramebufferObject>
 #include <QtCore/qdebug.h>
 #include <QtGui/private/qapplication_p.h>
+#include <QtOpenGL/private/qgl_p.h>
+#include <QtOpenGL/private/qglpaintdevice_p.h>
+
+#include "qwaylandintegration.h"
+#include "qwaylandwindowsurface.h"
 
 #include <wayland-client.h>
 #include <unistd.h>
 #include <errno.h>
 #include <sys/mman.h>
 
-#define GL_GLEXT_PROTOTYPES
-#define EGL_EGLEXT_PROTOTYPES
-#define MESA_EGL_NO_X11_HEADERS
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
 QT_BEGIN_NAMESPACE
 
 QWaylandShmBuffer::QWaylandShmBuffer(QWaylandDisplay *display,
@@ -147,35 +146,77 @@ void QWaylandShmWindowSurface::resize(const QSize &size)
     ww->attach(mBuffer);
 }
 
-
-class QWaylandDrmBuffer : public QWaylandBuffer {
+class QWaylandPaintDevice : public QGLPaintDevice
+{
 public:
-    QWaylandDrmBuffer(QWaylandDisplay *display,
-                      const QSize &size, QImage::Format format);
-    ~QWaylandDrmBuffer();
-    EGLImageKHR mImage;
-    GLuint mTexture;
+    QWaylandPaintDevice(QWaylandDisplay *display, QWidget *widget)
+       : QGLPaintDevice(), mDisplay(display), mWidget(widget)
+       {
+           QGLFormat format;
+           mContext = new QGLContext(format, widget);
+           mContext->create();
+           glGenFramebuffers(1, &mFbo);
+           glGenRenderbuffers(1, &mRbo);
+       }
+    ~QWaylandPaintDevice()
+       {
+           glDeleteFramebuffers(1, &mFbo);
+           glDeleteRenderbuffers(1, &mRbo);
+       }
+
+    QSize size() const { return mWidget->size(); }
+    QGLContext *context() const { return mContext; }
+    QPaintEngine *paintEngine() const { return qt_qgl_paint_engine(); }
+
+    void beginPaint();
+    void endPaint();
+private:
     QWaylandDisplay *mDisplay;
+    QWidget *mWidget;
+    QGLContext *mContext;
+    GLuint mFbo, mRbo;
 };
 
-class QWaylandDrmWindowSurface : public QWindowSurface
+void QWaylandPaintDevice::beginPaint(void)
 {
-public:
-    QWaylandDrmWindowSurface(QWidget *window, QWaylandDisplay *display);
-    ~QWaylandDrmWindowSurface();
+    QWaylandWindow *mWindow = (QWaylandWindow *)mWidget->platformWindow();
+    QWaylandDrmBuffer *mBuffer = (QWaylandDrmBuffer *)mWindow->getBuffer();
+    QPlatformGLContext *ctx = mWindow->glContext();
+    QRect geometry = mWidget->geometry();
 
-    QPaintDevice *paintDevice();
-    void flush(QWidget *widget, const QRegion &region, const QPoint &offset);
-    void resize(const QSize &size);
+    QGLPaintDevice::beginPaint();
 
-private:
-    QWaylandDrmBuffer *mBuffer;
-    QWaylandDisplay *mDisplay;
-};
+    ctx->makeCurrent();
 
+    glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
+    glBindRenderbuffer(GL_RENDERBUFFER, mRbo);
+    glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, mBuffer->mImage);
+    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                                GL_RENDERBUFFER, mRbo);
+}
+
+void QWaylandPaintDevice::endPaint(void)
+{
+    QWaylandWindow *mWindow = (QWaylandWindow *)mWidget->platformWindow();
+    QPlatformGLContext *ctx = mWindow->glContext();
+    QRect geometry = mWidget->geometry();
+
+    wl_surface_damage(mWindow->surface(), 0, 0,
+                     geometry.width(), geometry.height());
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+    glBindRenderbuffer(GL_RENDERBUFFER, 0);
+    ctx->doneCurrent();
+
+    QGLPaintDevice::endPaint();
+}
+
+/*
+ * Shared DRM surface for GL based drawing
+ */
 QWaylandDrmBuffer::QWaylandDrmBuffer(QWaylandDisplay *display,
                                     const QSize &size, QImage::Format format)
     : mDisplay(display)
+    , mSize(size)
 {
     Q_UNUSED(format);
 
@@ -216,23 +257,62 @@ QWaylandDrmWindowSurface::QWaylandDrmWindowSurface(QWidget *window,
     , mBuffer(0)
     , mDisplay(display)
 {
+    mPaintDevice = new QWaylandPaintDevice(display, window);
 }
 
 QWaylandDrmWindowSurface::~QWaylandDrmWindowSurface()
 {
+    delete mPaintDevice;
 }
 
 QPaintDevice *QWaylandDrmWindowSurface::paintDevice()
 {
-    return NULL;
+    return mPaintDevice;
 }
 
 void QWaylandDrmWindowSurface::flush(QWidget *widget, const QRegion &region, const QPoint &offset)
 {
+    Q_UNUSED(region);
+    Q_UNUSED(offset);
+    Q_UNUSED(widget);
+#if 0
+    GLuint surf_rbo, surf_fbo;
+    QWaylandWindow *mWindow = (QWaylandWindow *)widget->platformWindow();
+    QPlatformGLContext *ctx = mWindow->glContext();
+    QRect geometry = widget->geometry();
+
+    ctx->makeCurrent();
+
+    glGenFramebuffers(1, &surf_fbo);
+    glBindFramebuffer(GL_FRAMEBUFFER, surf_fbo);
+    glGenRenderbuffers(1, &surf_rbo);
+    glBindRenderbuffer(GL_RENDERBUFFER, surf_rbo);
+    glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, mBuffer->mImage);
+    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                                GL_RENDERBUFFER, surf_rbo);
+
+    wl_surface_damage(mWindow->surface(), 0, 0,
+                     geometry.width(), geometry.height());
+
+    ctx->doneCurrent();
+#endif
 }
 
 void QWaylandDrmWindowSurface::resize(const QSize &size)
 {
+    QWaylandWindow *ww = (QWaylandWindow *) window()->platformWindow();
+    QWindowSurface::resize(size);
+    QImage::Format format = QApplicationPrivate::platformIntegration()->screens().first()->format();
+
+    if (mBuffer != NULL && mBuffer->mSize == size)
+       return;
+
+    if (mBuffer != NULL)
+       delete mBuffer;
+
+    mBuffer = new QWaylandDrmBuffer(mDisplay, size, format);
+
+    ww->attach(mBuffer);
 }
 
 QT_END_NAMESPACE
index 2246db6..a033531 100644 (file)
 #ifndef QWINDOWSURFACE_WAYLAND_H
 #define QWINDOWSURFACE_WAYLAND_H
 
+#include <QGLFramebufferObject>
 #include <QtGui/private/qwindowsurface_p.h>
 
 #include <QtGui/QPlatformWindow>
 
+#define MESA_EGL_NO_X11_HEADERS
+#define EGL_EGLEXT_PROTOTYPES
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <QtOpenGL/qgl.h>
+
 QT_BEGIN_NAMESPACE
 
 class QWaylandDisplay;
@@ -80,6 +88,35 @@ private:
     QWaylandDisplay *mDisplay;
 };
 
+class QWaylandDrmBuffer : public QWaylandBuffer {
+public:
+    QWaylandDrmBuffer(QWaylandDisplay *display,
+                      const QSize &size, QImage::Format format);
+    ~QWaylandDrmBuffer();
+    EGLImageKHR mImage;
+    GLuint mTexture;
+    QWaylandDisplay *mDisplay;
+    QGLFramebufferObject *pdev;
+    QSize mSize;
+};
+
+class QWaylandDrmWindowSurface : public QWindowSurface
+{
+public:
+    QWaylandDrmWindowSurface(QWidget *window, QWaylandDisplay *display);
+    ~QWaylandDrmWindowSurface();
+
+    QPaintDevice *paintDevice();
+    void flush(QWidget *widget, const QRegion &region, const QPoint &offset);
+    void resize(const QSize &size);
+
+private:
+    QWaylandDrmBuffer *mBuffer;
+    QWaylandDisplay *mDisplay;
+    QPaintDevice *mPaintDevice;
+};
+
+
 QT_END_NAMESPACE
 
 #endif