summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
authorJørgen Lind <jorgen.lind@nokia.com>2012-01-04 08:33:28 +0100
committerJørgen Lind <jorgen.lind@nokia.com>2012-01-04 10:34:40 +0100
commitd5ea033df8cf0a2dec49fce639d84e7dd0a2fced (patch)
tree15d92a4990b612e73450d110a6cc820df8cdee2e /examples
parent62bba49c83849ca5904357de45c888f9fab3106a (diff)
Implement subsurfaces extension
This allows you to have subwindows in the compositor. We tried to experiment with composing subsurfaces client side, but the architecture did not feel very lean. This however, requires the compositor to compose each surface before drawing the surface. The example compositors render the subsurfaces into the wl_surfaces texture. This might not be a good idea. Change-Id: I6e186b62d7b490de7f4e6c6f22fcf6c1e0a70df3 Reviewed-by: Samuel Rødal <samuel.rodal@nokia.com>
Diffstat (limited to 'examples')
-rw-r--r--examples/qml-compositor/main.cpp43
-rw-r--r--examples/qml-compositor/qml-compositor.pro2
-rw-r--r--examples/qwidget-compositor/main.cpp190
-rw-r--r--examples/qwidget-compositor/qwidget-compositor.pro16
-rw-r--r--examples/qwidget-compositor/textureblitter.cpp118
-rw-r--r--examples/qwidget-compositor/textureblitter.h28
-rw-r--r--examples/qwindow-compositor/qwindow-compositor.pro16
-rw-r--r--examples/qwindow-compositor/qwindowcompositor.cpp98
-rw-r--r--examples/qwindow-compositor/qwindowcompositor.h14
-rw-r--r--examples/qwindow-compositor/surfacerenderer.cpp146
-rw-r--r--examples/qwindow-compositor/surfacerenderer.h29
-rw-r--r--examples/qwindow-compositor/textureblitter.cpp118
-rw-r--r--examples/qwindow-compositor/textureblitter.h26
13 files changed, 525 insertions, 319 deletions
diff --git a/examples/qml-compositor/main.cpp b/examples/qml-compositor/main.cpp
index fc6a4618e..466533b52 100644
--- a/examples/qml-compositor/main.cpp
+++ b/examples/qml-compositor/main.cpp
@@ -56,8 +56,10 @@ class QmlCompositor : public QQuickView, public WaylandCompositor
{
Q_OBJECT
public:
- QmlCompositor() : WaylandCompositor(this) {
- //setMouseTracking(true);
+ QmlCompositor()
+ : WaylandCompositor(this)
+ {
+ enableSubSurfaceExtension();
setSource(QUrl(QLatin1String("qrc:qml/QmlCompositor/main.qml")));
setResizeMode(QQuickView::SizeRootObjectToView);
winId();
@@ -78,27 +80,20 @@ public slots:
private slots:
void surfaceMapped() {
WaylandSurface *surface = qobject_cast<WaylandSurface *>(sender());
- surface->setGeometry(QRect(surface->geometry().topLeft(),size));
-
- if (m_windowMap.contains(surface)) {
- WaylandSurfaceItem *item = m_windowMap.value(surface);
- item->setWidth(size.width());
- item->setHeight(size.height());
- emit windowResized(QVariant::fromValue(static_cast<QQuickItem *>(item)));
- } else {
- WaylandSurfaceItem *item = new WaylandSurfaceItem(surface, rootObject());
- item->setTouchEventsEnabled(true);
- connect(surface, SIGNAL(destroyed(QObject *)), this, SLOT(surfaceDestroyed(QObject *)));
- emit windowAdded(QVariant::fromValue(static_cast<QQuickItem *>(item)));
- m_windowMap[surface] = item;
-
- item->takeFocus();
- }
+ WaylandSurfaceItem *item = surface->surfaceItem();
+ item->takeFocus();
+ emit windowAdded(QVariant::fromValue(static_cast<QQuickItem *>(item)));
+ }
+ void surfaceUnmapped() {
+ WaylandSurface *surface = qobject_cast<WaylandSurface *>(sender());
+ QQuickItem *item = surface->surfaceItem();
+ emit windowDestroyed(QVariant::fromValue(item));
}
void surfaceDestroyed(QObject *object) {
- WaylandSurfaceItem *item = m_windowMap.take(object);
- emit windowDestroyed(QVariant::fromValue(static_cast<QQuickItem *>(item)));
+ WaylandSurface *surface = static_cast<WaylandSurface *>(object);
+ QQuickItem *item = surface->surfaceItem();
+ emit windowDestroyed(QVariant::fromValue(item));
}
void frameSwappedSlot() {
@@ -107,11 +102,13 @@ private slots:
protected:
void surfaceCreated(WaylandSurface *surface) {
+ WaylandSurfaceItem *item = new WaylandSurfaceItem(surface, rootObject());
+ item->setTouchEventsEnabled(true);
+ connect(surface, SIGNAL(destroyed(QObject *)), this, SLOT(surfaceDestroyed(QObject *)));
+
connect(surface, SIGNAL(mapped()), this, SLOT(surfaceMapped()));
+ connect(surface,SIGNAL(unmapped()), this,SLOT(surfaceUnmapped()));
}
-
-private:
- QMap<QObject *, WaylandSurfaceItem *> m_windowMap;
};
int main(int argc, char *argv[])
diff --git a/examples/qml-compositor/qml-compositor.pro b/examples/qml-compositor/qml-compositor.pro
index 88c4ca021..1414cef3d 100644
--- a/examples/qml-compositor/qml-compositor.pro
+++ b/examples/qml-compositor/qml-compositor.pro
@@ -3,6 +3,8 @@ TARGET = qml-compositor
DEPENDPATH += .
INCLUDEPATH += .
+DEFINES += QT_COMPOSITOR_QUICK
+
# comment out the following to not use pkg-config in the pri files
CONFIG += use_pkgconfig
diff --git a/examples/qwidget-compositor/main.cpp b/examples/qwidget-compositor/main.cpp
index b074735b0..a95eda67f 100644
--- a/examples/qwidget-compositor/main.cpp
+++ b/examples/qwidget-compositor/main.cpp
@@ -47,32 +47,17 @@
#include <QTimer>
#include <QPainter>
#include <QMouseEvent>
+#include <QtCore/QLinkedList>
#ifdef QT_COMPOSITOR_WAYLAND_GL
#include <QOpenGLContext>
#include <QGLWidget>
+#include <QtGui/private/qopengltexturecache_p.h>
+#include "textureblitter.h"
#endif
#include <QDebug>
-//#include "qtouchscreen.h"
-//
-//static int touch_x_min, touch_x_max, touch_y_min, touch_y_max;
-//
-//class QWidgetCompositor;
-//
-//class TouchObserver : public QTouchScreenObserver
-//{
-//public:
-// TouchObserver(QWidgetCompositor *compositor)
-// : m_compositor(compositor) { }
-// void touch_configure(int x_min, int x_max, int y_min, int y_max);
-// void touch_point(QEvent::Type state, const QList<QWindowSystemInterface::TouchPoint> &points);
-//
-//private:
-// QWidgetCompositor *m_compositor;
-//};
-
#ifdef QT_COMPOSITOR_WAYLAND_GL
class QWidgetCompositor : public QGLWidget, public WaylandCompositor
#else
@@ -85,18 +70,19 @@ public:
: WaylandCompositor(windowHandle())
, m_moveSurface(0)
, m_dragSourceSurface(0)
+#ifdef QT_COMPOSITOR_WAYLAND_GL
+ , m_surfaceCompositorFbo(0)
+ , m_textureBlitter(0)
+ , m_textureCache(0)
+#endif
{
+ enableSubSurfaceExtension();
setMouseTracking(true);
setRetainedSelectionEnabled(true);
m_background = QImage(QLatin1String("background.jpg"));
//make sure we get the window id and create the glcontext
//so that clients can successfully initialize egl
winId();
-#ifdef QT_COMPOSITOR_WAYLAND_GL
- if (windowHandle()) {
-// windowHandle()->surfaceHandle();
- }
-#endif
}
private slots:
@@ -115,9 +101,8 @@ private slots:
pos = QPoint(px, py);
surface->setGeometry(QRect(pos, surface->geometry().size()));
m_surfaces.append(surface);
- } else {
- surface->setGeometry(QRect(geometry().topLeft(),size));
}
+
setInputFocus(surface);
update();
}
@@ -140,29 +125,113 @@ protected:
}
void surfaceCreated(WaylandSurface *surface) {
- qDebug() << "surface created";
connect(surface, SIGNAL(destroyed(QObject *)), this, SLOT(surfaceDestroyed(QObject *)));
connect(surface, SIGNAL(mapped()), this, SLOT(surfaceMapped()));
connect(surface, SIGNAL(damaged(const QRect &)), this, SLOT(surfaceDamaged(const QRect &)));
update();
}
+#ifdef QT_COMPOSITOR_WAYLAND_GL
+ GLuint composeSurface(WaylandSurface *surface) {
+ GLuint texture = 0;
+
+ if (!m_surfaceCompositorFbo) {
+ glGenFramebuffers(1,&m_surfaceCompositorFbo);
+ }
+ glBindFramebuffer(GL_FRAMEBUFFER, m_surfaceCompositorFbo);
+
+ if (surface->type() == WaylandSurface::Shm) {
+ texture = m_textureCache->bindTexture(context()->contextHandle(), surface->image());
+ } else {
+ texture = surface->texture(QOpenGLContext::currentContext());
+ }
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D, texture, 0);
+ paintChildren(surface,surface);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D, 0, 0);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ return texture;
+ }
+
+ void paintChildren(WaylandSurface *surface, WaylandSurface *window) {
+
+ if (surface->subSurfaces().size() == 0)
+ return;
+
+ QLinkedListIterator<WaylandSurface *> i(surface->subSurfaces());
+ while (i.hasNext()) {
+ WaylandSurface *subSurface = i.next();
+ QPoint p = subSurface->mapTo(window,QPoint(0,0));
+ QRect geo = subSurface->geometry();
+ geo.moveTo(p);
+ if (geo.isValid()) {
+ GLuint texture = 0;
+ if (subSurface->type() == WaylandSurface::Texture) {
+ texture = subSurface->texture(QOpenGLContext::currentContext());
+ } else if (surface->type() == WaylandSurface::Shm ) {
+ texture = m_textureCache->bindTexture(context()->contextHandle(), surface->image());
+ }
+ m_textureBlitter->drawTexture(texture,geo,window->geometry().size(),0,window->isYInverted(),subSurface->isYInverted());
+ }
+ paintChildren(subSurface,window);
+ }
+ }
+#else //hmmm, this is actually untested :(
+ QImage composeSurface(WaylandSurface *surface)
+ {
+ Q_ASSER(surface->type() == WaylandSurface::Shm);
+ QImage img = surface->image();
+ QPainter p(&img);
+ paintChildren(surface,p,surface);
+
+ return img;
+ }
+
+ void paintChildren(WaylandSurface *surface, QPainter *painter, WaylandSurface *window) {
+ if (surface->subSurfaces().size() == 0)
+ return;
+
+ QLinkedListIterator<WaylandSurface *> i(surface->subSurfaces());
+ while (i.hasNext()) {
+ WaylandSurface *subSurface = i.next();
+ QPoint p = subSurface->mapTo(window,QPoint(0,0));
+ QRect geo = subSurface->geometry();
+ geo.moveTo(p);
+ if (geo.isValid()) {
+ painter->drawImage(p,subSurface->image());
+ }
+ paintChildren(subSurface,painter,window);
+ }
+ }
+#endif //QT_COMPOSITOR_WAYLAND_GL
+
+
+
void paintEvent(QPaintEvent *) {
QPainter p(this);
if (!m_background.isNull())
p.drawPixmap(rect(), m_backgroundScaled);
+#ifdef QT_COMPOSITOR_WAYLAND_GL
+ if (!m_textureCache) {
+ m_textureCache = new QOpenGLTextureCache(context()->contextHandle());
+ }
+ if (!m_textureBlitter) {
+ m_textureBlitter = new TextureBlitter();
+ }
+ m_textureBlitter->bind();
+#endif
for (int i = 0; i < m_surfaces.size(); ++i) {
- if (m_surfaces.at(i)->type() == WaylandSurface::Texture) {
#ifdef QT_COMPOSITOR_WAYLAND_GL
- drawTexture(m_surfaces.at(i)->geometry(), m_surfaces.at(i)->texture(QOpenGLContext::currentContext()));
- break;
+ GLuint texture = composeSurface(m_surfaces.at(i));
+ m_textureBlitter->drawTexture(texture,m_surfaces.at(i)->geometry(),size(),0,false,m_surfaces.at(i)->isYInverted());
+#else
+ QImage img = composeSurface(m_surfaces.at(i));
+ p.drawImage(m_surfaces.at(i)->geometry().topLeft(),img);
#endif //QT_COMPOSITOR_WAYLAND_GL
- } else if (m_surfaces.at(i)->type() == WaylandSurface::Shm) {
- QImage img = m_surfaces.at(i)->image();
- p.drawImage(m_surfaces.at(i)->geometry(), img);
- }
}
if (!m_cursor.isNull())
@@ -173,7 +242,7 @@ protected:
#ifdef QT_COMPOSITOR_WAYLAND_GL
//jl:FIX FIX FIX:)
// update();
- glFinish();
+ m_textureBlitter->release();
#endif
}
@@ -293,6 +362,12 @@ private:
QList<WaylandSurface *> m_surfaces;
+#ifdef QT_COMPOSITOR_WAYLAND_GL
+ GLuint m_surfaceCompositorFbo;
+ TextureBlitter *m_textureBlitter;
+ QOpenGLTextureCache *m_textureCache;
+#endif
+
WaylandSurface *m_moveSurface;
QPoint m_moveOffset;
WaylandSurface *m_dragSourceSurface;
@@ -305,53 +380,6 @@ private:
friend class TouchObserver;
};
-//void TouchObserver::touch_configure(int x_min, int x_max, int y_min, int y_max)
-//{
-// touch_x_min = x_min;
-// touch_x_max = x_max;
-// touch_y_min = y_min;
-// touch_y_max = y_max;
-//}
-
-//void TouchObserver::touch_point(QEvent::Type state, const QList<QWindowSystemInterface::TouchPoint> &points)
-//{
-// Q_UNUSED(state);
-// WaylandSurface *focusSurface = m_compositor->inputFocus();
-// if (focusSurface) {
-// if (points.isEmpty())
-// return;
-// for (int i = 0; i < points.count(); ++i) {
-// const QWindowSystemInterface::TouchPoint &point(points.at(i));
-
-// // These are hw coordinates.
-// int x = int(point.area.left());
-// int y = int(point.area.top());
-
-// // Wayland expects surface-relative coordinates.
-
-// // Translate so that (0, 0) is the top-left corner.
-// x = qBound(touch_x_min, x, touch_x_max) - touch_x_min;
-// y = qBound(touch_y_min, y, touch_y_max) - touch_y_min;
-
-// // Get a normalized position in range 0..1.
-// const int hw_w = touch_x_max - touch_x_min;
-// const int hw_h = touch_y_max - touch_y_min;
-// const qreal nx = x / qreal(hw_w);
-// const qreal ny = y / qreal(hw_h);
-
-// // Map to surface.
-// QRect winRect(focusSurface->geometry());
-// x = int(nx * winRect.width());
-// y = int(ny * winRect.height());
-
-// focusSurface->sendTouchPointEvent(point.id,
-// x, y,
-// point.state);
-// }
-// focusSurface->sendTouchFrameEvent();
-// }
-//}
-
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
diff --git a/examples/qwidget-compositor/qwidget-compositor.pro b/examples/qwidget-compositor/qwidget-compositor.pro
index 56379891e..b681fb88b 100644
--- a/examples/qwidget-compositor/qwidget-compositor.pro
+++ b/examples/qwidget-compositor/qwidget-compositor.pro
@@ -11,8 +11,6 @@ CONFIG += use_pkgconfig
# the following line
#include (../../src/qt-compositor/qt-compositor.pri)
-# Input
-SOURCES += main.cpp
CONFIG += qt warn_on debug create_prl link_prl
OBJECTS_DIR = .obj/release-shared
@@ -25,13 +23,15 @@ isEmpty(QT_SOURCE_TREE) {
QTBASE = $$QT_SOURCE_TREE
}
-#TOUCHSCREEN_BASE = $$QTBASE/src/plugins/generic/touchscreen
-#SOURCES += $$TOUCHSCREEN_BASE/qtouchscreen.cpp
-#HEADERS += $$TOUCHSCREEN_BASE/qtouchscreen.h
-#INCLUDEPATH += $$TOUCHSCREEN_BASE
-#LIBS += -ludev -lmtdev
+# Input
+HEADERS += \
+ textureblitter.h
+
+SOURCES += \
+ main.cpp \
+ textureblitter.cpp
-QT += gui-private widgets widgets-private opengl opengl-private compositor
+QT += core-private gui-private widgets widgets-private opengl opengl-private compositor
# install
target.path = $$[QT_INSTALL_EXAMPLES]/qtwayland/qwidget-compositor
diff --git a/examples/qwidget-compositor/textureblitter.cpp b/examples/qwidget-compositor/textureblitter.cpp
new file mode 100644
index 000000000..8fefe48f6
--- /dev/null
+++ b/examples/qwidget-compositor/textureblitter.cpp
@@ -0,0 +1,118 @@
+#include "textureblitter.h"
+
+#include <QtGui/QOpenGLShaderProgram>
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLFunctions>
+
+TextureBlitter::TextureBlitter()
+ : m_shaderProgram(new QOpenGLShaderProgram())
+{
+ static const char *textureVertexProgram =
+ "uniform highp mat4 matrix;\n"
+ "attribute highp vec3 vertexCoordEntry;\n"
+ "attribute highp vec2 textureCoordEntry;\n"
+ "varying highp vec2 textureCoord;\n"
+ "void main() {\n"
+ " textureCoord = textureCoordEntry;\n"
+ " gl_Position = matrix * vec4(vertexCoordEntry, 1);\n"
+ "}\n";
+
+ static const char *textureFragmentProgram =
+ "uniform sampler2D texture;\n"
+ "varying highp vec2 textureCoord;\n"
+ "void main() {\n"
+ " gl_FragColor = texture2D(texture, textureCoord);\n"
+ "}\n";
+
+ //Enable transparent windows
+ glEnable(GL_BLEND);
+ glBlendFunc (GL_ONE,GL_ONE_MINUS_SRC_ALPHA);
+
+ m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram);
+ m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgram);
+ m_shaderProgram->link();
+}
+
+
+void TextureBlitter::bind()
+{
+
+ m_shaderProgram->bind();
+
+ m_vertexCoordEntry = m_shaderProgram->attributeLocation("vertexCoordEntry");
+ m_textureCoordEntry = m_shaderProgram->attributeLocation("textureCoordEntry");
+ m_matrixLocation = m_shaderProgram->uniformLocation("matrix");
+}
+
+void TextureBlitter::release()
+{
+ m_shaderProgram->release();
+}
+
+void TextureBlitter::drawTexture(int textureId, const QRectF &targetRect, const QSize &targetSize, int depth, bool targethasInvertedY, bool sourceHasInvertedY)
+{
+
+ glViewport(0,0,targetSize.width(),targetSize.height());
+ GLfloat zValue = depth / 1000.0f;
+ //Set Texture and Vertex coordinates
+ const GLfloat textureCoordinates[] = {
+ 0, 0,
+ 1, 0,
+ 1, 1,
+ 0, 1
+ };
+
+ int x1 = targetRect.left();
+ int x2 = targetRect.right();
+ int y1, y2;
+ if (targethasInvertedY) {
+ if (sourceHasInvertedY) {
+ y1 = targetRect.top();
+ y2 = targetRect.bottom();
+ } else {
+ y1 = targetRect.bottom();
+ y2 = targetRect.top();
+ }
+ } else {
+ if (sourceHasInvertedY) {
+ y1 = targetSize.height() - targetRect.top();
+ y2 = targetSize.height() - targetRect.bottom();
+ } else {
+ y1 = targetSize.height() - targetRect.bottom();
+ y2 = targetSize.height() - targetRect.top();
+ }
+ }
+
+ const GLfloat vertexCoordinates[] = {
+ x1, y1, zValue,
+ x2, y1, zValue,
+ x2, y2, zValue,
+ x1, y2, zValue
+ };
+
+ //Set matrix to transfrom geometry values into gl coordinate space.
+ m_transformMatrix.setToIdentity();
+ m_transformMatrix.scale( 2.0f / targetSize.width(), 2.0f / targetSize.height() );
+ m_transformMatrix.translate(-targetSize.width() / 2.0f, -targetSize.height() / 2.0f);
+
+ //attach the data!
+ QOpenGLContext *currentContext = QOpenGLContext::currentContext();
+ currentContext->functions()->glEnableVertexAttribArray(m_vertexCoordEntry);
+ currentContext->functions()->glEnableVertexAttribArray(m_textureCoordEntry);
+
+ currentContext->functions()->glVertexAttribPointer(m_vertexCoordEntry, 3, GL_FLOAT, GL_FALSE, 0, vertexCoordinates);
+ currentContext->functions()->glVertexAttribPointer(m_textureCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinates);
+ m_shaderProgram->setUniformValue(m_matrixLocation, m_transformMatrix);
+
+ glBindTexture(GL_TEXTURE_2D, textureId);
+
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ currentContext->functions()->glDisableVertexAttribArray(m_vertexCoordEntry);
+ currentContext->functions()->glDisableVertexAttribArray(m_textureCoordEntry);
+}
diff --git a/examples/qwidget-compositor/textureblitter.h b/examples/qwidget-compositor/textureblitter.h
new file mode 100644
index 000000000..35d5cffc0
--- /dev/null
+++ b/examples/qwidget-compositor/textureblitter.h
@@ -0,0 +1,28 @@
+#ifndef TEXTUREBLITTER_H
+#define TEXTUREBLITTER_H
+
+#include <QtGui/QMatrix4x4>
+
+#include <QtGui/qopengl.h>
+
+class QOpenGLShaderProgram;
+class TextureBlitter
+{
+public:
+ TextureBlitter();
+ void bind();
+ void release();
+ void drawTexture(int textureId, const QRectF &sourceGeometry,
+ const QSize &targetRect, int depth,
+ bool targethasInvertedY, bool sourceHasInvertedY);
+
+private:
+ QOpenGLShaderProgram *m_shaderProgram;
+ QMatrix4x4 m_transformMatrix;
+
+ int m_matrixLocation;
+ int m_vertexCoordEntry;
+ int m_textureCoordEntry;
+};
+
+#endif // TEXTUREBLITTER_H
diff --git a/examples/qwindow-compositor/qwindow-compositor.pro b/examples/qwindow-compositor/qwindow-compositor.pro
index b3e7ffbc2..3bae92dd6 100644
--- a/examples/qwindow-compositor/qwindow-compositor.pro
+++ b/examples/qwindow-compositor/qwindow-compositor.pro
@@ -9,17 +9,22 @@ CONFIG += use_pkgconfig
LIBS += -L ../../lib
#include (../../src/qt-compositor/qt-compositor.pri)
+HEADERS += \
+ qopenglwindow.h \
+ qwindowcompositor.h \
+ textureblitter.h
+
# Input
SOURCES += main.cpp \
qopenglwindow.cpp \
- surfacerenderer.cpp \
- qwindowcompositor.cpp
+ qwindowcompositor.cpp \
+ textureblitter.cpp
CONFIG += qt warn_on debug create_prl link_prl
OBJECTS_DIR = .obj/release-shared
MOC_DIR = .moc/release-shared
-QT += gui
+QT += gui gui-private core-private
QT += compositor
@@ -28,11 +33,6 @@ QT += compositor
# the following line
#include(../../src/compositor/compositor.pri)
-HEADERS += \
- qopenglwindow.h \
- surfacerenderer.h \
- qwindowcompositor.h
-
RESOURCES += qwindow-compositor.qrc
# install
diff --git a/examples/qwindow-compositor/qwindowcompositor.cpp b/examples/qwindow-compositor/qwindowcompositor.cpp
index 59e181a21..d194a4832 100644
--- a/examples/qwindow-compositor/qwindowcompositor.cpp
+++ b/examples/qwindow-compositor/qwindowcompositor.cpp
@@ -6,16 +6,27 @@
QWindowCompositor::QWindowCompositor(QOpenGLWindow *window)
: WaylandCompositor(window)
, m_window(window)
+ , m_textureBlitter(0)
+ , m_renderScheduler(this)
{
+ enableSubSurfaceExtension();
+ m_window->makeCurrent();
+
+ m_textureCache = new QOpenGLTextureCache(m_window->context());
+ m_textureBlitter = new TextureBlitter();
m_backgroundImage = QImage(QLatin1String(":/background.jpg"));
- m_renderer = new SurfaceRenderer(m_window->context(), m_window);
- m_backgroundTexture = m_renderer->textureFromImage(m_backgroundImage);
+ m_renderScheduler.setSingleShot(true);
+ connect(&m_renderScheduler,SIGNAL(timeout()),this,SLOT(render()));
+
+
+
+ glGenFramebuffers(1,&m_surface_fbo);
window->installEventFilter(this);
setRetainedSelectionEnabled(true);
- render();
+ m_renderScheduler.start(0);
}
void QWindowCompositor::surfaceDestroyed(QObject *object)
@@ -24,7 +35,7 @@ void QWindowCompositor::surfaceDestroyed(QObject *object)
m_surfaces.removeOne(surface);
if (inputFocus() == surface || !inputFocus()) // typically reset to 0 already in Compositor::surfaceDestroyed()
setInputFocus(m_surfaces.isEmpty() ? 0 : m_surfaces.last());
- render();
+ m_renderScheduler.start(0);
}
void QWindowCompositor::surfaceMapped()
@@ -42,7 +53,7 @@ void QWindowCompositor::surfaceMapped()
}
m_surfaces.append(surface);
setInputFocus(surface);
- render();
+ m_renderScheduler.start(0);
}
void QWindowCompositor::surfaceDamaged(const QRect &rect)
@@ -55,7 +66,7 @@ void QWindowCompositor::surfaceDamaged(WaylandSurface *surface, const QRect &rec
{
Q_UNUSED(surface)
Q_UNUSED(rect)
- render();
+ m_renderScheduler.start(0);
}
void QWindowCompositor::surfaceCreated(WaylandSurface *surface)
@@ -63,7 +74,7 @@ void QWindowCompositor::surfaceCreated(WaylandSurface *surface)
connect(surface, SIGNAL(destroyed(QObject *)), this, SLOT(surfaceDestroyed(QObject *)));
connect(surface, SIGNAL(mapped()), this, SLOT(surfaceMapped()));
connect(surface, SIGNAL(damaged(const QRect &)), this, SLOT(surfaceDamaged(const QRect &)));
- render();
+ m_renderScheduler.start(0);
}
QPointF QWindowCompositor::toSurface(WaylandSurface *surface, const QPointF &pos) const
@@ -83,33 +94,78 @@ WaylandSurface *QWindowCompositor::surfaceAt(const QPoint &point, QPoint *local)
return 0;
}
+GLuint QWindowCompositor::composeSurface(WaylandSurface *surface) {
+ GLuint texture = 0;
+
+ glBindFramebuffer(GL_FRAMEBUFFER, m_surface_fbo);
+
+ if (surface->type() == WaylandSurface::Shm) {
+ texture = m_textureCache->bindTexture(QOpenGLContext::currentContext(),surface->image());
+ } else {
+ texture = surface->texture(QOpenGLContext::currentContext());
+ }
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D, texture, 0);
+ paintChildren(surface,surface);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,0, 0);
+
+ glBindFramebuffer(GL_FRAMEBUFFER,0);
+ return texture;
+}
+
+void QWindowCompositor::paintChildren(WaylandSurface *surface, WaylandSurface *window) {
+
+ if (surface->subSurfaces().size() == 0)
+ return;
+
+ QLinkedListIterator<WaylandSurface *> i(surface->subSurfaces());
+ while (i.hasNext()) {
+ WaylandSurface *subSurface = i.next();
+ QPoint p = subSurface->mapTo(window,QPoint(0,0));
+ QRect geo = subSurface->geometry();
+ geo.moveTo(p);
+ if (geo.isValid()) {
+ GLuint texture = 0;
+ if (subSurface->type() == WaylandSurface::Texture) {
+ texture = subSurface->texture(QOpenGLContext::currentContext());
+ } else if (surface->type() == WaylandSurface::Shm ) {
+ texture = m_textureCache->bindTexture(QOpenGLContext::currentContext(),surface->image());
+ }
+ qDebug() << "window geo is" << window->geometry().size();
+ m_textureBlitter->drawTexture(texture,geo,window->geometry().size(),0,window->isYInverted(),subSurface->isYInverted());
+ }
+ paintChildren(subSurface,window);
+ }
+}
+
+
void QWindowCompositor::render()
{
m_window->makeCurrent();
+ m_backgroundTexture = m_textureCache->bindTexture(QOpenGLContext::currentContext(),m_backgroundImage);
+ m_textureBlitter->bind();
//Draw the background Image texture
int w = m_window->width();
int h = m_window->height();
- int iw = m_backgroundImage.width();
- int ih = m_backgroundImage.height();
- for (int y = 0; y < h; y += ih) {
- for (int x = 0; x < w; x += iw) {
- m_renderer->drawTexture(m_backgroundTexture, QRect(QPoint(x, y), QSize(iw, ih)), 0);
+ QSize imageSize = m_backgroundImage.size();
+ for (int y = 0; y < h; y += imageSize.height()) {
+ for (int x = 0; x < w; x += imageSize.width()) {
+ m_textureBlitter->drawTexture(m_backgroundTexture,QRect(QPoint(x, y),imageSize),window()->size(), 0,true,true);
}
}
- //Iterate all surfaces in m_surfaces
- //If type == WaylandSurface::Texture draw textureId at geometry
foreach (WaylandSurface *surface, m_surfaces) {
- if (surface->type() == WaylandSurface::Texture)
- m_renderer->drawTexture(surface->texture(QOpenGLContext::currentContext()), surface->geometry(), 1); //depth argument should be dynamic (focused should be top).
- else if (surface->type() == WaylandSurface::Shm)
- m_renderer->drawImage(surface->image(), surface->geometry());
+ GLuint texture = composeSurface(surface);
+ m_textureBlitter->drawTexture(texture,surface->geometry(),m_window->size(),0,false,surface->isYInverted());
}
+
+ m_textureBlitter->release();
frameFinished();
glFinish();
+
m_window->swapBuffers();
- m_window->context()->doneCurrent();
}
bool QWindowCompositor::eventFilter(QObject *obj, QEvent *event)
@@ -119,7 +175,7 @@ bool QWindowCompositor::eventFilter(QObject *obj, QEvent *event)
switch (event->type()) {
case QEvent::Expose:
- render();
+ m_renderScheduler.start(0);
break;
case QEvent::MouseButtonPress: {
QPoint local;
@@ -130,7 +186,7 @@ bool QWindowCompositor::eventFilter(QObject *obj, QEvent *event)
setInputFocus(targetSurface);
m_surfaces.removeOne(targetSurface);
m_surfaces.append(targetSurface);
- render();
+ m_renderScheduler.start(0);
}
targetSurface->sendMousePressEvent(local, me->button());
}
diff --git a/examples/qwindow-compositor/qwindowcompositor.h b/examples/qwindow-compositor/qwindowcompositor.h
index 247260406..558451eb9 100644
--- a/examples/qwindow-compositor/qwindowcompositor.h
+++ b/examples/qwindow-compositor/qwindowcompositor.h
@@ -3,9 +3,11 @@
#include "waylandcompositor.h"
#include "waylandsurface.h"
-#include "surfacerenderer.h"
+#include "textureblitter.h"
#include "qopenglwindow.h"
+#include <QtGui/private/qopengltexturecache_p.h>
+
#include <QObject>
class QWindowCompositor : public QObject, public WaylandCompositor
@@ -18,13 +20,16 @@ private slots:
void surfaceMapped();
void surfaceDamaged(const QRect &rect);
+ void render();
protected:
void surfaceDamaged(WaylandSurface *surface, const QRect &rect);
void surfaceCreated(WaylandSurface *surface);
WaylandSurface* surfaceAt(const QPoint &point, QPoint *local = 0);
- void render();
+ GLuint composeSurface(WaylandSurface *surface);
+ void paintChildren(WaylandSurface *surface, WaylandSurface *window);
+
bool eventFilter(QObject *obj, QEvent *event);
QPointF toSurface(WaylandSurface *surface, const QPointF &pos) const;
@@ -34,7 +39,10 @@ private:
QImage m_backgroundImage;
GLuint m_backgroundTexture;
QList<WaylandSurface *> m_surfaces;
- SurfaceRenderer *m_renderer;
+ TextureBlitter *m_textureBlitter;
+ QOpenGLTextureCache *m_textureCache;
+ GLuint m_surface_fbo;
+ QTimer m_renderScheduler;
};
#endif // QWINDOWCOMPOSITOR_H
diff --git a/examples/qwindow-compositor/surfacerenderer.cpp b/examples/qwindow-compositor/surfacerenderer.cpp
deleted file mode 100644
index 31f31419d..000000000
--- a/examples/qwindow-compositor/surfacerenderer.cpp
+++ /dev/null
@@ -1,146 +0,0 @@
-#include "surfacerenderer.h"
-
-#include <QOpenGLFunctions>
-#include <QImage>
-
-SurfaceRenderer::SurfaceRenderer(QOpenGLContext *context, QWindow *surface)
- : m_context(context)
- , m_surface(surface)
-{
- const char *textureVertexProgram =
- "uniform highp mat4 matrix;\n"
- "attribute highp vec3 vertexCoordEntry;\n"
- "attribute highp vec2 textureCoordEntry;\n"
- "varying highp vec2 textureCoord;\n"
- "void main() {\n"
- " textureCoord = textureCoordEntry;\n"
- " gl_Position = matrix * vec4(vertexCoordEntry, 1);\n"
- "}\n";
-
- const char *textureFragmentProgram =
- "uniform sampler2D texture;\n"
- "varying highp vec2 textureCoord;\n"
- "void main() {\n"
- " gl_FragColor = texture2D(texture, textureCoord);\n"
- "}\n";
-
- m_context->makeCurrent(m_surface);
-
- //Enable transparent windows
- glEnable(GL_BLEND);
- glBlendFunc (GL_ONE,GL_ONE_MINUS_SRC_ALPHA);
-
- //May need to manually set context here
- m_shaderProgram = new QOpenGLShaderProgram();
-
- m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram);
- m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgram);
- m_shaderProgram->link();
- m_shaderProgram->bind();
-
- m_vertexCoordEntry = m_shaderProgram->attributeLocation("vertexCoordEntry");
- m_textureCoordEntry = m_shaderProgram->attributeLocation("textureCoordEntry");
- m_matrixLocation = m_shaderProgram->uniformLocation("matrix");
-
-}
-
-void SurfaceRenderer::drawImage(const QImage &image, const QRectF &geometry)
-{
- if (image.isNull())
- return;
- GLuint textureId = textureFromImage(image);
- drawTexture(textureId, geometry);
- glDeleteTextures(1, &textureId);
-}
-
-void SurfaceRenderer::drawTexture(int textureId, const QRectF &geometry, int depth)
-{
- GLfloat zValue = depth / 1000.0f;
- //Set Texture and Vertex coordinates
- GLfloat textureCoordinates[] = { 0, 1,
- 1, 1,
- 1, 0,
- 0, 0
- };
-
- GLfloat vertexCoordinates[] = { geometry.left(), geometry.top(), zValue,
- geometry.right(), geometry.top(), zValue,
- geometry.right(), geometry.bottom(), zValue,
- geometry.left(), geometry.bottom(), zValue
- };
-
- //Set matrix to transfrom geometry values into gl coordinate space.
- m_transformMatrix.setToIdentity();
- m_transformMatrix.scale( 2.0f / m_surface->geometry().width(), -2.0f / m_surface->geometry().height());
- m_transformMatrix.translate(-m_surface->geometry().width() / 2.0f, -m_surface->geometry().height() / 2.0f);
-
- m_shaderProgram->bind();
-
- //attach the data!
- m_context->functions()->glEnableVertexAttribArray(m_vertexCoordEntry);
- m_context->functions()->glEnableVertexAttribArray(m_textureCoordEntry);
-
- m_context->functions()->glVertexAttribPointer(m_vertexCoordEntry, 3, GL_FLOAT, GL_FALSE, 0, vertexCoordinates);
- m_context->functions()->glVertexAttribPointer(m_textureCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinates);
- m_shaderProgram->setUniformValue(m_matrixLocation, m_transformMatrix);
-
- glBindTexture(GL_TEXTURE_2D, textureId);
-
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-
- glBindTexture(GL_TEXTURE_2D, 0);
-
- m_context->functions()->glDisableVertexAttribArray(m_vertexCoordEntry);
- m_context->functions()->glDisableVertexAttribArray(m_textureCoordEntry);
- m_shaderProgram->release();
-}
-
-static inline QImage convertToGLFormat(const QImage &img)
-{
- QImage dst(img.width(), img.height(), QImage::Format_ARGB32);
- const int width = img.width();
- const int height = img.height();
- const uint *p = (const uint*) img.scanLine(img.height() - 1);
- uint *q = (uint*) dst.scanLine(0);
-
- if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
- for (int i=0; i < height; ++i) {
- const uint *end = p + width;
- while (p < end) {
- *q = (*p << 8) | ((*p >> 24) & 0xff);
- p++;
- q++;
- }
- p -= 2 * width;
- }
- } else {
- for (int i=0; i < height; ++i) {
- const uint *end = p + width;
- while (p < end) {
- *q = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00);
- p++;
- q++;
- }
- p -= 2 * width;
- }
- }
-
- return dst;
-}
-
-GLuint SurfaceRenderer::textureFromImage(const QImage &image)
-{
- QImage convertedImage = convertToGLFormat(image);
- GLuint textureId;
- //Copy QImage data to Texture
- glGenTextures(1, &textureId);
- glBindTexture(GL_TEXTURE_2D, textureId);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, convertedImage.width(), convertedImage.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, convertedImage.constBits());
-
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- return textureId;
-}
diff --git a/examples/qwindow-compositor/surfacerenderer.h b/examples/qwindow-compositor/surfacerenderer.h
deleted file mode 100644
index abfb554b0..000000000
--- a/examples/qwindow-compositor/surfacerenderer.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef SURFACERENDERER_H
-#define SURFACERENDERER_H
-
-#include <QOpenGLContext>
-#include <QOpenGLShaderProgram>
-#include <QWindow>
-
-class SurfaceRenderer
-{
-public:
- SurfaceRenderer(QOpenGLContext *context, QWindow *surface);
-
- void drawImage(const QImage &image, const QRectF &geometry);
- void drawTexture(int textureId, const QRectF &geometry, int depth = 0);
- GLuint textureFromImage(const QImage &image);
-
-private:
-
- QOpenGLContext *m_context;
- QWindow *m_surface;
- QOpenGLShaderProgram *m_shaderProgram;
- QMatrix4x4 m_transformMatrix;
-
- int m_matrixLocation;
- int m_vertexCoordEntry;
- int m_textureCoordEntry;
-};
-
-#endif // SURFACERENDERER_H
diff --git a/examples/qwindow-compositor/textureblitter.cpp b/examples/qwindow-compositor/textureblitter.cpp
new file mode 100644
index 000000000..8fefe48f6
--- /dev/null
+++ b/examples/qwindow-compositor/textureblitter.cpp
@@ -0,0 +1,118 @@
+#include "textureblitter.h"
+
+#include <QtGui/QOpenGLShaderProgram>
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLFunctions>
+
+TextureBlitter::TextureBlitter()
+ : m_shaderProgram(new QOpenGLShaderProgram())
+{
+ static const char *textureVertexProgram =
+ "uniform highp mat4 matrix;\n"
+ "attribute highp vec3 vertexCoordEntry;\n"
+ "attribute highp vec2 textureCoordEntry;\n"
+ "varying highp vec2 textureCoord;\n"
+ "void main() {\n"
+ " textureCoord = textureCoordEntry;\n"
+ " gl_Position = matrix * vec4(vertexCoordEntry, 1);\n"
+ "}\n";
+
+ static const char *textureFragmentProgram =
+ "uniform sampler2D texture;\n"
+ "varying highp vec2 textureCoord;\n"
+ "void main() {\n"
+ " gl_FragColor = texture2D(texture, textureCoord);\n"
+ "}\n";
+
+ //Enable transparent windows
+ glEnable(GL_BLEND);
+ glBlendFunc (GL_ONE,GL_ONE_MINUS_SRC_ALPHA);
+
+ m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram);
+ m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgram);
+ m_shaderProgram->link();
+}
+
+
+void TextureBlitter::bind()
+{
+
+ m_shaderProgram->bind();
+
+ m_vertexCoordEntry = m_shaderProgram->attributeLocation("vertexCoordEntry");
+ m_textureCoordEntry = m_shaderProgram->attributeLocation("textureCoordEntry");
+ m_matrixLocation = m_shaderProgram->uniformLocation("matrix");
+}
+
+void TextureBlitter::release()
+{
+ m_shaderProgram->release();
+}
+
+void TextureBlitter::drawTexture(int textureId, const QRectF &targetRect, const QSize &targetSize, int depth, bool targethasInvertedY, bool sourceHasInvertedY)
+{
+
+ glViewport(0,0,targetSize.width(),targetSize.height());
+ GLfloat zValue = depth / 1000.0f;
+ //Set Texture and Vertex coordinates
+ const GLfloat textureCoordinates[] = {
+ 0, 0,
+ 1, 0,
+ 1, 1,
+ 0, 1
+ };
+
+ int x1 = targetRect.left();
+ int x2 = targetRect.right();
+ int y1, y2;
+ if (targethasInvertedY) {
+ if (sourceHasInvertedY) {
+ y1 = targetRect.top();
+ y2 = targetRect.bottom();
+ } else {
+ y1 = targetRect.bottom();
+ y2 = targetRect.top();
+ }
+ } else {
+ if (sourceHasInvertedY) {
+ y1 = targetSize.height() - targetRect.top();
+ y2 = targetSize.height() - targetRect.bottom();
+ } else {
+ y1 = targetSize.height() - targetRect.bottom();
+ y2 = targetSize.height() - targetRect.top();
+ }
+ }
+
+ const GLfloat vertexCoordinates[] = {
+ x1, y1, zValue,
+ x2, y1, zValue,
+ x2, y2, zValue,
+ x1, y2, zValue
+ };
+
+ //Set matrix to transfrom geometry values into gl coordinate space.
+ m_transformMatrix.setToIdentity();
+ m_transformMatrix.scale( 2.0f / targetSize.width(), 2.0f / targetSize.height() );
+ m_transformMatrix.translate(-targetSize.width() / 2.0f, -targetSize.height() / 2.0f);
+
+ //attach the data!
+ QOpenGLContext *currentContext = QOpenGLContext::currentContext();
+ currentContext->functions()->glEnableVertexAttribArray(m_vertexCoordEntry);
+ currentContext->functions()->glEnableVertexAttribArray(m_textureCoordEntry);
+
+ currentContext->functions()->glVertexAttribPointer(m_vertexCoordEntry, 3, GL_FLOAT, GL_FALSE, 0, vertexCoordinates);
+ currentContext->functions()->glVertexAttribPointer(m_textureCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinates);
+ m_shaderProgram->setUniformValue(m_matrixLocation, m_transformMatrix);
+
+ glBindTexture(GL_TEXTURE_2D, textureId);
+
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ currentContext->functions()->glDisableVertexAttribArray(m_vertexCoordEntry);
+ currentContext->functions()->glDisableVertexAttribArray(m_textureCoordEntry);
+}
diff --git a/examples/qwindow-compositor/textureblitter.h b/examples/qwindow-compositor/textureblitter.h
new file mode 100644
index 000000000..13b2c6af8
--- /dev/null
+++ b/examples/qwindow-compositor/textureblitter.h
@@ -0,0 +1,26 @@
+#ifndef TEXTUREBLITTER_H
+#define TEXTUREBLITTER_H
+
+#include <QtGui/QMatrix4x4>
+
+class QOpenGLShaderProgram;
+class TextureBlitter
+{
+public:
+ TextureBlitter();
+ void bind();
+ void release();
+ void drawTexture(int textureId, const QRectF &sourceGeometry,
+ const QSize &targetRect, int depth,
+ bool targethasInvertedY, bool sourceHasInvertedY);
+
+private:
+ QOpenGLShaderProgram *m_shaderProgram;
+ QMatrix4x4 m_transformMatrix;
+
+ int m_matrixLocation;
+ int m_vertexCoordEntry;
+ int m_textureCoordEntry;
+};
+
+#endif // TEXTUREBLITTER_H