diff options
author | Louai Al-Khanji <louai.al-khanji@theqtcompany.com> | 2016-02-19 15:58:33 -0800 |
---|---|---|
committer | Louai Al-Khanji <louai.al-khanji@qt.io> | 2016-04-29 16:09:07 +0000 |
commit | ab2d5162039bd7dac6547a5984dbe6e19b7d835c (patch) | |
tree | 6e2f8da3c6e9340634821666c8b7079870f57566 /src/compositor/compositor_api/qwaylandquickitem.cpp | |
parent | aae5a5b19c320f367a7e43d54d84b0562a85737a (diff) |
QtWaylandCompositor: Add support for different EGL buffer formats
Change-Id: Idfeeedbf247fa81dccdf28a1aa04f878900ed262
Reviewed-by: Giulio Camuffo <giulio.camuffo@kdab.com>
Diffstat (limited to 'src/compositor/compositor_api/qwaylandquickitem.cpp')
-rw-r--r-- | src/compositor/compositor_api/qwaylandquickitem.cpp | 252 |
1 files changed, 231 insertions, 21 deletions
diff --git a/src/compositor/compositor_api/qwaylandquickitem.cpp b/src/compositor/compositor_api/qwaylandquickitem.cpp index ded16a9c3..e46b38ccd 100644 --- a/src/compositor/compositor_api/qwaylandquickitem.cpp +++ b/src/compositor/compositor_api/qwaylandquickitem.cpp @@ -57,8 +57,179 @@ #include <wayland-server.h> #include <QThread> +#ifndef GL_TEXTURE_EXTERNAL_OES +#define GL_TEXTURE_EXTERNAL_OES 0x8D65 +#endif + QT_BEGIN_NAMESPACE +static const struct { + const char * const vertexShaderSourceFile; + const char * const fragmentShaderSourceFile; + GLenum textureTarget; + int planeCount; + bool canProvideTexture; + QSGMaterial::Flags materialFlags; + QSGMaterialType materialType; +} bufferTypes[] = { + // BufferFormatEgl_Null + { "", "", 0, 0, false, 0, {} }, + + // BufferFormatEgl_RGB + { + ":/qt-project.org/wayland/compositor/shaders/surface.vert", + ":/qt-project.org/wayland/compositor/shaders/surface_rgbx.frag", + GL_TEXTURE_2D, 1, true, + QSGMaterial::Blending, + {} + }, + + // BufferFormatEgl_RGBA + { + ":/qt-project.org/wayland/compositor/shaders/surface.vert", + ":/qt-project.org/wayland/compositor/shaders/surface_rgba.frag", + GL_TEXTURE_2D, 1, true, + QSGMaterial::Blending, + {} + }, + + // BufferFormatEgl_EXTERNAL_OES + { + ":/qt-project.org/wayland/compositor/shaders/surface.vert", + ":/qt-project.org/wayland/compositor/shaders/surface_oes_external.frag", + GL_TEXTURE_EXTERNAL_OES, 1, false, + QSGMaterial::Blending, + {} + }, + + // BufferFormatEgl_Y_U_V + { + ":/qt-project.org/wayland/compositor/shaders/surface.vert", + ":/qt-project.org/wayland/compositor/shaders/surface_y_u_v.frag", + GL_TEXTURE_2D, 3, false, + QSGMaterial::Blending, + {} + }, + + // BufferFormatEgl_Y_UV + { + ":/qt-project.org/wayland/compositor/shaders/surface.vert", + ":/qt-project.org/wayland/compositor/shaders/surface_y_uv.frag", + GL_TEXTURE_2D, 2, false, + QSGMaterial::Blending, + {} + }, + + // BufferFormatEgl_Y_XUXV + { + ":/qt-project.org/wayland/compositor/shaders/surface.vert", + ":/qt-project.org/wayland/compositor/shaders/surface_y_xuxv.frag", + GL_TEXTURE_2D, 2, false, + QSGMaterial::Blending, + {} + } +}; + +QWaylandBufferMaterialShader::QWaylandBufferMaterialShader(QWaylandBufferRef::BufferFormatEgl format) + : QSGMaterialShader() + , m_format(format) +{ + setShaderSourceFile(QOpenGLShader::Vertex, QString::fromLatin1(bufferTypes[format].vertexShaderSourceFile)); + setShaderSourceFile(QOpenGLShader::Fragment, QString::fromLatin1(bufferTypes[format].fragmentShaderSourceFile)); +} + +void QWaylandBufferMaterialShader::updateState(const QSGMaterialShader::RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) +{ + QSGMaterialShader::updateState(state, newEffect, oldEffect); + + QWaylandBufferMaterial *material = static_cast<QWaylandBufferMaterial *>(newEffect); + material->bind(); + + if (state.isMatrixDirty()) + program()->setUniformValue(m_id_matrix, state.combinedMatrix()); + + if (state.isOpacityDirty()) + program()->setUniformValue(m_id_opacity, state.opacity()); +} + +const char * const *QWaylandBufferMaterialShader::attributeNames() const +{ + static char const *const attr[] = { "qt_VertexPosition", "qt_VertexTexCoord", 0 }; + return attr; +} + +void QWaylandBufferMaterialShader::initialize() +{ + QSGMaterialShader::initialize(); + + m_id_matrix = program()->uniformLocation("qt_Matrix"); + m_id_opacity = program()->uniformLocation("qt_Opacity"); + + for (int i = 0; i < bufferTypes[m_format].planeCount; i++) { + m_id_tex << program()->uniformLocation("tex" + QByteArray::number(i)); + program()->setUniformValue(m_id_tex[i], i); + } + + Q_ASSERT(m_id_tex.size() == bufferTypes[m_format].planeCount); +} + +QWaylandBufferMaterial::QWaylandBufferMaterial(QWaylandBufferRef::BufferFormatEgl format) + : QSGMaterial() + , m_format(format) +{ + QOpenGLFunctions *gl = QOpenGLContext::currentContext()->functions(); + + for (int i = 0; i < bufferTypes[m_format].planeCount; i++) { + GLuint texture; + gl->glGenTextures(1, &texture); + gl->glBindTexture(bufferTypes[m_format].textureTarget, texture); + gl->glTexParameteri(bufferTypes[m_format].textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + gl->glTexParameteri(bufferTypes[m_format].textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + gl->glTexParameteri(bufferTypes[m_format].textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + gl->glTexParameteri(bufferTypes[m_format].textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + m_textures << texture; + } + + gl->glBindTexture(bufferTypes[m_format].textureTarget, 0); + setFlag(bufferTypes[m_format].materialFlags); +} + +QWaylandBufferMaterial::~QWaylandBufferMaterial() +{ + QOpenGLFunctions *gl = QOpenGLContext::currentContext()->functions(); + + for (GLuint texture : m_textures) + gl->glDeleteTextures(1, &texture); +} + +void QWaylandBufferMaterial::bind() +{ + QOpenGLFunctions *gl = QOpenGLContext::currentContext()->functions(); + const GLenum target = bufferTypes[m_format].textureTarget; + + switch (m_textures.size()) { + case 3: + gl->glActiveTexture(GL_TEXTURE2); + gl->glBindTexture(target, m_textures[2]); + case 2: + gl->glActiveTexture(GL_TEXTURE1); + gl->glBindTexture(target, m_textures[1]); + case 1: + gl->glActiveTexture(GL_TEXTURE0); + gl->glBindTexture(target, m_textures[0]); + } +} + +QSGMaterialType *QWaylandBufferMaterial::type() const +{ + return const_cast<QSGMaterialType *>(&bufferTypes[m_format].materialType); +} + +QSGMaterialShader *QWaylandBufferMaterial::createShader() const +{ + return new QWaylandBufferMaterialShader(m_format); +} + QMutex *QWaylandQuickItemPrivate::mutex = 0; class QWaylandSurfaceTextureProvider : public QSGTextureProvider @@ -85,7 +256,6 @@ public: if (m_ref.hasBuffer()) { if (buffer.isShm()) { m_sgTex = surfaceItem->window()->createTextureFromImage(buffer.image()); - m_invertY = false; if (m_sgTex) { m_sgTex->bind(); } @@ -101,7 +271,6 @@ public: glBindTexture(GL_TEXTURE_2D, texture); buffer.bindToTexture(); m_sgTex = surfaceItem->window()->createTextureFromId(texture , QSize(surfaceItem->width(), surfaceItem->height()), opt); - m_invertY = buffer.origin() == QWaylandSurface::OriginBottomLeft; } } emit textureChanged(); @@ -115,10 +284,8 @@ public: } void setSmooth(bool smooth) { m_smooth = smooth; } - bool invertY() const { return m_invertY; } private: bool m_smooth; - bool m_invertY; QSGTexture *m_sgTex; QWaylandBufferRef m_ref; }; @@ -249,6 +416,12 @@ QWaylandSurface::Origin QWaylandQuickItem::origin() const return d->origin; } +bool QWaylandQuickItem::isTextureProvider() const +{ + Q_D(const QWaylandQuickItem); + return QQuickItem::isTextureProvider() || d->provider; +} + /*! * Returns the texture provider of this QWaylandQuickItem. */ @@ -822,37 +995,73 @@ void QWaylandQuickItem::updateInputMethod(Qt::InputMethodQueries queries) QSGNode *QWaylandQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) { Q_D(QWaylandQuickItem); - bool mapped = (surface() && surface()->isMapped() && d->view->currentBuffer().hasBuffer()) - || (d->view->isBufferLocked() && d->provider); + const bool mapped = surface() && surface()->isMapped() && d->view->currentBuffer().hasBuffer(); if (!mapped || !d->paintEnabled) { delete oldNode; return 0; } - QSGSimpleTextureNode *node = static_cast<QSGSimpleTextureNode *>(oldNode); + QWaylandBufferRef ref = d->view->currentBuffer(); + const bool invertY = ref.origin() == QWaylandSurface::OriginBottomLeft; + const QRectF rect = invertY ? QRectF(0, height(), width(), -height()) + : QRectF(0, 0, width(), height()); - if (!node) - node = new QSGSimpleTextureNode(); + if (ref.isShm() || bufferTypes[ref.bufferFormatEgl()].canProvideTexture) { + QSGSimpleTextureNode *node = static_cast<QSGSimpleTextureNode *>(oldNode); - if (!d->provider) - d->provider = new QWaylandSurfaceTextureProvider(); + if (!node) + node = new QSGSimpleTextureNode(); - if (d->newTexture) { - d->newTexture = false; - d->provider->setBufferRef(this, d->view->currentBuffer()); - node->setTexture(d->provider->texture()); - } + if (!d->provider) + d->provider = new QWaylandSurfaceTextureProvider(); + + if (d->newTexture) { + d->newTexture = false; + d->provider->setBufferRef(this, ref); + node->setTexture(d->provider->texture()); + } - d->provider->setSmooth(smooth()); + d->provider->setSmooth(smooth()); + node->setRect(rect); - if (d->provider->invertY()) { - node->setRect(0, height(), width(), -height()); + return node; } else { - node->setRect(0, 0, width(), height()); + Q_ASSERT(!d->provider); + + QSGGeometryNode *node = static_cast<QSGGeometryNode *>(oldNode); + + if (!node) + node = new QSGGeometryNode; + + QSGGeometry *geometry = node->geometry(); + QWaylandBufferMaterial *material = static_cast<QWaylandBufferMaterial *>(node->material()); + + if (!geometry) + geometry = new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4); + + if (!material) + material = new QWaylandBufferMaterial(ref.bufferFormatEgl()); + + if (d->newTexture) { + d->newTexture = false; + material->bind(); + ref.bindToTexture(); + } + + ref.updateTexture(); + QSGGeometry::updateTexturedRectGeometry(geometry, rect, QRectF(0, 0, 1, 1)); + + node->setGeometry(geometry); + node->setFlag(QSGNode::OwnsGeometry, true); + + node->setMaterial(material); + node->setFlag(QSGNode::OwnsMaterial, true); + + return node; } - return node; + Q_UNREACHABLE(); } void QWaylandQuickItem::setTouchEventsEnabled(bool enabled) @@ -909,3 +1118,4 @@ void QWaylandQuickItem::handleSubsurfacePosition(const QPoint &pos) } QT_END_NAMESPACE + |