summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2010-06-17 23:20:34 -0700
committerJesse Barnes <jbarnes@virtuousgeek.org>2010-06-17 23:20:34 -0700
commita6cd1146c4144f8fa85174b97db70678af0ab939 (patch)
treec553c9c26f06fb7dc76aeb11c503322cba187d1d
parent744d2a603f1fd58270b5b0bd07208611c91ce9da (diff)
Window surface for Wayland
-rw-r--r--src/gui/kernel/qwidget.h3
-rw-r--r--src/opengl/qgl.h3
-rw-r--r--src/opengl/qglpixelbuffer.h3
-rw-r--r--src/opengl/qgraphicssystem_gl.cpp2
-rw-r--r--src/opengl/qwindowsurface_waylandgl.cpp609
-rw-r--r--src/opengl/qwindowsurface_waylandgl_p.h36
6 files changed, 618 insertions, 38 deletions
diff --git a/src/gui/kernel/qwidget.h b/src/gui/kernel/qwidget.h
index 941bd68929..7a65262472 100644
--- a/src/gui/kernel/qwidget.h
+++ b/src/gui/kernel/qwidget.h
@@ -735,6 +735,9 @@ private:
friend class QGLContext;
friend class QGLWidget;
friend class QGLWindowSurface;
+#ifdef Q_WS_WAYLAND
+ friend class QWaylandWindowSurface;
+#endif
friend class QX11PaintEngine;
friend class QWin32PaintEngine;
friend class QShortcutPrivate;
diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h
index f0b36f75ea..c700d78be3 100644
--- a/src/opengl/qgl.h
+++ b/src/opengl/qgl.h
@@ -414,6 +414,9 @@ private:
friend class QGL2PaintEngineExPrivate;
friend class QGLEngineShaderManager;
friend class QGLWindowSurface;
+#ifdef Q_WS_WAYLAND
+ friend class QWaylandWindowSurface;
+#endif
friend class QGLPixmapData;
friend class QGLPixmapFilterBase;
friend class QGLTextureGlyphCache;
diff --git a/src/opengl/qglpixelbuffer.h b/src/opengl/qglpixelbuffer.h
index d9c7e3e5ef..0490e6be2a 100644
--- a/src/opengl/qglpixelbuffer.h
+++ b/src/opengl/qglpixelbuffer.h
@@ -111,6 +111,9 @@ private:
friend class QGLDrawable;
friend class QGLWindowSurface;
friend class QGLPaintDevice;
+#ifdef Q_WS_WAYLAND
+ friend class QWaylandWindowSurface;
+#endif
friend class QGLPBufferGLPaintDevice;
friend class QGLContextPrivate;
};
diff --git a/src/opengl/qgraphicssystem_gl.cpp b/src/opengl/qgraphicssystem_gl.cpp
index afbaa7abab..cff8400823 100644
--- a/src/opengl/qgraphicssystem_gl.cpp
+++ b/src/opengl/qgraphicssystem_gl.cpp
@@ -91,7 +91,7 @@ QWindowSurface *QGLGraphicsSystem::createWindowSurface(QWidget *widget) const
#endif
#ifdef Q_WS_WAYLAND
-// return new QWaylandWindowSurface(widget);
+ return new QWaylandWindowSurface(widget);
#endif
return new QGLWindowSurface(widget);
diff --git a/src/opengl/qwindowsurface_waylandgl.cpp b/src/opengl/qwindowsurface_waylandgl.cpp
index 1fcb457b50..09d5ac8817 100644
--- a/src/opengl/qwindowsurface_waylandgl.cpp
+++ b/src/opengl/qwindowsurface_waylandgl.cpp
@@ -41,80 +41,629 @@
#include <private/qimagepixmapcleanuphooks_p.h>
+#include <qglframebufferobject.h>
+#include <qglpixelbuffer.h>
+#include <qcolormap.h>
+#include <qdesktopwidget.h>
+#include <private/qwidget_p.h>
+#include "qdebug.h"
+
+#include <private/qglextensions_p.h>
+#include <private/qwindowsurface_gl_p.h>
+
+#include <private/qgl_p.h>
+
+#include <private/qglpixelbuffer_p.h>
+#include <private/qgraphicssystem_gl_p.h>
+
+#include <private/qpaintengineex_opengl2_p.h>
+#include <private/qpixmapdata_gl_p.h>
+
#include "qwindowsurface_waylandgl_p.h"
#include "qpixmapdata_waylandgl_p.h"
QT_BEGIN_NAMESPACE
+class QWaylandGlobalShareWidget
+{
+public:
+ QWaylandGlobalShareWidget() : widget(0), initializing(false) {}
+
+ QGLWidget *shareWidget() {
+ if (!initializing && !widget && !cleanedUp) {
+ initializing = true;
+ widget = new QGLWidget;
+ // We dont need this internal widget to appear in QApplication::topLevelWidgets()
+ if (QWidgetPrivate::allWidgets)
+ QWidgetPrivate::allWidgets->remove(widget);
+ initializing = false;
+ }
+ return widget;
+ }
+
+ void cleanup() {
+ QGLWidget *w = widget;
+ cleanedUp = true;
+ widget = 0;
+ delete w;
+ }
+
+ static bool cleanedUp;
+
+private:
+ QGLWidget *widget;
+ bool initializing;
+};
+
+bool QWaylandGlobalShareWidget::cleanedUp = false;
+
+static void qt_cleanup_gl_share_widget();
+Q_GLOBAL_STATIC_WITH_INITIALIZER(QWaylandGlobalShareWidget, _qt_wayland_gl_share_widget,
+ {
+ qAddPostRoutine(qt_cleanup_gl_share_widget);
+ })
+
+static void qt_cleanup_gl_share_widget()
+{
+ _qt_wayland_gl_share_widget()->cleanup();
+}
+
+QGLWidget* qt_wayland_gl_share_widget()
+{
+ if (QWaylandGlobalShareWidget::cleanedUp)
+ return 0;
+ return _qt_wayland_gl_share_widget()->shareWidget();
+}
+
+struct QWaylandWindowSurfacePrivate
+{
+ EGLImageKHR eglImage;
+ QGLFramebufferObject *fbo;
+ QGLPixelBuffer *pb;
+ GLuint tex_id;
+ GLuint pb_tex_id;
+
+ int geometry_updated : 1;
+
+ QGLContext *ctx;
+
+ QList<QGLContext **> contexts;
+
+ QRegion paintedRegion;
+ QSize size;
+
+ QList<QImage> buffers;
+ QWaylandWindowSurfaceGLPaintDevice glDevice;
+ QWaylandWindowSurface* q_ptr;
+};
+
+QGLFormat QWaylandWindowSurface::surfaceFormat;
+
+void QWaylandWindowSurfaceGLPaintDevice::endPaint()
+{
+ glFlush();
+ QGLPaintDevice::endPaint();
+}
+
+QSize QWaylandWindowSurfaceGLPaintDevice::size() const
+{
+ return d->size;
+}
+
+QGLContext* QWaylandWindowSurfaceGLPaintDevice::context() const
+{
+ return d->ctx;
+}
+
+
+int QWaylandWindowSurfaceGLPaintDevice::metric(PaintDeviceMetric m) const
+{
+ return qt_paint_device_metric(d->q_ptr->window(), m);
+}
+
+QPaintEngine *QWaylandWindowSurfaceGLPaintDevice::paintEngine() const
+{
+ return qt_qgl_paint_engine();
+}
+
QWaylandWindowSurface::QWaylandWindowSurface(QWidget* window)
- : QWindowSurface(window), m_window(window)
+ : QWindowSurface(window), d_ptr(new QWaylandWindowSurfacePrivate)
{
+ Q_ASSERT(window->isTopLevel());
+
+ d_ptr->pb = 0;
+ d_ptr->fbo = 0;
+ d_ptr->ctx = 0;
+
+ d_ptr->glDevice.d = d_ptr;
+ d_ptr->q_ptr = this;
+ d_ptr->geometry_updated = false;
}
QWaylandWindowSurface::~QWaylandWindowSurface()
{
+ if (d_ptr->ctx)
+ glDeleteTextures(1, &d_ptr->tex_id);
+ foreach(QGLContext **ctx, d_ptr->contexts) {
+ delete *ctx;
+ *ctx = 0;
+ }
+
+ delete d_ptr->pb;
+ delete d_ptr->fbo;
+ delete d_ptr;
+}
+
+void QWaylandWindowSurface::deleted(QObject *object)
+{
+ // Make sure that the fbo is destroyed before destroying its context.
+ delete d_ptr->fbo;
+ d_ptr->fbo = 0;
+
+ QWidget *widget = qobject_cast<QWidget *>(object);
+ if (widget) {
+ QWidgetPrivate *widgetPrivate = widget->d_func();
+ if (widgetPrivate->extraData()) {
+ union { QGLContext **ctxPtr; void **voidPtr; };
+ voidPtr = &widgetPrivate->extraData()->glContext;
+ int index = d_ptr->contexts.indexOf(ctxPtr);
+ if (index != -1) {
+ delete *ctxPtr;
+ *ctxPtr = 0;
+ d_ptr->contexts.removeAt(index);
+ }
+ }
+ }
+}
+
+void QWaylandWindowSurface::hijackWindow(QWidget *widget)
+{
+ QWidgetPrivate *widgetPrivate = widget->d_func();
+ widgetPrivate->createExtra();
+ if (widgetPrivate->extraData()->glContext)
+ return;
+
+ QGLContext *ctx = new QGLContext(surfaceFormat, widget);
+ ctx->create(qt_wayland_gl_share_widget()->context());
+
+#ifndef QT_NO_EGL
+ if (ctx->d_func()->eglContext->configAttrib(EGL_SWAP_BEHAVIOR) != EGL_BUFFER_PRESERVED)
+ setPartialUpdateSupport(false); // Force full-screen updates
+#endif
+
+ widgetPrivate->extraData()->glContext = ctx;
+
+ union { QGLContext **ctxPtr; void **voidPtr; };
+
+ connect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(deleted(QObject*)));
+
+ voidPtr = &widgetPrivate->extraData()->glContext;
+ d_ptr->contexts << ctxPtr;
+ qDebug() << "hijackWindow() context created for" << widget << d_ptr->contexts.size();
+}
+
+QGLContext *QWaylandWindowSurface::context() const
+{
+ return d_ptr->ctx;
}
QPaintDevice *QWaylandWindowSurface::paintDevice()
{
- return &m_backBuffer;
+ updateGeometry();
+
+ if (d_ptr->pb)
+ return d_ptr->pb;
+
+ if (d_ptr->ctx)
+ return &d_ptr->glDevice;
+
+ QGLContext *ctx = reinterpret_cast<QGLContext *>
+ (window()->d_func()->extraData()->glContext);
+ ctx->makeCurrent();
+ return d_ptr->fbo;
+}
+
+static void drawTexture(const QRectF &rect, GLuint tex_id, const QSize &texSize, const QRectF &src = QRectF());
+
+void QWaylandWindowSurface::beginPaint(const QRegion &)
+{
}
-void QWaylandWindowSurface::flush(QWidget *widget, const QRegion &widgetRegion,
+void QWaylandWindowSurface::endPaint(const QRegion &rgn)
+{
+ if (context())
+ d_ptr->paintedRegion |= rgn;
+
+ d_ptr->buffers.clear();
+}
+
+void QWaylandWindowSurface::flush(QWidget *widget, const QRegion &rgn,
const QPoint &offset)
{
- eglWaitNative(EGL_CORE_NATIVE_ENGINE);
+ if (context() && widget != window()) {
+ qWarning("No native child widget support in GL window surface without FBOs or pixel buffers");
+ return;
+ }
+
+ //### Find out why d_ptr->geometry_updated isn't always false.
+ // flush() should not be called when d_ptr->geometry_updated is true. It assumes that either
+ // d_ptr->fbo or d_ptr->pb is allocated and has the correct size.
+ if (d_ptr->geometry_updated)
+ return;
+
+ QWidget *parent = widget->internalWinId() ? widget : widget->nativeParentWidget();
+ Q_ASSERT(parent);
+
+ if (!geometry().isValid())
+ return;
+
+ // Needed to support native child-widgets...
+ hijackWindow(parent);
+
+ QRect br = rgn.boundingRect().translated(offset);
+ br = br.intersected(window()->rect());
+ QPoint wOffset = qt_qwidget_data(parent)->wrect.topLeft();
+ QRect rect = br.translated(-offset - wOffset);
+
+ const GLenum target = GL_TEXTURE_2D;
+ Q_UNUSED(target);
+
+ if (context()) {
+ context()->makeCurrent();
+
+ if (context()->format().doubleBuffer()) {
+ d_ptr->paintedRegion = QRegion();
+ context()->swapBuffers();
+ } else {
+ glFlush();
+ }
+
+ return;
+ }
+
+ QGLContext *previous_ctx = const_cast<QGLContext *>(QGLContext::currentContext());
+ QGLContext *ctx = reinterpret_cast<QGLContext *>(parent->d_func()->extraData()->glContext);
+
+ // QPainter::end() should have unbound the fbo, otherwise something is very wrong...
+ Q_ASSERT(!d_ptr->fbo || !d_ptr->fbo->isBound());
+
+ if (ctx != previous_ctx) {
+ ctx->makeCurrent();
+ }
+
+ QSize size = widget->rect().size();
+ if (ctx->format().doubleBuffer()) {
+ rect = parent->rect();
+ br = rect.translated(wOffset + offset);
+ size = parent->size();
+ }
+
+ glDisable(GL_SCISSOR_TEST);
+
+ if (d_ptr->fbo && (QGLExtensions::glExtensions() & QGLExtensions::FramebufferBlit)) {
+ const int h = d_ptr->fbo->height();
+
+ const int sx0 = br.left();
+ const int sx1 = br.left() + br.width();
+ const int sy0 = h - (br.top() + br.height());
+ const int sy1 = h - br.top();
+
+ const int tx0 = rect.left();
+ const int tx1 = rect.left() + rect.width();
+ const int ty0 = parent->height() - (rect.top() + rect.height());
+ const int ty1 = parent->height() - rect.top();
+
+ if (window() == parent || d_ptr->fbo->format().samples() <= 1) {
+ // glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, d_ptr->fbo->handle());
+
+ glBlitFramebufferEXT(sx0, sy0, sx1, sy1,
+ tx0, ty0, tx1, ty1,
+ GL_COLOR_BUFFER_BIT,
+ GL_NEAREST);
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0);
+ } else {
+ // can't do sub-region blits with multisample FBOs
+ QGLFramebufferObject *temp = qgl_fbo_pool()->acquire(d_ptr->fbo->size(), QGLFramebufferObjectFormat());
+
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, temp->handle());
+ glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, d_ptr->fbo->handle());
+
+ glBlitFramebufferEXT(0, 0, d_ptr->fbo->width(), d_ptr->fbo->height(),
+ 0, 0, d_ptr->fbo->width(), d_ptr->fbo->height(),
+ GL_COLOR_BUFFER_BIT,
+ GL_NEAREST);
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, temp->handle());
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0);
+
+ glBlitFramebufferEXT(sx0, sy0, sx1, sy1,
+ tx0, ty0, tx1, ty1,
+ GL_COLOR_BUFFER_BIT,
+ GL_NEAREST);
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0);
+
+ qgl_fbo_pool()->release(temp);
+ }
+ }
+#if !defined(QT_OPENGL_ES_2)
+ else {
+ GLuint texture;
+ if (d_ptr->fbo) {
+ texture = d_ptr->fbo->texture();
+ } else {
+ d_ptr->pb->makeCurrent();
+ glBindTexture(target, d_ptr->pb_tex_id);
+ const uint bottom = window()->height() - (br.y() + br.height());
+ glCopyTexSubImage2D(target, 0, br.x(), bottom, br.x(), bottom, br.width(), br.height());
+ texture = d_ptr->pb_tex_id;
+ glBindTexture(target, 0);
+ }
+
+ glDisable(GL_DEPTH_TEST);
+
+ if (d_ptr->fbo) {
+ d_ptr->fbo->release();
+ } else {
+ ctx->makeCurrent();
+ }
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+#ifndef QT_OPENGL_ES
+ glOrtho(0, size.width(), size.height(), 0, -999999, 999999);
+#else
+ glOrthof(0, size.width(), size.height(), 0, -999999, 999999);
+#endif
+ glViewport(0, 0, size.width(), size.height());
+
+ glColor4f(1, 1, 1, 1);
+ drawTexture(rect, texture, window()->size(), br);
+
+ if (d_ptr->fbo)
+ d_ptr->fbo->bind();
+ }
+#else
+ // OpenGL/ES 2.0 version of the fbo blit.
+ else if (d_ptr->fbo && 0) {
+ Q_UNUSED(target);
+
+ GLuint texture = d_ptr->fbo->texture();
+
+ glDisable(GL_DEPTH_TEST);
+
+ if (d_ptr->fbo->isBound())
+ d_ptr->fbo->release();
+
+ glViewport(0, 0, size.width(), size.height());
+
+ QGLShaderProgram *blitProgram =
+ QGLEngineSharedShaders::shadersForContext(ctx)->blitProgram();
+ blitProgram->bind();
+ blitProgram->setUniformValue("imageTexture", 0 /*QT_IMAGE_TEXTURE_UNIT*/);
+
+ // The shader manager's blit program does not multiply the
+ // vertices by the pmv matrix, so we need to do the effect
+ // of the orthographic projection here ourselves.
+ QRectF r;
+ qreal w = size.width() ? size.width() : 1.0f;
+ qreal h = size.height() ? size.height() : 1.0f;
+ r.setLeft((rect.left() / w) * 2.0f - 1.0f);
+ if (rect.right() == (size.width() - 1))
+ r.setRight(1.0f);
+ else
+ r.setRight((rect.right() / w) * 2.0f - 1.0f);
+ r.setBottom((rect.top() / h) * 2.0f - 1.0f);
+ if (rect.bottom() == (size.height() - 1))
+ r.setTop(1.0f);
+ else
+ r.setTop((rect.bottom() / w) * 2.0f - 1.0f);
+
+ drawTexture(r, texture, window()->size(), br);
+ }
+#endif
+
+ if (ctx->format().doubleBuffer())
+ ctx->swapBuffers();
+ else
+ glFlush();
}
void QWaylandWindowSurface::setGeometry(const QRect &rect)
{
- if (rect.width() > m_backBuffer.size().width() ||
- rect.height() > m_backBuffer.size().height()) {
- QWaylandGLPixmapData *pd = new QWaylandGLPixmapData;
- QSize newSize = rect.size();
- pd->resize(newSize.width(), newSize.height());
- m_backBuffer = QPixmap(pd);
- if (window()->testAttribute(Qt::WA_TranslucentBackground))
- m_backBuffer.fill(Qt::transparent);
- }
QWindowSurface::setGeometry(rect);
+ d_ptr->geometry_updated = true;
}
void QWaylandWindowSurface::updateGeometry()
{
+ if (!d_ptr->geometry_updated)
+ return;
+ d_ptr->geometry_updated = false;
+
+
+ QRect rect = geometry();
+ hijackWindow(window());
+ QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext);
+
+#ifdef Q_WS_MAC
+ ctx->updatePaintDevice();
+#endif
+
+ const GLenum target = GL_TEXTURE_2D;
+
+ if (rect.width() <= 0 || rect.height() <= 0)
+ return;
+
+ if (d_ptr->size == rect.size())
+ return;
+
+ d_ptr->size = rect.size();
+
+ if (d_ptr->ctx) {
+#ifndef QT_OPENGL_ES_2
+ if (d_ptr->destructive_swap_buffers) {
+ glBindTexture(target, d_ptr->tex_id);
+ glTexImage2D(target, 0, GL_RGBA, rect.width(), rect.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
+ glBindTexture(target, 0);
+ }
+#endif
+ return;
+ }
+
+ if ((QGLExtensions::glExtensions() & QGLExtensions::FramebufferObject)
+ && qt_gl_preferGL2Engine())
+ {
+ ctx->d_ptr->internal_context = true;
+ ctx->makeCurrent();
+ delete d_ptr->fbo;
+
+ QGLFramebufferObjectFormat format;
+ format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+ format.setInternalTextureFormat(GLenum(GL_RGBA));
+ format.setTextureTarget(target);
+
+ if (QGLExtensions::glExtensions() & QGLExtensions::FramebufferBlit)
+ format.setSamples(8);
+
+ d_ptr->fbo = new QGLFramebufferObject(rect.size(), format);
+
+ if (d_ptr->fbo->isValid()) {
+ qDebug() << "Created Window Surface FBO" << rect.size()
+ << "with samples" << d_ptr->fbo->format().samples();
+ return;
+ } else {
+ qDebug() << "QWaylandWindowSurface: Failed to create valid FBO, falling back";
+ delete d_ptr->fbo;
+ d_ptr->fbo = 0;
+ }
+ }
+
+ ctx->makeCurrent();
+
+ qDebug() << "QWaylandWindowSurface: Using plain widget as window surface" << this;;
+ d_ptr->ctx = ctx;
+ d_ptr->ctx->d_ptr->internal_context = true;
}
bool QWaylandWindowSurface::scroll(const QRegion &area, int dx, int dy)
{
- eglWaitNative(EGL_CORE_NATIVE_ENGINE);
+ // this code randomly fails currently for unknown reasons
+ return false;
+
+ if (!d_ptr->pb)
+ return false;
+
+ d_ptr->pb->makeCurrent();
+
+ QRect br = area.boundingRect();
+
+#if 0
+ // ## workaround driver issue (scrolling by these deltas is unbearably slow for some reason)
+ // ## maybe we should use glCopyTexSubImage insteadk
+ if (dx == 1 || dx == -1 || dy == 1 || dy == -1 || dy == 2)
+ return false;
+ glRasterPos2i(br.x() + dx, br.y() + br.height() + dy);
+ glCopyPixels(br.x(), d_ptr->pb->height() - (br.y() + br.height()), br.width(), br.height(), GL_COLOR);
return true;
-}
+#endif
-void QWaylandWindowSurface::beginPaint(const QRegion &region)
-{
+ const GLenum target = GL_TEXTURE_2D;
+
+ glBindTexture(target, d_ptr->tex_id);
+ glCopyTexImage2D(target, 0, GL_RGBA, br.x(), d_ptr->pb->height() - (br.y() + br.height()), br.width(), br.height(), 0);
+ glBindTexture(target, 0);
+
+ drawTexture(br.translated(dx, dy), d_ptr->tex_id, window()->size());
+
+ return true;
}
-void QWaylandWindowSurface::endPaint(const QRegion &region)
+static void drawTexture(const QRectF &rect, GLuint tex_id, const QSize &texSize, const QRectF &br)
{
-#if 0
- struct wl_visual *visual;
- EGLint name, stride;
-
- QEgl::eglExportDRMImageMESA(qWayland->egl_display, image, &name, NULL,
- &stride);
- visual = wl_display_get_premultiplied_argb_visual(qWayland->egl_display);
- wl_surface_attach(surface, name, width, height, stride, visual);
- wl_surface_map(surface, 0, 0, width, height);
+ const GLenum target = GL_TEXTURE_2D;
+ QRectF src = br.isEmpty()
+ ? QRectF(QPointF(), texSize)
+ : QRectF(QPointF(br.x(), texSize.height() - br.bottom()), br.size());
+
+ if (target == GL_TEXTURE_2D) {
+ qreal width = texSize.width();
+ qreal height = texSize.height();
+
+ src.setLeft(src.left() / width);
+ src.setRight(src.right() / width);
+ src.setTop(src.top() / height);
+ src.setBottom(src.bottom() / height);
+ }
+
+ const GLfloat tx1 = src.left();
+ const GLfloat tx2 = src.right();
+ const GLfloat ty1 = src.top();
+ const GLfloat ty2 = src.bottom();
+
+ GLfloat texCoordArray[4*2] = {
+ tx1, ty2, tx2, ty2, tx2, ty1, tx1, ty1
+ };
+
+ GLfloat vertexArray[4*2];
+ extern void qt_add_rect_to_array(const QRectF &r, GLfloat *array); // qpaintengine_opengl.cpp
+ qt_add_rect_to_array(rect, vertexArray);
+
+#if !defined(QT_OPENGL_ES_2)
+ glVertexPointer(2, GL_FLOAT, 0, vertexArray);
+ glTexCoordPointer(2, GL_FLOAT, 0, texCoordArray);
+
+ glBindTexture(target, tex_id);
+ glEnable(target);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ glDisable(target);
+ glBindTexture(target, 0);
+#else
+ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexArray);
+ glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, texCoordArray);
+
+ glBindTexture(target, tex_id);
+
+ glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
+
+ glBindTexture(target, 0);
#endif
}
QImage *QWaylandWindowSurface::buffer(const QWidget *widget)
{
-}
+ QImage image;
-QGLContext *QWaylandWindowSurface::context() const
-{
+ if (d_ptr->pb)
+ image = d_ptr->pb->toImage();
+ else if (d_ptr->fbo)
+ image = d_ptr->fbo->toImage();
+
+ if (image.isNull())
+ return 0;
+
+ QRect rect = widget->rect();
+ rect.translate(widget->mapTo(widget->window(), QPoint()));
+
+ QImage subImage = image.copy(rect);
+ d_ptr->buffers << subImage;
+ return &d_ptr->buffers.last();
}
QT_END_NAMESPACE
diff --git a/src/opengl/qwindowsurface_waylandgl_p.h b/src/opengl/qwindowsurface_waylandgl_p.h
index d287b7c9d8..4a6dbc924c 100644
--- a/src/opengl/qwindowsurface_waylandgl_p.h
+++ b/src/opengl/qwindowsurface_waylandgl_p.h
@@ -39,8 +39,8 @@
**
****************************************************************************/
-#ifndef QWINDOWSURFACE_X11GL_P_H
-#define QWINDOWSURFACE_X11GL_P_H
+#ifndef QWINDOWSURFACE_WAYLANDGL_P_H
+#define QWINDOWSURFACE_WAYLANDGL_P_H
//
// W A R N I N G
@@ -60,13 +60,30 @@
QT_BEGIN_NAMESPACE
-class QWaylandWindowSurface : public QWindowSurface
+class QPaintDevice;
+class QPoint;
+class QRegion;
+class QWidget;
+struct QWaylandWindowSurfacePrivate;
+
+class QWaylandWindowSurfaceGLPaintDevice : public QGLPaintDevice
{
public:
+ QPaintEngine* paintEngine() const;
+ void endPaint();
+ QSize size() const;
+ int metric(PaintDeviceMetric m) const;
+ QGLContext* context() const;
+ QWaylandWindowSurfacePrivate* d;
+};
+
+class QWaylandWindowSurface : public QObject, public QWindowSurface
+{
+ Q_OBJECT
+public:
QWaylandWindowSurface(QWidget* window);
virtual ~QWaylandWindowSurface();
- // Inherreted from QWindowSurface
QPaintDevice *paintDevice();
void flush(QWidget *widget, const QRegion &region, const QPoint &offset);
void setGeometry(const QRect &rect);
@@ -80,12 +97,17 @@ public:
QGLContext *context() const;
+ static QGLFormat surfaceFormat;
+private slots:
+ void deleted(QObject *object);
+
private:
- QWidget *m_window;
- QPixmap m_backBuffer;
+ void hijackWindow(QWidget *widget);
+
+ QWaylandWindowSurfacePrivate *d_ptr;
};
QT_END_NAMESPACE
-#endif // QWINDOWSURFACE_X11GL_P_H
+#endif // QWINDOWSURFACE_WAYLANDGL_P_H