Add a custom WaylandSurfaceNode with its own materials
authorAndy Nichols <andy.nichols@nokia.com>
Fri, 11 May 2012 12:39:36 +0000 (14:39 +0200)
committerAndy Nichols <andy.nichols@nokia.com>
Fri, 18 May 2012 11:48:31 +0000 (13:48 +0200)
With the previous WaylandSurfaceNode based on QSGSimpleTextureNode,
QSGTexture's created from SHM buffers would always have and use their
alpha channels, despite the useTextureAlpha flag being set to false. Now
when the useTextureAlpha flag is set to false, we use a material that
ignores the textures alpha channel.

Change-Id: I9cc33939f37856495f8885357f49de5ffdd81d1f
Reviewed-by: Gunnar Sletta <gunnar.sletta@nokia.com>
Reviewed-by: Samuel Rødal <samuel.rodal@nokia.com>
src/compositor/compositor_api/compositor_api.pri
src/compositor/compositor_api/waylandsurfaceitem.cpp
src/compositor/compositor_api/waylandsurfacenode.cpp [new file with mode: 0644]
src/compositor/compositor_api/waylandsurfacenode.h [new file with mode: 0644]
src/compositor/compositor_api/waylandsurfacetexturematerial.cpp [new file with mode: 0644]
src/compositor/compositor_api/waylandsurfacetexturematerial.h [new file with mode: 0644]

index 0f81d77..72b1949 100644 (file)
@@ -3,12 +3,16 @@ INCLUDEPATH += $$PWD
 HEADERS += \
     $$PWD/waylandcompositor.h \
     $$PWD/waylandsurface.h \
-    $$PWD/waylandinput.h
+    $$PWD/waylandinput.h \
+    $$PWD/waylandsurfacenode.h \
+    $$PWD/waylandsurfacetexturematerial.h
 
 SOURCES += \
     $$PWD/waylandcompositor.cpp \
     $$PWD/waylandsurface.cpp \
-    $$PWD/waylandinput.cpp
+    $$PWD/waylandinput.cpp \
+    $$PWD/waylandsurfacenode.cpp \
+    $$PWD/waylandsurfacetexturematerial.cpp
 
 QT += core-private
 
index 71bfd61..e042125 100644 (file)
@@ -39,6 +39,7 @@
 ****************************************************************************/
 
 #include "waylandsurfaceitem.h"
+#include "waylandsurfacenode.h"
 #include "waylandsurface.h"
 #include "waylandcompositor.h"
 #include "waylandinput.h"
 #include <QtGui/QGuiApplication>
 #include <QtGui/QScreen>
 
-#include <QtQuick/QSGSimpleTextureNode>
 #include <QtQuick/QSGSimpleRectNode>
 #include <QtQuick/QQuickCanvas>
 
 #include <QtCore/QMutexLocker>
 #include <QtCore/QMutex>
 
-class WaylandSurfaceNode : public QSGSimpleTextureNode
-{
-public:
-    WaylandSurfaceNode(WaylandSurfaceItem *item)
-        : m_item(item), m_textureUpdated(false)
-    {
-        if (m_item)
-            m_item->m_node = this;
-        setFlag(UsePreprocess,true);
-    }
-    ~WaylandSurfaceNode() {
-        QMutexLocker locker(WaylandSurfaceItem::mutex);
-        if (m_item)
-            m_item->m_node = 0;
-    }
-    void preprocess() {
-        QMutexLocker locker(WaylandSurfaceItem::mutex);
-
-        //Update if the item is dirty and we haven't done an updateTexture for this frame
-        if (m_item && m_item->m_damaged && !m_textureUpdated) {
-            m_item->updateTexture();
-            updateTexture();
-        }
-        //Reset value for next frame: we have not done updatePaintNode yet
-        m_textureUpdated = false;
-    }
-
-    void updateTexture() {
-        Q_ASSERT(m_item && m_item->textureProvider());
-
-        QSGTexture *texture = m_item->textureProvider()->texture();
-        setTexture(texture);
-        setFiltering(texture->filtering());
-    }
-
-    WaylandSurfaceItem *m_item;
-    bool m_textureUpdated;
-};
 
 class WaylandSurfaceTextureProvider : public QSGTextureProvider
 {
@@ -189,7 +151,7 @@ WaylandSurfaceItem::~WaylandSurfaceItem()
 {
     QMutexLocker locker(mutex);
     if (m_node)
-        m_node->m_item = 0;
+        m_node->setItem(0);
     if (m_surface)
         m_surface->setSurfaceItem(0);
     if (m_provider)
@@ -421,7 +383,8 @@ QSGNode *WaylandSurfaceItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDa
         node->setRect(0, 0, width(), height());
     }
 
-    node->m_textureUpdated = true;
+    node->setTextureUpdated(true);
+
     return node;
 }
 
diff --git a/src/compositor/compositor_api/waylandsurfacenode.cpp b/src/compositor/compositor_api/waylandsurfacenode.cpp
new file mode 100644 (file)
index 0000000..e657175
--- /dev/null
@@ -0,0 +1,104 @@
+#include "waylandsurfacenode.h"
+#include "waylandsurfaceitem.h"
+
+#include <QtCore/QMutexLocker>
+#include <QtQuick/QSGTexture>
+#include <QtQuick/QSGSimpleTextureNode>
+#include <QtQuick/QSGFlatColorMaterial>
+
+WaylandSurfaceNode::WaylandSurfaceNode(WaylandSurfaceItem *item)
+    : m_item(item)
+    , m_textureUpdated(false)
+    , m_useTextureAlpha(false)
+    , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4)
+{
+    m_textureMaterial = WaylandSurfaceTextureMaterial::createMaterial();
+    m_opaqueTextureMaterial = WaylandSurfaceTextureOpaqueMaterial::createMaterial();
+
+    m_currentMaterial = m_opaqueTextureMaterial;
+
+    setGeometry(&m_geometry);
+    setMaterial(m_currentMaterial);
+
+    if (m_item)
+        m_item->m_node = this;
+    setFlag(UsePreprocess,true);
+}
+
+
+WaylandSurfaceNode::~WaylandSurfaceNode()
+{
+    QMutexLocker locker(WaylandSurfaceItem::mutex);
+    if (m_item)
+        m_item->m_node = 0;
+    delete m_textureMaterial;
+    delete m_opaqueTextureMaterial;
+}
+
+void WaylandSurfaceNode::preprocess()
+{
+    QMutexLocker locker(WaylandSurfaceItem::mutex);
+
+    //Update if the item is dirty and we haven't done an updateTexture for this frame
+    if (m_item && m_item->m_damaged && !m_textureUpdated) {
+        m_item->updateTexture();
+        updateTexture();
+    }
+    //Reset value for next frame: we have not done updatePaintNode yet
+    m_textureUpdated = false;
+}
+
+void WaylandSurfaceNode::updateTexture()
+{
+    Q_ASSERT(m_item && m_item->textureProvider());
+
+    //If m_item->useTextureAlpha has changed to true use m_texureMaterial
+    //otherwise use m_opaqueTextureMaterial.
+    if (m_item->useTextureAlpha() != m_useTextureAlpha) {
+        m_useTextureAlpha = m_item->useTextureAlpha();
+        if (m_useTextureAlpha) {
+            m_currentMaterial = m_textureMaterial;
+        } else {
+            m_currentMaterial = m_opaqueTextureMaterial;
+        }
+        setMaterial(m_currentMaterial);
+    }
+
+    QSGTexture *texture = m_item->textureProvider()->texture();
+    setTexture(texture);
+}
+
+void WaylandSurfaceNode::setRect(const QRectF &rect)
+{
+    if (m_rect == rect)
+        return;
+    m_rect = rect;
+
+    if (texture()) {
+        QSize ts = texture()->textureSize();
+        QRectF sourceRect(0, 0, ts.width(), ts.height());
+        QSGGeometry::updateTexturedRectGeometry(&m_geometry, m_rect, texture()->convertToNormalizedSourceRect(sourceRect));
+    }
+}
+
+void WaylandSurfaceNode::setTexture(QSGTexture *texture)
+{
+    if (m_currentMaterial->state()->texture() == texture)
+        return;
+    m_currentMaterial->state()->setTexture(texture);
+
+    QSize ts = texture->textureSize();
+    QRectF sourceRect(0, 0, ts.width(), ts.height());
+    QSGGeometry::updateTexturedRectGeometry(&m_geometry, m_rect, texture->convertToNormalizedSourceRect(sourceRect));
+    markDirty(DirtyMaterial);
+}
+
+QSGTexture *WaylandSurfaceNode::texture() const
+{
+    return m_currentMaterial->state()->texture();
+}
+
+void WaylandSurfaceNode::setItem(WaylandSurfaceItem *item)
+{
+    m_item = item;
+}
diff --git a/src/compositor/compositor_api/waylandsurfacenode.h b/src/compositor/compositor_api/waylandsurfacenode.h
new file mode 100644 (file)
index 0000000..3ea0afe
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef WAYLANDSURFACENODE_H
+#define WAYLANDSURFACENODE_H
+
+#include "waylandsurfacetexturematerial.h"
+
+#include <QtQuick/QSGGeometryNode>
+#include <QtQuick/QSGOpaqueTextureMaterial>
+
+class WaylandSurfaceItem;
+class QSGTexture;
+
+class WaylandSurfaceNode : public QSGGeometryNode
+{
+public:
+    WaylandSurfaceNode(WaylandSurfaceItem *item = 0);
+    ~WaylandSurfaceNode();
+
+    void preprocess();
+    void updateTexture();
+
+    void setRect(const QRectF &rect);
+    inline void setRect(qreal x, qreal y, qreal w, qreal h) { setRect(QRectF(x, y, w, h)); }
+
+    void setTexture(QSGTexture *texture);
+    QSGTexture *texture() const;
+
+    bool isTextureUpdated() const { return m_textureUpdated; }
+    void setTextureUpdated(bool textureUpdated) { m_textureUpdated = textureUpdated; }
+
+    WaylandSurfaceItem *item() const { return m_item; }
+    void setItem(WaylandSurfaceItem *item);
+
+private:
+
+    WaylandSurfaceItem *m_item;
+    bool m_textureUpdated;
+    bool m_useTextureAlpha;
+
+    QSGGeometry m_geometry;
+    QSGSimpleMaterial<WaylandSurfaceTextureState> *m_textureMaterial;
+    QSGSimpleMaterial<WaylandSurfaceTextureState> *m_opaqueTextureMaterial;
+    QSGSimpleMaterial<WaylandSurfaceTextureState> *m_currentMaterial;
+
+    QRectF m_rect;
+};
+
+#endif // WAYLANDSURFACENODE_H
diff --git a/src/compositor/compositor_api/waylandsurfacetexturematerial.cpp b/src/compositor/compositor_api/waylandsurfacetexturematerial.cpp
new file mode 100644 (file)
index 0000000..80a3d2c
--- /dev/null
@@ -0,0 +1,77 @@
+#include "waylandsurfacetexturematerial.h"
+#include <QtGui/QOpenGLContext>
+
+static const char wayland_surface_texture_material_vertex[] =
+           "uniform highp mat4 qt_Matrix;                      \n"
+           "attribute highp vec4 qt_VertexPosition;            \n"
+           "attribute highp vec2 qt_VertexTexCoord;            \n"
+           "varying highp vec2 qt_TexCoord;                    \n"
+           "void main() {                                      \n"
+           "    qt_TexCoord = qt_VertexTexCoord;               \n"
+           "    gl_Position = qt_Matrix * qt_VertexPosition;   \n"
+           "}";
+
+
+static const char wayland_surface_texture_opaque_material_fragment[] =
+           "varying highp vec2 qt_TexCoord;                    \n"
+           "uniform sampler2D qt_Texture;                      \n"
+           "uniform lowp float qt_Opacity;                     \n"
+           "void main() {                                      \n"
+           "    gl_FragColor = vec4(texture2D(qt_Texture, qt_TexCoord).rgb, 1.0) * qt_Opacity; \n"
+           "}";
+
+static const char wayland_surface_texture_material_fragment[] =
+           "varying highp vec2 qt_TexCoord;                    \n"
+           "uniform sampler2D qt_Texture;                      \n"
+           "uniform lowp float qt_Opacity;                     \n"
+           "void main() {                                      \n"
+           "    gl_FragColor = texture2D(qt_Texture, qt_TexCoord) * qt_Opacity; \n"
+           "}";
+
+QList<QByteArray> WaylandSurfaceTextureMaterial::attributes() const
+{
+    QList<QByteArray> attributeList;
+    attributeList << "qt_VertexPosition";
+    attributeList << "qt_VertexTexCoord";
+    return attributeList;
+}
+
+void WaylandSurfaceTextureMaterial::updateState(const WaylandSurfaceTextureState *newState, const WaylandSurfaceTextureState *oldState)
+{
+    Q_UNUSED(oldState);
+    newState->texture()->bind();
+}
+
+const char *WaylandSurfaceTextureMaterial::vertexShader() const
+{
+    return wayland_surface_texture_material_vertex;
+}
+
+const char *WaylandSurfaceTextureMaterial::fragmentShader() const
+{
+    return wayland_surface_texture_material_fragment;
+}
+
+QList<QByteArray> WaylandSurfaceTextureOpaqueMaterial::attributes() const
+{
+    QList<QByteArray> attributeList;
+    attributeList << "qt_VertexPosition";
+    attributeList << "qt_VertexTexCoord";
+    return attributeList;
+}
+
+void WaylandSurfaceTextureOpaqueMaterial::updateState(const WaylandSurfaceTextureState *newState, const WaylandSurfaceTextureState *oldState)
+{
+    Q_UNUSED(oldState);
+    newState->texture()->bind();
+}
+
+const char *WaylandSurfaceTextureOpaqueMaterial::vertexShader() const
+{
+    return wayland_surface_texture_material_vertex;
+}
+
+const char *WaylandSurfaceTextureOpaqueMaterial::fragmentShader() const
+{
+    return wayland_surface_texture_opaque_material_fragment;
+}
diff --git a/src/compositor/compositor_api/waylandsurfacetexturematerial.h b/src/compositor/compositor_api/waylandsurfacetexturematerial.h
new file mode 100644 (file)
index 0000000..ace271e
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef WAYLANDSURFACETEXTUREMATERIAL_H
+#define WAYLANDSURFACETEXTUREMATERIAL_H
+
+#include <QtQuick/QSGSimpleMaterial>
+#include <QtQuick/QSGTexture>
+#include <QtGui/QOpenGLFunctions>
+
+class WaylandSurfaceTextureState {
+public:
+    WaylandSurfaceTextureState()
+        : m_texture(0)
+    {}
+    void setTexture(QSGTexture *texture) { m_texture = texture; }
+    QSGTexture *texture() const { return m_texture; }
+
+private:
+    QSGTexture *m_texture;
+};
+
+class WaylandSurfaceTextureMaterial : public QSGSimpleMaterialShader<WaylandSurfaceTextureState>
+{
+    QSG_DECLARE_SIMPLE_SHADER(WaylandSurfaceTextureMaterial, WaylandSurfaceTextureState)
+    public:
+
+        QList<QByteArray> attributes() const;
+
+        void updateState(const WaylandSurfaceTextureState *newState, const WaylandSurfaceTextureState *oldState);
+protected:
+        const char *vertexShader() const;
+        const char *fragmentShader() const;
+};
+
+class WaylandSurfaceTextureOpaqueMaterial : public QSGSimpleMaterialShader<WaylandSurfaceTextureState>
+{
+    QSG_DECLARE_SIMPLE_SHADER(WaylandSurfaceTextureOpaqueMaterial, WaylandSurfaceTextureState)
+    public:
+
+        QList<QByteArray> attributes() const;
+
+        void updateState(const WaylandSurfaceTextureState *newState, const WaylandSurfaceTextureState *oldState);
+protected:
+        const char *vertexShader() const;
+        const char *fragmentShader() const;
+};
+
+#endif // WAYLANDSURFACETEXTUREMATERIAL_H