diff options
32 files changed, 941 insertions, 798 deletions
diff --git a/examples/wayland/minimal-cpp/compositor.cpp b/examples/wayland/minimal-cpp/compositor.cpp index ea685923b..5e46895c4 100644 --- a/examples/wayland/minimal-cpp/compositor.cpp +++ b/examples/wayland/minimal-cpp/compositor.cpp @@ -44,17 +44,9 @@ #include <QtWaylandCompositor/qwaylandoutput.h> #include <QOpenGLFunctions> -GLuint View::getTexture() { - if (advance()) { - QOpenGLFunctions *functions = QOpenGLContext::currentContext()->functions(); - if (m_texture) - functions->glDeleteTextures(1, &m_texture); - - functions->glGenTextures(1, &m_texture); - functions->glBindTexture(GL_TEXTURE_2D, m_texture); - functions->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - currentBuffer().bindToTexture(); - } +QOpenGLTexture *View::getTexture() { + if (advance()) + m_texture = currentBuffer().toOpenGLTexture(); return m_texture; } diff --git a/examples/wayland/minimal-cpp/compositor.h b/examples/wayland/minimal-cpp/compositor.h index fe379082c..e44a8eb52 100644 --- a/examples/wayland/minimal-cpp/compositor.h +++ b/examples/wayland/minimal-cpp/compositor.h @@ -48,17 +48,18 @@ QT_BEGIN_NAMESPACE class Window; +class QOpenGLTexture; class View : public QWaylandView { Q_OBJECT public: View() : m_texture(0) {} - GLuint getTexture(); + QOpenGLTexture *getTexture(); bool isCursor() const; private: friend class Compositor; - GLuint m_texture; + QOpenGLTexture *m_texture; }; class Compositor : public QWaylandCompositor diff --git a/examples/wayland/minimal-cpp/window.cpp b/examples/wayland/minimal-cpp/window.cpp index 2d529cce5..6ae89be4f 100644 --- a/examples/wayland/minimal-cpp/window.cpp +++ b/examples/wayland/minimal-cpp/window.cpp @@ -44,6 +44,7 @@ #include <QPainter> #include <QMatrix4x4> #include <QOpenGLFunctions> +#include <QOpenGLTexture> Window::Window() : m_compositor(0) @@ -83,7 +84,10 @@ void Window::paintGL() Q_FOREACH (View *view, m_compositor->views()) { if (view->isCursor()) continue; - GLuint textureId = view->getTexture(); + auto texture = view->getTexture(); + if (!texture) + continue; + GLuint textureId = texture->textureId(); QWaylandSurface *surface = view->surface(); if (surface && surface->hasContent()) { QSize s = surface->size(); diff --git a/examples/wayland/qwindow-compositor/compositor.cpp b/examples/wayland/qwindow-compositor/compositor.cpp index e9231faf9..a55bb3b72 100644 --- a/examples/wayland/qwindow-compositor/compositor.cpp +++ b/examples/wayland/qwindow-compositor/compositor.cpp @@ -65,32 +65,13 @@ View::View() , m_parentView(nullptr) {} -GLuint View::getTexture(GLenum *target) +QOpenGLTexture *View::getTexture() { - QWaylandBufferRef buf = currentBuffer(); - GLuint streamingTexture = buf.textureForPlane(0); - if (streamingTexture) - m_texture = streamingTexture; - - if (!buf.isSharedMemory() && buf.bufferFormatEgl() == QWaylandBufferRef::BufferFormatEgl_EXTERNAL_OES) - m_textureTarget = GL_TEXTURE_EXTERNAL_OES; - if (advance()) { - buf = currentBuffer(); - if (!m_texture) - glGenTextures(1, &m_texture); - - glBindTexture(m_textureTarget, m_texture); - if (buf.isSharedMemory()) - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - buf.bindToTexture(); + QWaylandBufferRef buf = currentBuffer(); + m_texture = buf.toOpenGLTexture(); } - buf.updateTexture(); - - if (target) - *target = m_textureTarget; - return m_texture; } diff --git a/examples/wayland/qwindow-compositor/compositor.h b/examples/wayland/qwindow-compositor/compositor.h index b7569082f..bf52c8c7e 100644 --- a/examples/wayland/qwindow-compositor/compositor.h +++ b/examples/wayland/qwindow-compositor/compositor.h @@ -53,13 +53,14 @@ QT_BEGIN_NAMESPACE class QWaylandWlShell; class QWaylandWlShellSurface; class QWaylandXdgShellV5; +class QOpenGLTexture; class View : public QWaylandView { Q_OBJECT public: View(); - GLuint getTexture(GLenum *target = 0); + QOpenGLTexture *getTexture(); QPointF position() const { return m_position; } void setPosition(const QPointF &pos) { m_position = pos; } bool isCursor() const; @@ -73,7 +74,7 @@ public: private: friend class Compositor; GLenum m_textureTarget; - GLuint m_texture; + QOpenGLTexture *m_texture; QPointF m_position; QWaylandWlShellSurface *m_wlShellSurface; QWaylandXdgSurfaceV5 *m_xdgSurface; diff --git a/examples/wayland/qwindow-compositor/window.cpp b/examples/wayland/qwindow-compositor/window.cpp index 617d79c0e..371e0de80 100644 --- a/examples/wayland/qwindow-compositor/window.cpp +++ b/examples/wayland/qwindow-compositor/window.cpp @@ -120,12 +120,11 @@ void Window::paintGL() Q_FOREACH (View *view, m_compositor->views()) { if (view->isCursor()) continue; - GLenum target; - GLuint textureId = view->getTexture(&target); - if (!textureId || !target) + auto texture = view->getTexture(); + if (!texture) continue; - if (target != currentTarget) { - currentTarget = target; + if (texture->target() != currentTarget) { + currentTarget = texture->target(); m_textureBlitter.bind(currentTarget); } QWaylandSurface *surface = view->surface(); @@ -141,7 +140,7 @@ void Window::paintGL() ? QOpenGLTextureBlitter::OriginTopLeft : QOpenGLTextureBlitter::OriginBottomLeft; QMatrix4x4 targetTransform = QOpenGLTextureBlitter::targetTransform(surfaceGeometry, QRect(QPoint(), size())); - m_textureBlitter.blit(textureId, targetTransform, surfaceOrigin); + m_textureBlitter.blit(texture->textureId(), targetTransform, surfaceOrigin); } } } diff --git a/src/compositor/compositor_api/qwaylandbufferref.cpp b/src/compositor/compositor_api/qwaylandbufferref.cpp index 7cc17fcbe..8f7c63f40 100644 --- a/src/compositor/compositor_api/qwaylandbufferref.cpp +++ b/src/compositor/compositor_api/qwaylandbufferref.cpp @@ -38,14 +38,14 @@ #include <QAtomicInt> #include "qwaylandbufferref.h" -#include "wayland_wrapper/qwlsurfacebuffer_p.h" +#include "wayland_wrapper/qwlclientbuffer_p.h" QT_BEGIN_NAMESPACE class QWaylandBufferRefPrivate { public: - QtWayland::SurfaceBuffer *buffer; + QtWayland::ClientBuffer *buffer; bool nullOrDestroyed() { return !buffer || buffer->isDestroyed(); @@ -74,7 +74,7 @@ QWaylandBufferRef::QWaylandBufferRef() /*! * Constructs a reference to \a buffer. */ -QWaylandBufferRef::QWaylandBufferRef(QtWayland::SurfaceBuffer *buffer) +QWaylandBufferRef::QWaylandBufferRef(QtWayland::ClientBuffer *buffer) : d(new QWaylandBufferRefPrivate) { d->buffer = buffer; @@ -104,17 +104,18 @@ QWaylandBufferRef::~QWaylandBufferRef() } /*! - * Assigns \a ref to this buffer. The previously referenced buffer is - * dereferenced and the new one gets a new reference. + * Assigns \a ref to this buffer and adds a reference to it. The previously referenced buffer is + * dereferenced. */ QWaylandBufferRef &QWaylandBufferRef::operator=(const QWaylandBufferRef &ref) { + if (ref.d->buffer) + ref.d->buffer->ref(); + if (d->buffer) d->buffer->deref(); d->buffer = ref.d->buffer; - if (d->buffer) - d->buffer->ref(); return *this; } @@ -141,7 +142,7 @@ bool QWaylandBufferRef::operator!=(const QWaylandBufferRef &ref) * Returns true if this QWaylandBufferRef does not reference a buffer. * Otherwise returns false. * - * \sa hasBuffer() + * \sa hasBuffer(), hasContent() */ bool QWaylandBufferRef::isNull() const { @@ -151,12 +152,21 @@ bool QWaylandBufferRef::isNull() const /*! * Returns true if this QWaylandBufferRef references a buffer. Otherwise returns false. * - * \sa isNull() + * \sa isNull(), hasContent() */ bool QWaylandBufferRef::hasBuffer() const { return d->buffer; } +/*! + * Returns true if this QWaylandBufferRef references a buffer that has content. Otherwise returns false. + * + * \sa isNull(), hasBuffer() + */ +bool QWaylandBufferRef::hasContent() const +{ + return QtWayland::ClientBuffer::hasContent(d->buffer); +} /*! * Returns true if this QWaylandBufferRef references a buffer that @@ -176,6 +186,14 @@ struct ::wl_resource *QWaylandBufferRef::wl_buffer() const } /*! + * \internal + */ +QtWayland::ClientBuffer *QWaylandBufferRef::buffer() const +{ + return d->buffer; +} + +/*! * Returns the size of the buffer. * If the buffer referenced is null, an invalid QSize() is returned. */ @@ -242,35 +260,23 @@ QImage QWaylandBufferRef::image() const } #ifdef QT_WAYLAND_COMPOSITOR_GL -GLuint QWaylandBufferRef::textureForPlane(int plane) const -{ - if (d->nullOrDestroyed()) - return 0; - - return d->buffer->textureForPlane(plane); -} - /*! - * Binds the buffer to the current OpenGL texture. This may - * perform a copy of the buffer data, depending on the platform - * and the type of the buffer. + * Returns an OpenGL texture for the buffer. \a plane is the index for multi-plane formats, such as YUV. + * + * The returned texture is owned by the buffer. The texture is only valid for as + * long as the buffer reference exists. The caller of this function must not delete the texture, and must + * keep a reference to the buffer for as long as the texture is being used. + * + * Returns \c nullptr if there is no valid buffer, or if no texture can be created. */ -void QWaylandBufferRef::bindToTexture() const +QOpenGLTexture *QWaylandBufferRef::toOpenGLTexture(int plane) const { if (d->nullOrDestroyed()) - return; - - return d->buffer->bindToTexture(); + return nullptr; + return d->buffer->toOpenGlTexture(plane); } -void QWaylandBufferRef::updateTexture() const -{ - if (d->nullOrDestroyed() || d->buffer->isSharedMemory()) - return; - - d->buffer->updateTexture(); -} #endif QT_END_NAMESPACE diff --git a/src/compositor/compositor_api/qwaylandbufferref.h b/src/compositor/compositor_api/qwaylandbufferref.h index 77f817aba..549ea0a80 100644 --- a/src/compositor/compositor_api/qwaylandbufferref.h +++ b/src/compositor/compositor_api/qwaylandbufferref.h @@ -50,22 +50,24 @@ struct wl_resource; QT_BEGIN_NAMESPACE +class QOpenGLTexture; + namespace QtWayland { - class SurfaceBuffer; + class ClientBuffer; } class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandBufferRef { public: QWaylandBufferRef(); - explicit QWaylandBufferRef(QtWayland::SurfaceBuffer *buffer); QWaylandBufferRef(const QWaylandBufferRef &ref); ~QWaylandBufferRef(); QWaylandBufferRef &operator=(const QWaylandBufferRef &ref); bool isNull() const; bool hasBuffer() const; + bool hasContent() const; bool isDestroyed() const; bool operator==(const QWaylandBufferRef &ref); bool operator!=(const QWaylandBufferRef &ref); @@ -98,14 +100,15 @@ public: QImage image() const; #ifdef QT_WAYLAND_COMPOSITOR_GL - GLuint textureForPlane(int plane) const; - void bindToTexture() const; - void updateTexture() const; + QOpenGLTexture *toOpenGLTexture(int plane = 0) const; #endif private: + explicit QWaylandBufferRef(QtWayland::ClientBuffer *buffer); + QtWayland::ClientBuffer *buffer() const; class QWaylandBufferRefPrivate *const d; friend class QWaylandBufferRefPrivate; + friend class QWaylandSurfacePrivate; }; QT_END_NAMESPACE diff --git a/src/compositor/compositor_api/qwaylandcompositor.cpp b/src/compositor/compositor_api/qwaylandcompositor.cpp index 0d4e30df7..79a62a1f2 100644 --- a/src/compositor/compositor_api/qwaylandcompositor.cpp +++ b/src/compositor/compositor_api/qwaylandcompositor.cpp @@ -53,6 +53,7 @@ #include "wayland_wrapper/qwldatadevice_p.h" #include "wayland_wrapper/qwldatadevicemanager_p.h" +#include "wayland_wrapper/qwlbuffermanager_p.h" #include "hardware_integration/qwlclientbufferintegration_p.h" #include "hardware_integration/qwlclientbufferintegrationfactory_p.h" @@ -81,6 +82,7 @@ #ifdef QT_WAYLAND_COMPOSITOR_GL # include <QOpenGLTextureBlitter> +# include <QOpenGLTexture> # include <QOpenGLContext> # include <QOpenGLFramebufferObject> # include <QMatrix4x4> @@ -174,6 +176,7 @@ void QWaylandCompositorPrivate::init() wl_subcompositor::init(display, 1); data_device_manager = new QtWayland::DataDeviceManager(q); + buffer_manager = new QtWayland::BufferManager(q); wl_display_init_shm(display); QVector<wl_shm_format> formats = QWaylandSharedMemoryFormatHelper::supportedWaylandFormats(); @@ -895,7 +898,7 @@ void QWaylandCompositor::grabSurface(QWaylandSurfaceGrabber *grabber, const QWay fbo.bind(); QOpenGLTextureBlitter blitter; blitter.create(); - blitter.bind(); + glViewport(0, 0, buffer.size().width(), buffer.size().height()); @@ -904,15 +907,10 @@ void QWaylandCompositor::grabSurface(QWaylandSurfaceGrabber *grabber, const QWay ? QOpenGLTextureBlitter::OriginTopLeft : QOpenGLTextureBlitter::OriginBottomLeft; - GLuint texture; - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - buffer.bindToTexture(); - blitter.blit(texture, QMatrix4x4(), surfaceOrigin); - + auto texture = buffer.toOpenGLTexture(); + blitter.bind(texture->target()); + blitter.blit(texture->textureId(), QMatrix4x4(), surfaceOrigin); blitter.release(); - glDeleteTextures(1, &texture); emit grabber->success(fbo.toImage()); } else diff --git a/src/compositor/compositor_api/qwaylandcompositor_p.h b/src/compositor/compositor_api/qwaylandcompositor_p.h index 9942331e4..5255f3d58 100644 --- a/src/compositor/compositor_api/qwaylandcompositor_p.h +++ b/src/compositor/compositor_api/qwaylandcompositor_p.h @@ -64,6 +64,7 @@ namespace QtWayland { class ClientBufferIntegration; class ServerBufferIntegration; class DataDeviceManager; + class BufferManager; } class QWindowSystemEventHandler; @@ -89,6 +90,7 @@ public: inline QtWayland::ServerBufferIntegration *serverBufferIntegration() const; QtWayland::DataDeviceManager *dataDeviceManager() const { return data_device_manager; } + QtWayland::BufferManager *bufferManager() const { return buffer_manager; } void feedRetainedSelectionData(QMimeData *data); QWaylandPointer *callCreatePointerDevice(QWaylandSeat *seat) @@ -129,6 +131,7 @@ protected: QList<QWaylandSurface *> all_surfaces; QtWayland::DataDeviceManager *data_device_manager; + QtWayland::BufferManager *buffer_manager; QElapsedTimer timer; diff --git a/src/compositor/compositor_api/qwaylandquickcompositor.cpp b/src/compositor/compositor_api/qwaylandquickcompositor.cpp index 21e32573e..b69e20791 100644 --- a/src/compositor/compositor_api/qwaylandquickcompositor.cpp +++ b/src/compositor/compositor_api/qwaylandquickcompositor.cpp @@ -38,6 +38,7 @@ #include <QtQml/QQmlEngine> #include <QQuickWindow> #include <QOpenGLTextureBlitter> +#include <QOpenGLTexture> #include <QOpenGLFramebufferObject> #include <QMatrix4x4> #include <QRunnable> @@ -140,7 +141,6 @@ void QWaylandQuickCompositor::grabSurface(QWaylandSurfaceGrabber *grabber, const fbo.bind(); QOpenGLTextureBlitter blitter; blitter.create(); - blitter.bind(); glViewport(0, 0, buffer.size().width(), buffer.size().height()); @@ -149,15 +149,10 @@ void QWaylandQuickCompositor::grabSurface(QWaylandSurfaceGrabber *grabber, const ? QOpenGLTextureBlitter::OriginTopLeft : QOpenGLTextureBlitter::OriginBottomLeft; - GLuint texture; - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - buffer.bindToTexture(); - blitter.blit(texture, QMatrix4x4(), surfaceOrigin); - + auto texture = buffer.toOpenGLTexture(); + blitter.bind(texture->target()); + blitter.blit(texture->textureId(), QMatrix4x4(), surfaceOrigin); blitter.release(); - glDeleteTextures(1, &texture); emit grabber->success(fbo.toImage()); } diff --git a/src/compositor/compositor_api/qwaylandquickitem.cpp b/src/compositor/compositor_api/qwaylandquickitem.cpp index a3234cba6..f41a4c3ee 100644 --- a/src/compositor/compositor_api/qwaylandquickitem.cpp +++ b/src/compositor/compositor_api/qwaylandquickitem.cpp @@ -50,6 +50,7 @@ #include <QtGui/QGuiApplication> #include <QtGui/QScreen> #include <QtGui/QOpenGLFunctions> +#include <QtGui/QOpenGLTexture> #include <QtQuick/QSGSimpleTextureNode> #include <QtQuick/QQuickWindow> @@ -188,52 +189,40 @@ QWaylandBufferMaterial::QWaylandBufferMaterial(QWaylandBufferRef::BufferFormatEg QWaylandBufferMaterial::~QWaylandBufferMaterial() { - QOpenGLFunctions *gl = QOpenGLContext::currentContext()->functions(); - - for (GLuint texture : m_textures) - gl->glDeleteTextures(1, &texture); } -void QWaylandBufferMaterial::setTextureForPlane(int plane, uint texture) +void QWaylandBufferMaterial::setTextureForPlane(int plane, QOpenGLTexture *texture) { if (plane < 0 || plane >= bufferTypes[m_format].planeCount) { qWarning("plane index is out of range"); return; } - QOpenGLFunctions *gl = QOpenGLContext::currentContext()->functions(); - const GLenum target = bufferTypes[m_format].textureTarget; - - gl->glBindTexture(target, texture); - setTextureParameters(target); + texture->bind(); + setTextureParameters(texture->target()); ensureTextures(plane - 1); - if (m_textures.size() <= plane) { + if (m_textures.size() <= plane) m_textures << texture; - } else { - std::swap(m_textures[plane], texture); - gl->glDeleteTextures(1, &texture); - } + else + m_textures[plane] = texture; } void QWaylandBufferMaterial::bind() { - QOpenGLFunctions *gl = QOpenGLContext::currentContext()->functions(); - const GLenum target = bufferTypes[m_format].textureTarget; - ensureTextures(bufferTypes[m_format].planeCount); switch (m_textures.size()) { case 3: - gl->glActiveTexture(GL_TEXTURE2); - gl->glBindTexture(target, m_textures[2]); + if (m_textures[2]) + m_textures[2]->bind(GL_TEXTURE2); case 2: - gl->glActiveTexture(GL_TEXTURE1); - gl->glBindTexture(target, m_textures[1]); + if (m_textures[1]) + m_textures[1]->bind(GL_TEXTURE1); case 1: - gl->glActiveTexture(GL_TEXTURE0); - gl->glBindTexture(target, m_textures[0]); + if (m_textures[0]) + m_textures[0]->bind(GL_TEXTURE0); } } @@ -260,15 +249,8 @@ void QWaylandBufferMaterial::setTextureParameters(GLenum target) //TODO move this into a separate centralized texture management class void QWaylandBufferMaterial::ensureTextures(int count) { - QOpenGLFunctions *gl = QOpenGLContext::currentContext()->functions(); - const GLenum target = bufferTypes[m_format].textureTarget; - GLuint texture; - for (int plane = m_textures.size(); plane < count; plane++) { - gl->glGenTextures(1, &texture); - gl->glBindTexture(target, texture); - setTextureParameters(target); - m_textures << texture; + m_textures << nullptr; } } @@ -308,11 +290,8 @@ public: opt |= QQuickWindow::TextureHasAlphaChannel; } - GLuint texture; - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - buffer.bindToTexture(); - m_sgTex = surfaceItem->window()->createTextureFromId(texture , QSize(surfaceItem->width(), surfaceItem->height()), opt); + auto texture = buffer.toOpenGLTexture(); + m_sgTex = surfaceItem->window()->createTextureFromId(texture->textureId() , QSize(surfaceItem->width(), surfaceItem->height()), opt); } } emit textureChanged(); @@ -1151,6 +1130,7 @@ QSGNode *QWaylandQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat : QRectF(0, 0, width(), height()); if (ref.isSharedMemory() || bufferTypes[ref.bufferFormatEgl()].canProvideTexture) { + // This case could covered by the more general path below, but this is more efficient (especially when using ShaderEffect items). QSGSimpleTextureNode *node = static_cast<QSGSimpleTextureNode *>(oldNode); if (!node) { @@ -1193,13 +1173,11 @@ QSGNode *QWaylandQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat if (d->newTexture) { d->newTexture = false; for (int plane = 0; plane < bufferTypes[ref.bufferFormatEgl()].planeCount; plane++) - if (uint texture = ref.textureForPlane(plane)) + if (auto texture = ref.toOpenGLTexture(plane)) material->setTextureForPlane(plane, texture); material->bind(); - ref.bindToTexture(); } - ref.updateTexture(); QSGGeometry::updateTexturedRectGeometry(geometry, rect, QRectF(0, 0, 1, 1)); node->setGeometry(geometry); diff --git a/src/compositor/compositor_api/qwaylandquickitem_p.h b/src/compositor/compositor_api/qwaylandquickitem_p.h index 30f1e93c7..c30829926 100644 --- a/src/compositor/compositor_api/qwaylandquickitem_p.h +++ b/src/compositor/compositor_api/qwaylandquickitem_p.h @@ -59,6 +59,7 @@ QT_BEGIN_NAMESPACE class QWaylandSurfaceTextureProvider; class QMutex; +class QOpenGLTexture; class QWaylandBufferMaterialShader : public QSGMaterialShader { @@ -84,7 +85,7 @@ public: QWaylandBufferMaterial(QWaylandBufferRef::BufferFormatEgl format); ~QWaylandBufferMaterial(); - void setTextureForPlane(int plane, uint texture); + void setTextureForPlane(int plane, QOpenGLTexture *texture); void bind(); @@ -96,7 +97,7 @@ private: void ensureTextures(int count); const QWaylandBufferRef::BufferFormatEgl m_format; - QVarLengthArray<GLuint, 3> m_textures; + QVarLengthArray<QOpenGLTexture*, 3> m_textures; }; class QWaylandQuickItemPrivate : public QQuickItemPrivate diff --git a/src/compositor/compositor_api/qwaylandsurface.cpp b/src/compositor/compositor_api/qwaylandsurface.cpp index c00d765c5..2f4de5cfc 100644 --- a/src/compositor/compositor_api/qwaylandsurface.cpp +++ b/src/compositor/compositor_api/qwaylandsurface.cpp @@ -40,6 +40,7 @@ #include "wayland_wrapper/qwldatadevice_p.h" #include "wayland_wrapper/qwldatadevicemanager_p.h" +#include "wayland_wrapper/qwlbuffermanager_p.h" #include "wayland_wrapper/qwlregion_p.h" #include "extensions/qwlextendedsurface_p.h" @@ -123,7 +124,6 @@ QWaylandSurfacePrivate::QWaylandSurfacePrivate() , compositor(Q_NULLPTR) , refCount(1) , client(Q_NULLPTR) - , buffer(0) , role(0) , inputRegion(infiniteRegion()) , bufferScale(1) @@ -135,7 +135,7 @@ QWaylandSurfacePrivate::QWaylandSurfacePrivate() , inputMethodControl(Q_NULLPTR) , subsurface(0) { - pending.buffer = 0; + pending.buffer = QWaylandBufferRef(); pending.newlyAttached = false; pending.inputRegion = infiniteRegion(); pending.bufferScale = 1; @@ -153,9 +153,6 @@ QWaylandSurfacePrivate::~QWaylandSurfacePrivate() bufferRef = QWaylandBufferRef(); - for (int i = 0; i < bufferPool.size(); i++) - bufferPool[i]->setDestroyIfUnused(true); - foreach (QtWayland::FrameCallback *c, pendingFrameCallbacks) c->destroy(); foreach (QtWayland::FrameCallback *c, frameCallbacks) @@ -237,9 +234,7 @@ void QWaylandSurfacePrivate::surface_destroy(Resource *resource) void QWaylandSurfacePrivate::surface_attach(Resource *, struct wl_resource *buffer, int x, int y) { - if (pending.buffer) - pending.buffer->disown(); - pending.buffer = createSurfaceBuffer(buffer); + pending.buffer = QWaylandBufferRef(getBuffer(buffer)); pending.offset = QPoint(x, y); pending.newlyAttached = true; } @@ -274,19 +269,37 @@ void QWaylandSurfacePrivate::surface_commit(Resource *) { Q_Q(QWaylandSurface); - if (pending.buffer || pending.newlyAttached) { - setBackBuffer(pending.buffer, pending.damage); + if (pending.buffer.hasBuffer()) + bufferRef = pending.buffer; + + auto buffer = bufferRef.buffer(); + if (buffer) + buffer->setCommitted(pending.damage); + + setSize(bufferRef.size()); + damage = pending.damage.intersected(QRect(QPoint(), size)); + + for (int i = 0; i < views.size(); i++) { + views.at(i)->bufferCommitted(bufferRef, damage); } - pending.buffer = 0; - pending.offset = QPoint(); - pending.newlyAttached = false; - pending.damage = QRegion(); + emit q->damaged(damage); + + bool oldHasContent = hasContent; + hasContent = bufferRef.hasContent(); + if (oldHasContent != hasContent) + emit q->hasContentChanged(); + + if (!pending.offset.isNull()) + emit q->offsetForNextFrame(pending.offset); setBufferScale(pending.bufferScale); - if (buffer) - buffer->setCommitted(); + + pending.buffer = QWaylandBufferRef(); + pending.offset = QPoint(); + pending.newlyAttached = false; + pending.damage = QRegion(); frameCallbacks << pendingFrameCallbacks; pendingFrameCallbacks.clear(); @@ -326,52 +339,10 @@ void QWaylandSurfacePrivate::surface_set_buffer_scale(QtWaylandServer::wl_surfac pending.bufferScale = scale; } -void QWaylandSurfacePrivate::setBackBuffer(QtWayland::SurfaceBuffer *b, const QRegion &d) +QtWayland::ClientBuffer *QWaylandSurfacePrivate::getBuffer(struct ::wl_resource *buffer) { - Q_Q(QWaylandSurface); - buffer = b; - - bufferRef = QWaylandBufferRef(buffer); - - setSize(bufferRef.size()); - damage = d.intersected(QRect(QPoint(), size)); - - for (int i = 0; i < views.size(); i++) { - views.at(i)->bufferCommitted(bufferRef, damage); - } - - emit q->damaged(damage); - - bool oldHasContent = hasContent; - hasContent = QtWayland::SurfaceBuffer::hasContent(buffer); - if (oldHasContent != hasContent) - emit q->hasContentChanged(); - - if (!pending.offset.isNull()) - emit q->offsetForNextFrame(pending.offset); -} - -QtWayland::SurfaceBuffer *QWaylandSurfacePrivate::createSurfaceBuffer(struct ::wl_resource *buffer) -{ - Q_Q(QWaylandSurface); - QtWayland::SurfaceBuffer *newBuffer = 0; - for (int i = 0; i < bufferPool.size(); i++) { - if (!bufferPool[i]->isRegisteredWithBuffer()) { - newBuffer = bufferPool[i]; - newBuffer->initialize(buffer); - break; - } - } - - if (!newBuffer) { - newBuffer = new QtWayland::SurfaceBuffer(q); - newBuffer->initialize(buffer); - bufferPool.append(newBuffer); - if (bufferPool.size() > 3) - qWarning() << "Increased buffer pool size to" << bufferPool.size() << "for surface" << q; - } - - return newBuffer; + QtWayland::BufferManager *bufMan = QWaylandCompositorPrivate::get(compositor)->bufferManager(); + return bufMan->getBuffer(buffer); } /*! @@ -590,7 +561,7 @@ Qt::ScreenOrientation QWaylandSurface::contentOrientation() const QWaylandSurface::Origin QWaylandSurface::origin() const { Q_D(const QWaylandSurface); - return d->buffer ? d->buffer->origin() : QWaylandSurface::OriginTopLeft; + return d->bufferRef.origin(); } /*! @@ -835,8 +806,7 @@ void QWaylandSurfacePrivate::refView(QWaylandView *view) views.append(view); ref(); - QWaylandBufferRef ref(buffer); - view->bufferCommitted(ref, QRect(QPoint(0,0), ref.size())); + view->bufferCommitted(bufferRef, QRect(QPoint(0,0), bufferRef.size())); } void QWaylandSurfacePrivate::derefView(QWaylandView *view) diff --git a/src/compositor/compositor_api/qwaylandsurface_p.h b/src/compositor/compositor_api/qwaylandsurface_p.h index 0596b61ba..94ec287bd 100644 --- a/src/compositor/compositor_api/qwaylandsurface_p.h +++ b/src/compositor/compositor_api/qwaylandsurface_p.h @@ -52,7 +52,7 @@ #include <QtWaylandCompositor/qwaylandexport.h> #include <private/qobject_p.h> -#include <private/qwlsurfacebuffer_p.h> +#include <private/qwlclientbuffer_p.h> #include <QtWaylandCompositor/qwaylandsurface.h> #include <QtWaylandCompositor/qwaylandbufferref.h> @@ -134,8 +134,7 @@ protected: void surface_set_buffer_transform(Resource *resource, int32_t transform) Q_DECL_OVERRIDE; void surface_set_buffer_scale(Resource *resource, int32_t bufferScale) Q_DECL_OVERRIDE; - void setBackBuffer(QtWayland::SurfaceBuffer *buffer, const QRegion &damage); - QtWayland::SurfaceBuffer *createSurfaceBuffer(struct ::wl_resource *buffer); + QtWayland::ClientBuffer *getBuffer(struct ::wl_resource *buffer); public: //member variables QWaylandCompositor *compositor; @@ -143,12 +142,11 @@ public: //member variables QWaylandClient *client; QList<QWaylandView *> views; QRegion damage; - QtWayland::SurfaceBuffer *buffer; QWaylandBufferRef bufferRef; QWaylandSurfaceRole *role; struct { - QtWayland::SurfaceBuffer *buffer; + QWaylandBufferRef buffer; QRegion damage; QPoint offset; bool newlyAttached; @@ -165,8 +163,6 @@ public: //member variables QRegion inputRegion; QRegion opaqueRegion; - QVector<QtWayland::SurfaceBuffer *> bufferPool; - QSize size; int bufferScale; bool isCursorSurface; diff --git a/src/compositor/compositor_api/qwaylandview.cpp b/src/compositor/compositor_api/qwaylandview.cpp index 5b87eae21..850503847 100644 --- a/src/compositor/compositor_api/qwaylandview.cpp +++ b/src/compositor/compositor_api/qwaylandview.cpp @@ -151,6 +151,7 @@ void QWaylandView::setSurface(QWaylandSurface *newSurface) } d->nextBuffer = QWaylandBufferRef(); + d->nextBufferCommitted = false; d->nextDamage = QRegion(); if (d->surface) { @@ -211,6 +212,7 @@ void QWaylandView::bufferCommitted(const QWaylandBufferRef &buffer, const QRegio QMutexLocker locker(&d->bufferMutex); d->nextBuffer = buffer; d->nextDamage = damage; + d->nextBufferCommitted = true; } /*! @@ -232,7 +234,8 @@ void QWaylandView::bufferCommitted(const QWaylandBufferRef &buffer, const QRegio bool QWaylandView::advance() { Q_D(QWaylandView); - if (d->currentBuffer == d->nextBuffer && !d->forceAdvanceSucceed) + + if (!d->nextBufferCommitted && !d->forceAdvanceSucceed) return false; if (d->bufferLocked) @@ -247,6 +250,7 @@ bool QWaylandView::advance() QMutexLocker locker(&d->bufferMutex); d->forceAdvanceSucceed = false; + d->nextBufferCommitted = false; d->currentBuffer = d->nextBuffer; d->currentDamage = d->nextDamage; return true; diff --git a/src/compositor/compositor_api/qwaylandview_p.h b/src/compositor/compositor_api/qwaylandview_p.h index d9fd352ed..8c55eca36 100644 --- a/src/compositor/compositor_api/qwaylandview_p.h +++ b/src/compositor/compositor_api/qwaylandview_p.h @@ -69,6 +69,7 @@ public: : renderObject(Q_NULLPTR) , surface(Q_NULLPTR) , output(Q_NULLPTR) + , nextBufferCommitted(false) , bufferLocked(false) , broadcastRequestedPositionChanged(false) , forceAdvanceSucceed(false) @@ -86,6 +87,7 @@ public: QRegion currentDamage; QWaylandBufferRef nextBuffer; QRegion nextDamage; + bool nextBufferCommitted; bool bufferLocked; bool broadcastRequestedPositionChanged; bool forceAdvanceSucceed; diff --git a/src/compositor/hardware_integration/qwlclientbufferintegration_p.h b/src/compositor/hardware_integration/qwlclientbufferintegration_p.h index 90762437b..a7de2c0e3 100644 --- a/src/compositor/hardware_integration/qwlclientbufferintegration_p.h +++ b/src/compositor/hardware_integration/qwlclientbufferintegration_p.h @@ -57,6 +57,7 @@ QT_BEGIN_NAMESPACE class QWaylandCompositor; +class QOpenGLTexture; namespace QtWayland { class Display; @@ -68,22 +69,11 @@ public: virtual ~ClientBufferIntegration() { } void setCompositor(QWaylandCompositor *compositor) { m_compositor = compositor; } + QWaylandCompositor *compositor() const { return m_compositor; } virtual void initializeHardware(struct ::wl_display *display) = 0; - virtual void initializeBuffer(struct ::wl_resource *buffer) { Q_UNUSED(buffer); } - virtual QWaylandBufferRef::BufferFormatEgl bufferFormat(struct ::wl_resource *buffer) { Q_UNUSED(buffer); return QWaylandBufferRef::BufferFormatEgl_RGBA; } - virtual uint textureForBuffer(struct ::wl_resource *buffer, int plane) { Q_UNUSED(buffer); Q_UNUSED(plane); return 0; } - - virtual void bindTextureToBuffer(struct ::wl_resource *buffer) = 0; - virtual void updateTextureForBuffer(struct ::wl_resource *buffer) { Q_UNUSED(buffer); } - - virtual QWaylandSurface::Origin origin(struct ::wl_resource *) const { return QWaylandSurface::OriginBottomLeft; } - - virtual void *lockNativeBuffer(struct ::wl_resource *) const { return 0; } - virtual void unlockNativeBuffer(void *) const { return; } - - virtual QSize bufferSize(struct ::wl_resource *) const { return QSize(); } + virtual ClientBuffer *createBufferFor(struct ::wl_resource *buffer) = 0; protected: QWaylandCompositor *m_compositor; diff --git a/src/compositor/wayland_wrapper/qwlbuffermanager.cpp b/src/compositor/wayland_wrapper/qwlbuffermanager.cpp new file mode 100644 index 000000000..765c9a03a --- /dev/null +++ b/src/compositor/wayland_wrapper/qwlbuffermanager.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwlbuffermanager_p.h" +#include <QWaylandCompositor> +#include <QtWaylandCompositor/private/qwaylandcompositor_p.h> +#include <QtWaylandCompositor/private/qwlclientbufferintegration_p.h> +#include <QDebug> + +QT_BEGIN_NAMESPACE + +namespace QtWayland { + +BufferManager::BufferManager(QWaylandCompositor *compositor) + : QObject(compositor) + , m_compositor(compositor) +{ + +} + +struct buffer_manager_destroy_listener : wl_listener +{ + buffer_manager_destroy_listener() + : d(0) + { + notify = BufferManager::destroy_listener_callback; + wl_list_init(&this->link); + } + + BufferManager *d; +}; + +ClientBuffer *BufferManager::getBuffer(wl_resource *buffer_resource) +{ + if (!buffer_resource) + return nullptr; + + auto it = m_buffers.find(buffer_resource); + if (it != m_buffers.end()) + return it.value(); + + auto bufferIntegration = QWaylandCompositorPrivate::get(m_compositor)->clientBufferIntegration(); + ClientBuffer *newBuffer = nullptr; + if (bufferIntegration) + newBuffer = bufferIntegration->createBufferFor(buffer_resource); + if (!newBuffer) + newBuffer = new SharedMemoryBuffer(buffer_resource); + m_buffers[buffer_resource] = newBuffer; + + auto *destroy_listener = new buffer_manager_destroy_listener; + destroy_listener->d = this; + wl_signal_add(&buffer_resource->destroy_signal, destroy_listener); + return newBuffer; +} + + +void BufferManager::destroy_listener_callback(wl_listener *listener, void *data) +{ + buffer_manager_destroy_listener *destroy_listener = static_cast<buffer_manager_destroy_listener *>(listener); + BufferManager *self = destroy_listener->d; + struct ::wl_resource *buffer = static_cast<struct ::wl_resource *>(data); + + wl_list_remove(&destroy_listener->link); + delete destroy_listener; + + Q_ASSERT(self); + Q_ASSERT(buffer); + + ClientBuffer *clientBuffer = self->m_buffers.take(buffer); + + if (!clientBuffer) + return; + + clientBuffer->setDestroyed(); +} + +} +QT_END_NAMESPACE diff --git a/src/compositor/wayland_wrapper/qwlbuffermanager_p.h b/src/compositor/wayland_wrapper/qwlbuffermanager_p.h new file mode 100644 index 000000000..e1325ef89 --- /dev/null +++ b/src/compositor/wayland_wrapper/qwlbuffermanager_p.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWLBUFFERMANAGER_H +#define QWLBUFFERMANAGER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QObject> +#include "qwlclientbuffer_p.h" +QT_BEGIN_NAMESPACE + +class QWaylandCompositor; + +namespace QtWayland { + +class ClientBuffer; + +class Q_WAYLAND_COMPOSITOR_EXPORT BufferManager : public QObject +{ +public: + BufferManager(QWaylandCompositor *compositor); + ClientBuffer *getBuffer(struct ::wl_resource *buffer_resource); +private: + friend struct buffer_manager_destroy_listener; + static void destroy_listener_callback(wl_listener *listener, void *data); + + QHash<struct ::wl_resource *, ClientBuffer*> m_buffers; + QWaylandCompositor *m_compositor; +}; + +} +QT_END_NAMESPACE + +#endif // QWLBUFFERMANAGER_H diff --git a/src/compositor/wayland_wrapper/qwlclientbuffer.cpp b/src/compositor/wayland_wrapper/qwlclientbuffer.cpp new file mode 100644 index 000000000..589ab825b --- /dev/null +++ b/src/compositor/wayland_wrapper/qwlclientbuffer.cpp @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwlclientbuffer_p.h" + +#ifdef QT_WAYLAND_COMPOSITOR_GL +#include "hardware_integration/qwlclientbufferintegration_p.h" +#include <qpa/qplatformopenglcontext.h> +#include <QOpenGLTexture> +#endif + +#include <QtCore/QDebug> + +#include <wayland-server-protocol.h> +#include "qwaylandsharedmemoryformathelper_p.h" + +#include <QtWaylandCompositor/private/qwaylandcompositor_p.h> + +QT_BEGIN_NAMESPACE + +namespace QtWayland { + +ClientBuffer::ClientBuffer(struct ::wl_resource *buffer) + : m_buffer(buffer) + , m_textureDirty(false) + , m_committed(false) + , m_destroyed(false) +{ +} + + +ClientBuffer::~ClientBuffer() +{ + if (m_buffer && m_committed && !m_destroyed) + sendRelease(); +} + +void ClientBuffer::sendRelease() +{ + Q_ASSERT(m_buffer); + wl_buffer_send_release(m_buffer); + m_committed = false; +} + +void ClientBuffer::setDestroyed() +{ + m_destroyed = true; + m_committed = false; + m_buffer = nullptr; + + if (!m_refCount) + delete this; +} + +void ClientBuffer::ref() +{ + m_refCount.ref(); +} + +void ClientBuffer::deref() +{ + if (!m_refCount.deref()) { + if (isCommitted() && m_buffer && !m_destroyed) + sendRelease(); + if (m_destroyed) + delete this; + } +} + +void ClientBuffer::setCommitted(QRegion &damage) +{ + m_damage = damage; + m_committed = true; + m_textureDirty = true; +} + +QWaylandBufferRef::BufferFormatEgl ClientBuffer::bufferFormatEgl() const +{ + return QWaylandBufferRef::BufferFormatEgl_Null; +} + +SharedMemoryBuffer::SharedMemoryBuffer(wl_resource *bufferResource) + : ClientBuffer(bufferResource) + , m_shmTexture(nullptr) +{ + +} + +QSize SharedMemoryBuffer::size() const +{ + if (wl_shm_buffer *shmBuffer = wl_shm_buffer_get(m_buffer)) { + int width = wl_shm_buffer_get_width(shmBuffer); + int height = wl_shm_buffer_get_height(shmBuffer); + return QSize(width, height); + } + return QSize(); +} + +QWaylandSurface::Origin SharedMemoryBuffer::origin() const +{ + return QWaylandSurface::OriginTopLeft; +} + + +// TODO: support different color formats, and try to avoid QImage::convertToFormat() + +QImage SharedMemoryBuffer::image() const +{ + if (wl_shm_buffer *shmBuffer = wl_shm_buffer_get(m_buffer)) { + int width = wl_shm_buffer_get_width(shmBuffer); + int height = wl_shm_buffer_get_height(shmBuffer); + int bytesPerLine = wl_shm_buffer_get_stride(shmBuffer); + uchar *data = static_cast<uchar *>(wl_shm_buffer_get_data(shmBuffer)); + return QImage(data, width, height, bytesPerLine, QImage::Format_ARGB32_Premultiplied); + } + + return QImage(); +} + +#ifdef QT_WAYLAND_COMPOSITOR_GL +QOpenGLTexture *SharedMemoryBuffer::toOpenGlTexture(int plane) +{ + Q_UNUSED(plane); + if (isSharedMemory()) { + if (!m_shmTexture) { + m_shmTexture = new QOpenGLTexture(QOpenGLTexture::Target2D); + m_shmTexture->create(); + } + if (m_textureDirty) { + m_textureDirty = false; + m_shmTexture->bind(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + // TODO: partial texture upload + QImage image = this->image(); + if (image.hasAlphaChannel()) { + if (image.format() != QImage::Format_RGBA8888) + image = image.convertToFormat(QImage::Format_RGBA8888); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image.constBits()); + } else { + if (image.format() != QImage::Format_RGBX8888) + image = image.convertToFormat(QImage::Format_RGBX8888); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width(), image.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, image.constBits()); + } + //we can release the buffer after uploading, since we have a copy + if (isCommitted()) + sendRelease(); + } + return m_shmTexture; + } + return nullptr; +} +#endif + +} + +QT_END_NAMESPACE diff --git a/src/compositor/wayland_wrapper/qwlsurfacebuffer_p.h b/src/compositor/wayland_wrapper/qwlclientbuffer_p.h index e0a7d021f..72c5a56e3 100644 --- a/src/compositor/wayland_wrapper/qwlsurfacebuffer_p.h +++ b/src/compositor/wayland_wrapper/qwlclientbuffer_p.h @@ -34,8 +34,8 @@ ** ****************************************************************************/ -#ifndef SURFACEBUFFER_H -#define SURFACEBUFFER_H +#ifndef QWLCLIENTBUFFER_P_H +#define QWLCLIENTBUFFER_P_H // // W A R N I N G @@ -63,83 +63,85 @@ QT_BEGIN_NAMESPACE class QWaylandClientBufferIntegration; class QWaylandBufferRef; class QWaylandCompositor; +class QOpenGLTexture; namespace QtWayland { struct surface_buffer_destroy_listener { struct wl_listener listener; - class SurfaceBuffer *surfaceBuffer; + class ClientBuffer *surfaceBuffer; }; -class SurfaceBuffer +class Q_WAYLAND_COMPOSITOR_EXPORT ClientBuffer { public: - SurfaceBuffer(QWaylandSurface *surface); + ClientBuffer(struct ::wl_resource *bufferResource); - ~SurfaceBuffer(); + virtual ~ClientBuffer(); - void initialize(struct ::wl_resource *bufferResource); - void destructBufferState(); + virtual QWaylandBufferRef::BufferFormatEgl bufferFormatEgl() const; + virtual QSize size() const = 0; + virtual QWaylandSurface::Origin origin() const = 0; - inline bool isRegisteredWithBuffer() const { return m_is_registered_for_buffer; } + virtual void *lockNativeBuffer() { return nullptr; } + virtual void unlockNativeBuffer(void *native_buffer) const { Q_UNUSED(native_buffer); } - void sendRelease(); - void disown(); - - void setDisplayed(); + virtual QImage image() const { return QImage(); } inline bool isCommitted() const { return m_committed; } - inline void setCommitted() { m_committed = true; } - inline bool isDisplayed() const { return m_is_displayed; } - + virtual void setCommitted(QRegion &damage); bool isDestroyed() { return m_destroyed; } inline struct ::wl_resource *waylandBufferHandle() const { return m_buffer; } - void setDestroyIfUnused(bool destroy); - - QSize size() const; - QWaylandSurface::Origin origin() const; bool isSharedMemory() const { return wl_shm_buffer_get(m_buffer); } - QImage image() const; - QWaylandBufferRef::BufferFormatEgl bufferFormatEgl() const; #ifdef QT_WAYLAND_COMPOSITOR_GL - void bindToTexture() const; - uint textureForPlane(int plane) const; - void updateTexture() const; + virtual QOpenGLTexture *toOpenGlTexture(int plane = 0) = 0; #endif - static bool hasContent(SurfaceBuffer *buffer) { return buffer && buffer->waylandBufferHandle(); } -private: + static bool hasContent(ClientBuffer *buffer) { return buffer && buffer->waylandBufferHandle(); } + +protected: void ref(); void deref(); - void destroyIfUnused(); + void sendRelease(); + void setDestroyed(); - QWaylandSurface *m_surface; - QWaylandCompositor *m_compositor; struct ::wl_resource *m_buffer; - int m_bufferScale; - struct surface_buffer_destroy_listener m_destroy_listener; + QRegion m_damage; + bool m_textureDirty; + +private: bool m_committed; - bool m_is_registered_for_buffer; - bool m_surface_has_buffer; bool m_destroyed; - bool m_is_displayed; - QAtomicInt m_refCount; - bool m_used; - bool m_destroyIfUnused; - - static void destroy_listener_callback(wl_listener *listener, void *data); friend class ::QWaylandBufferRef; + friend class BufferManager; +}; + +class Q_WAYLAND_COMPOSITOR_EXPORT SharedMemoryBuffer : public ClientBuffer +{ +public: + SharedMemoryBuffer(struct ::wl_resource *bufferResource); + + QSize size() const Q_DECL_OVERRIDE; + QWaylandSurface::Origin origin() const Q_DECL_OVERRIDE; + QImage image() const; + +#ifdef QT_WAYLAND_COMPOSITOR_GL + QOpenGLTexture *toOpenGlTexture(int plane = 0) Q_DECL_OVERRIDE; + +private: + QOpenGLTexture *m_shmTexture; +#endif }; } QT_END_NAMESPACE -#endif // SURFACEBUFFER_H +#endif // QWLCLIENTBUFFER_P_H diff --git a/src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp b/src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp deleted file mode 100644 index df2dded2f..000000000 --- a/src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtWaylandCompositor module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qwlsurfacebuffer_p.h" - -#ifdef QT_WAYLAND_COMPOSITOR_GL -#include "hardware_integration/qwlclientbufferintegration_p.h" -#include <qpa/qplatformopenglcontext.h> -#endif - -#include <QtCore/QDebug> - -#include <wayland-server-protocol.h> -#include "qwaylandsharedmemoryformathelper_p.h" - -#include <QtWaylandCompositor/private/qwaylandcompositor_p.h> - -QT_BEGIN_NAMESPACE - -namespace QtWayland { - -SurfaceBuffer::SurfaceBuffer(QWaylandSurface *surface) - : m_surface(surface) - , m_compositor(surface->compositor()) - , m_buffer(0) - , m_committed(false) - , m_is_registered_for_buffer(false) - , m_surface_has_buffer(false) - , m_destroyed(false) - , m_is_displayed(false) - , m_used(false) - , m_destroyIfUnused(false) -{ -} - -SurfaceBuffer::~SurfaceBuffer() -{ - if (m_is_registered_for_buffer) - destructBufferState(); -} - -void SurfaceBuffer::initialize(struct ::wl_resource *buffer) -{ - m_buffer = buffer; - m_committed = false; - m_is_registered_for_buffer = true; - m_surface_has_buffer = true; - m_is_displayed = false; - m_destroyed = false; - m_destroy_listener.surfaceBuffer = this; - m_destroy_listener.listener.notify = destroy_listener_callback; - if (buffer) { -#ifdef QT_WAYLAND_COMPOSITOR_GL - if (ClientBufferIntegration *integration = QWaylandCompositorPrivate::get(m_compositor)->clientBufferIntegration()) - integration->initializeBuffer(buffer); -#endif - wl_signal_add(&buffer->destroy_signal, &m_destroy_listener.listener); - } -} - -void SurfaceBuffer::destructBufferState() -{ - if (m_buffer) { - if (m_committed) - sendRelease(); - wl_list_remove(&m_destroy_listener.listener.link); - } - m_buffer = 0; - m_committed = false; - m_is_registered_for_buffer = false; - m_is_displayed = false; -} - -void SurfaceBuffer::sendRelease() -{ - Q_ASSERT(m_buffer); - wl_buffer_send_release(m_buffer); -} - -void SurfaceBuffer::disown() -{ - m_surface_has_buffer = false; - destructBufferState(); - destroyIfUnused(); -} - -void SurfaceBuffer::setDisplayed() -{ - m_is_displayed = true; -} - -void SurfaceBuffer::destroy_listener_callback(wl_listener *listener, void *data) -{ - Q_UNUSED(data); - struct surface_buffer_destroy_listener *destroy_listener = - reinterpret_cast<struct surface_buffer_destroy_listener *>(listener); - SurfaceBuffer *d = destroy_listener->surfaceBuffer; - - // Mark the buffer as destroyed and clear m_buffer right away to avoid - // touching it before it is properly cleaned up. - d->m_destroyed = true; - d->m_buffer = 0; -} - -void SurfaceBuffer::ref() -{ - m_used = m_refCount.ref(); -} - -void SurfaceBuffer::deref() -{ - m_used = m_refCount.deref(); - if (!m_used) - disown(); -} - -void SurfaceBuffer::setDestroyIfUnused(bool destroy) -{ - m_destroyIfUnused = destroy; - destroyIfUnused(); -} - -void SurfaceBuffer::destroyIfUnused() -{ - if (!m_used && m_destroyIfUnused) - delete this; -} - -QSize SurfaceBuffer::size() const -{ - if (!m_buffer) - return QSize(); - - if (wl_shm_buffer *shmBuffer = wl_shm_buffer_get(m_buffer)) { - int width = wl_shm_buffer_get_width(shmBuffer); - int height = wl_shm_buffer_get_height(shmBuffer); - return QSize(width, height); - } -#ifdef QT_WAYLAND_COMPOSITOR_GL - if (ClientBufferIntegration *integration = QWaylandCompositorPrivate::get(m_compositor)->clientBufferIntegration()) { - return integration->bufferSize(m_buffer); - } -#endif - - return QSize(); -} - -QWaylandSurface::Origin SurfaceBuffer::origin() const -{ - if (isSharedMemory()) { - return QWaylandSurface::OriginTopLeft; - } - -#ifdef QT_WAYLAND_COMPOSITOR_GL - if (ClientBufferIntegration *integration = QWaylandCompositorPrivate::get(m_compositor)->clientBufferIntegration()) { - return integration->origin(m_buffer); - } -#endif - return QWaylandSurface::OriginTopLeft; -} - -QImage SurfaceBuffer::image() const -{ - if (wl_shm_buffer *shmBuffer = wl_shm_buffer_get(m_buffer)) { - int width = wl_shm_buffer_get_width(shmBuffer); - int height = wl_shm_buffer_get_height(shmBuffer); - int bytesPerLine = wl_shm_buffer_get_stride(shmBuffer); - uchar *data = static_cast<uchar *>(wl_shm_buffer_get_data(shmBuffer)); - return QImage(data, width, height, bytesPerLine, QImage::Format_ARGB32_Premultiplied); - } - - return QImage(); -} - -QWaylandBufferRef::BufferFormatEgl SurfaceBuffer::bufferFormatEgl() const -{ - Q_ASSERT(isSharedMemory() == false); - -#ifdef QT_WAYLAND_COMPOSITOR_GL - if (QtWayland::ClientBufferIntegration *clientInt = QWaylandCompositorPrivate::get(m_compositor)->clientBufferIntegration()) - return clientInt->bufferFormat(m_buffer); -#endif - - return QWaylandBufferRef::BufferFormatEgl_Null; -} - -#ifdef QT_WAYLAND_COMPOSITOR_GL -void SurfaceBuffer::bindToTexture() const -{ - Q_ASSERT(m_compositor); - if (isSharedMemory()) { - QImage image = this->image(); - if (image.hasAlphaChannel()) { - if (image.format() != QImage::Format_RGBA8888) { - image = image.convertToFormat(QImage::Format_RGBA8888); - } - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image.constBits()); - } else { - if (image.format() != QImage::Format_RGBX8888) { - image = image.convertToFormat(QImage::Format_RGBX8888); - } - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width(), image.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, image.constBits()); - } - } else { - if (QtWayland::ClientBufferIntegration *clientInt = QWaylandCompositorPrivate::get(m_compositor)->clientBufferIntegration()) { - clientInt->bindTextureToBuffer(m_buffer); - } - } -} - -uint SurfaceBuffer::textureForPlane(int plane) const -{ - if (QtWayland::ClientBufferIntegration *clientInt = QWaylandCompositorPrivate::get(m_compositor)->clientBufferIntegration()) - return clientInt->textureForBuffer(m_buffer, plane); - - return 0; -} - -void SurfaceBuffer::updateTexture() const -{ - if (QtWayland::ClientBufferIntegration *clientInt = QWaylandCompositorPrivate::get(m_compositor)->clientBufferIntegration()) - clientInt->updateTextureForBuffer(m_buffer); -} -#endif - -} - -QT_END_NAMESPACE diff --git a/src/compositor/wayland_wrapper/wayland_wrapper.pri b/src/compositor/wayland_wrapper/wayland_wrapper.pri index f338ddc05..fa5d76291 100644 --- a/src/compositor/wayland_wrapper/wayland_wrapper.pri +++ b/src/compositor/wayland_wrapper/wayland_wrapper.pri @@ -3,21 +3,23 @@ WAYLANDSERVERSOURCES += \ ../3rdparty/protocol/wayland.xml \ HEADERS += \ + wayland_wrapper/qwlbuffermanager_p.h \ + wayland_wrapper/qwlclientbuffer_p.h \ wayland_wrapper/qwldatadevice_p.h \ wayland_wrapper/qwldatadevicemanager_p.h \ wayland_wrapper/qwldataoffer_p.h \ wayland_wrapper/qwldatasource_p.h \ wayland_wrapper/qwlregion_p.h \ - wayland_wrapper/qwlsurfacebuffer_p.h \ ../shared/qwaylandxkb_p.h \ SOURCES += \ + wayland_wrapper/qwlbuffermanager.cpp \ + wayland_wrapper/qwlclientbuffer.cpp \ wayland_wrapper/qwldatadevice.cpp \ wayland_wrapper/qwldatadevicemanager.cpp \ wayland_wrapper/qwldataoffer.cpp \ wayland_wrapper/qwldatasource.cpp \ wayland_wrapper/qwlregion.cpp \ - wayland_wrapper/qwlsurfacebuffer.cpp \ ../shared/qwaylandxkb.cpp \ INCLUDEPATH += wayland_wrapper diff --git a/src/hardwareintegration/compositor/brcm-egl/brcmeglintegration.cpp b/src/hardwareintegration/compositor/brcm-egl/brcmeglintegration.cpp index 508e88257..940ce82f5 100644 --- a/src/hardwareintegration/compositor/brcm-egl/brcmeglintegration.cpp +++ b/src/hardwareintegration/compositor/brcm-egl/brcmeglintegration.cpp @@ -40,6 +40,7 @@ #include <qpa/qplatformnativeinterface.h> #include <QtGui/QGuiApplication> #include <QtGui/QOpenGLContext> +#include <QOpenGLTexture> #include <qpa/qplatformscreen.h> #include <QtGui/QWindow> @@ -60,6 +61,9 @@ public: : egl_display(EGL_NO_DISPLAY) , valid(false) { } + + static BrcmEglIntegrationPrivate *get(BrcmEglIntegration *integration); + EGLDisplay egl_display; bool valid; PFNEGLQUERYGLOBALIMAGEBRCMPROC eglQueryGlobalImageBRCM; @@ -117,25 +121,46 @@ void BrcmEglIntegration::initializeHardware(struct ::wl_display *display) } } -void BrcmEglIntegration::bindTextureToBuffer(struct ::wl_resource *buffer) +QtWayland::ClientBuffer *BrcmEglIntegration::createBufferFor(wl_resource *buffer) { - Q_D(BrcmEglIntegration); + if (wl_shm_buffer_get(buffer)) + return nullptr; + return new BrcmEglClientBuffer(this, buffer); +} + +BrcmEglIntegrationPrivate *BrcmEglIntegrationPrivate::get(BrcmEglIntegration *integration) +{ + return integration->d_ptr.data(); +} + +QOpenGLTexture *BrcmEglClientBuffer::toOpenGlTexture(int plane) +{ + Q_UNUSED(plane); + + auto d = BrcmEglIntegrationPrivate::get(m_integration); if (!d->valid) { qWarning("bindTextureToBuffer failed!"); - return; + return nullptr; } - BrcmBuffer *brcmBuffer = BrcmBuffer::fromResource(buffer); + BrcmBuffer *brcmBuffer = BrcmBuffer::fromResource(m_buffer); if (!d->eglQueryGlobalImageBRCM(brcmBuffer->handle(), brcmBuffer->handle() + 2)) { qWarning("eglQueryGlobalImageBRCM failed!"); - return; + return nullptr; } EGLImageKHR image = d->eglCreateImageKHR(d->egl_display, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, (EGLClientBuffer)brcmBuffer->handle(), NULL); if (image == EGL_NO_IMAGE_KHR) qWarning("eglCreateImageKHR() failed: %x\n", eglGetError()); + if (!m_texture) { + m_texture = new QOpenGLTexture(QOpenGLTexture::Target2D); + m_texture->create(); + } + + m_texture->bind(); + d->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -144,6 +169,8 @@ void BrcmEglIntegration::bindTextureToBuffer(struct ::wl_resource *buffer) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); d->eglDestroyImageKHR(d->egl_display, image); + + return m_texture; } void BrcmEglIntegration::brcm_bind_resource(Resource *) @@ -155,11 +182,29 @@ void BrcmEglIntegration::brcm_create_buffer(Resource *resource, uint32_t id, int new BrcmBuffer(resource->client(), id, QSize(width, height), static_cast<EGLint *>(data->data), data->size / sizeof(EGLint)); } -QSize BrcmEglIntegration::bufferSize(struct ::wl_resource *buffer) const +BrcmEglClientBuffer::BrcmEglClientBuffer(BrcmEglIntegration *integration, wl_resource *buffer) + : ClientBuffer(buffer) + , m_integration(integration) + , m_texture(nullptr) +{ +} + +QWaylandBufferRef::BufferFormatEgl BrcmEglClientBuffer::bufferFormatEgl() const { - BrcmBuffer *brcmBuffer = BrcmBuffer::fromResource(buffer); + return QWaylandBufferRef::BufferFormatEgl_RGBA; +} +QSize BrcmEglClientBuffer::size() const +{ + BrcmBuffer *brcmBuffer = BrcmBuffer::fromResource(m_buffer); return brcmBuffer->size(); } +QWaylandSurface::Origin BrcmEglClientBuffer::origin() const +{ + BrcmBuffer *brcmBuffer = BrcmBuffer::fromResource(m_buffer); + return brcmBuffer->isYInverted() ? QWaylandSurface::OriginTopLeft : QWaylandSurface::OriginBottomLeft; +} + + QT_END_NAMESPACE diff --git a/src/hardwareintegration/compositor/brcm-egl/brcmeglintegration.h b/src/hardwareintegration/compositor/brcm-egl/brcmeglintegration.h index 48dd9c42e..a1d39e4fe 100644 --- a/src/hardwareintegration/compositor/brcm-egl/brcmeglintegration.h +++ b/src/hardwareintegration/compositor/brcm-egl/brcmeglintegration.h @@ -42,6 +42,8 @@ #include <QtCore/QScopedPointer> +#include <private/qwlclientbuffer_p.h> + QT_BEGIN_NAMESPACE class BrcmEglIntegrationPrivate; @@ -53,10 +55,7 @@ public: BrcmEglIntegration(); void initializeHardware(struct ::wl_display *display) Q_DECL_OVERRIDE; - - void bindTextureToBuffer(struct ::wl_resource *buffer) Q_DECL_OVERRIDE; - - QSize bufferSize(struct ::wl_resource *buffer) const Q_DECL_OVERRIDE; + QtWayland::ClientBuffer *createBufferFor(wl_resource *buffer) Q_DECL_OVERRIDE; protected: void brcm_bind_resource(Resource *resource) Q_DECL_OVERRIDE; @@ -67,6 +66,21 @@ private: QScopedPointer<BrcmEglIntegrationPrivate> d_ptr; }; +class BrcmEglClientBuffer : public QtWayland::ClientBuffer +{ +public: + BrcmEglClientBuffer(BrcmEglIntegration *integration, wl_resource *buffer); + + QWaylandBufferRef::BufferFormatEgl bufferFormatEgl() const Q_DECL_OVERRIDE; + QSize size() const Q_DECL_OVERRIDE; + QWaylandSurface::Origin origin() const Q_DECL_OVERRIDE; + QOpenGLTexture *toOpenGlTexture(int plane) Q_DECL_OVERRIDE; +private: + BrcmEglIntegration *m_integration; + QOpenGLTexture *m_texture; +}; + + QT_END_NAMESPACE #endif // BRCMEGLINTEGRATION_H diff --git a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp index 4416d103c..d71fce6ae 100644 --- a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp +++ b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp @@ -40,6 +40,7 @@ #include <qpa/qplatformnativeinterface.h> #include <QtGui/QGuiApplication> #include <QtGui/QOpenGLContext> +#include <QtGui/QOpenGLTexture> #include <qpa/qplatformscreen.h> #include <QtGui/QWindow> #include <QtCore/QPointer> @@ -90,6 +91,10 @@ #define EGL_TEXTURE_Y_XUXV_WL 0x31D9 #endif +#ifndef EGL_PLATFORM_X11_KHR +#define EGL_PLATFORM_X11_KHR 0x31D5 +#endif + /* Needed for compatibility with Mesa older than 10.0. */ typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYWAYLANDBUFFERWL_compat) (EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value); @@ -110,17 +115,50 @@ typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenu QT_BEGIN_NAMESPACE +static const char * +egl_error_string(EGLint code) +{ +#define MYERRCODE(x) case x: return #x; + switch (code) { + MYERRCODE(EGL_SUCCESS) + MYERRCODE(EGL_NOT_INITIALIZED) + MYERRCODE(EGL_BAD_ACCESS) + MYERRCODE(EGL_BAD_ALLOC) + MYERRCODE(EGL_BAD_ATTRIBUTE) + MYERRCODE(EGL_BAD_CONTEXT) + MYERRCODE(EGL_BAD_CONFIG) + MYERRCODE(EGL_BAD_CURRENT_SURFACE) + MYERRCODE(EGL_BAD_DISPLAY) + MYERRCODE(EGL_BAD_SURFACE) + MYERRCODE(EGL_BAD_MATCH) + MYERRCODE(EGL_BAD_PARAMETER) + MYERRCODE(EGL_BAD_NATIVE_PIXMAP) + MYERRCODE(EGL_BAD_NATIVE_WINDOW) + MYERRCODE(EGL_CONTEXT_LOST) + default: + return "unknown"; + } +#undef MYERRCODE +} + struct BufferState { BufferState(); + enum EglMode { + ModeNone, + ModeEGLImage, + ModeEGLStream + }; + EGLint egl_format; QVarLengthArray<EGLImageKHR, 3> egl_images; + QOpenGLTexture *textures[3]; EGLStreamKHR egl_stream; - GLuint eglstream_texture; bool isYInverted; QSize size; + EglMode eglMode; }; class WaylandEglClientBufferIntegrationPrivate @@ -128,18 +166,14 @@ class WaylandEglClientBufferIntegrationPrivate public: WaylandEglClientBufferIntegrationPrivate(); - void attach(struct ::wl_resource *buffer); - void attach_egl_texture(struct ::wl_resource *buffer, EGLint format); - void attach_egl_fd_texture(struct ::wl_resource *buffer, EGLNativeFileDescriptorKHR streamFd); + void initBuffer(WaylandEglClientBuffer *buffer); + void init_egl_texture(WaylandEglClientBuffer *buffer, EGLint format); + void init_egl_fd_texture(WaylandEglClientBuffer *buffer, EGLNativeFileDescriptorKHR streamFd); void register_buffer(struct ::wl_resource *buffer, BufferState state); - void bindBuffer(struct ::wl_resource *buffer); - - static void handle_buffer_destroy(wl_listener *listener, void *data); EGLDisplay egl_display; bool valid; bool display_bound; - QHash<struct ::wl_resource *, BufferState> buffers; PFNEGLBINDWAYLANDDISPLAYWL egl_bind_wayland_display; PFNEGLUNBINDWAYLANDDISPLAYWL egl_unbind_wayland_display; @@ -151,25 +185,16 @@ public: PFNGLEGLIMAGETARGETTEXTURE2DOESPROC gl_egl_image_target_texture_2d; QEGLStreamConvenience *funcs; -}; - -struct buffer_destroy_listener : wl_listener -{ - buffer_destroy_listener() - : d(0) - { - notify = WaylandEglClientBufferIntegrationPrivate::handle_buffer_destroy; - wl_list_init(&this->link); + static WaylandEglClientBufferIntegrationPrivate *get(WaylandEglClientBufferIntegration *integration) { + return integration->d_ptr.data(); } - - WaylandEglClientBufferIntegrationPrivate *d; }; BufferState::BufferState() : egl_format(EGL_TEXTURE_RGBA) , egl_stream(EGL_NO_STREAM_KHR) - , eglstream_texture(0) , isYInverted(true) + , eglMode(ModeNone) {} WaylandEglClientBufferIntegrationPrivate::WaylandEglClientBufferIntegrationPrivate() @@ -183,21 +208,21 @@ WaylandEglClientBufferIntegrationPrivate::WaylandEglClientBufferIntegrationPriva , egl_destroy_image(0) , gl_egl_image_target_texture_2d(0) , funcs(Q_NULLPTR) -{} +{ +} -void WaylandEglClientBufferIntegrationPrivate::attach(struct ::wl_resource *buffer) +void WaylandEglClientBufferIntegrationPrivate::initBuffer(WaylandEglClientBuffer *buffer) { EGLint format; - EGLNativeFileDescriptorKHR streamFd = EGL_NO_FILE_DESCRIPTOR_KHR; - if (egl_query_wayland_buffer(egl_display, buffer, EGL_TEXTURE_FORMAT, &format)) - attach_egl_texture(buffer, format); - else if (egl_query_wayland_buffer(egl_display, buffer, EGL_WAYLAND_BUFFER_WL, &streamFd)) - attach_egl_fd_texture(buffer, streamFd); + if (egl_query_wayland_buffer(egl_display, buffer->waylandBufferHandle(), EGL_TEXTURE_FORMAT, &format)) + init_egl_texture(buffer, format); } -void WaylandEglClientBufferIntegrationPrivate::attach_egl_texture(struct ::wl_resource *buffer, EGLint format) +void WaylandEglClientBufferIntegrationPrivate::init_egl_texture(WaylandEglClientBuffer *buffer, EGLint format) { +// Non-streaming case + // Resolving GL functions may need a context current, so do it only here. if (!gl_egl_image_target_texture_2d) gl_egl_image_target_texture_2d = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES")); @@ -207,12 +232,13 @@ void WaylandEglClientBufferIntegrationPrivate::attach_egl_texture(struct ::wl_re return; } - BufferState state; + BufferState &state = *buffer->d; state.egl_format = format; + state.eglMode = BufferState::ModeEGLImage; #if defined(EGL_WAYLAND_Y_INVERTED_WL) EGLint isYInverted; - EGLBoolean ret = egl_query_wayland_buffer(egl_display, buffer, EGL_WAYLAND_Y_INVERTED_WL, &isYInverted); + EGLBoolean ret = egl_query_wayland_buffer(egl_display, buffer->waylandBufferHandle(), EGL_WAYLAND_Y_INVERTED_WL, &isYInverted); // Yes, this looks strange, but the specification says that EGL_FALSE return // value (not supported) should be treated the same as EGL_TRUE return value // and EGL_TRUE in value. @@ -244,21 +270,21 @@ void WaylandEglClientBufferIntegrationPrivate::attach_egl_texture(struct ::wl_re EGLImageKHR image = egl_create_image(egl_display, EGL_NO_CONTEXT, EGL_WAYLAND_BUFFER_WL, - buffer, + buffer->waylandBufferHandle(), attribs); if (image == EGL_NO_IMAGE_KHR) qWarning("failed to create EGL image for plane %d", i); state.egl_images << image; + state.textures[i] = nullptr; } - - register_buffer(buffer, state); } -void WaylandEglClientBufferIntegrationPrivate::attach_egl_fd_texture(struct ::wl_resource *buffer, EGLNativeFileDescriptorKHR streamFd) +void WaylandEglClientBufferIntegrationPrivate::init_egl_fd_texture(WaylandEglClientBuffer *buffer, EGLNativeFileDescriptorKHR streamFd) { - BufferState state; +//EglStreams case + BufferState &state = *buffer->d; state.egl_format = EGL_TEXTURE_EXTERNAL_WL; state.isYInverted = false; @@ -270,106 +296,37 @@ void WaylandEglClientBufferIntegrationPrivate::attach_egl_fd_texture(struct ::wl qWarning("%s:%d: eglCreateStreamFromFileDescriptorKHR failed: 0x%x", Q_FUNC_INFO, __LINE__, eglGetError()); return; } + state.eglMode = BufferState::ModeEGLStream; if (!QOpenGLContext::currentContext()) qWarning("EglClientBufferIntegration: creating texture with no current context"); //TODO This texture might end up in a different context than the quick item which wants to use it, this needs to be fixed somehow. - glGenTextures(1, &state.eglstream_texture); + + auto texture = new QOpenGLTexture(static_cast<QOpenGLTexture::Target>(GL_TEXTURE_EXTERNAL_OES)); + texture->create(); + state.textures[0] = texture; // TODO: support multiple planes for the streaming case + glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_EXTERNAL_OES, state.eglstream_texture); + texture->create(); + texture->bind(); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture->textureId()); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - register_buffer(buffer, state); - - bindBuffer(buffer); -} - -void WaylandEglClientBufferIntegrationPrivate::register_buffer(struct ::wl_resource *buffer, BufferState state) -{ - Q_ASSERT(!buffers.contains(buffer)); - - EGLint width, height; - egl_query_wayland_buffer(egl_display, buffer, EGL_WIDTH, &width); - egl_query_wayland_buffer(egl_display, buffer, EGL_HEIGHT, &height); - state.size = QSize(width, height); - - buffers[buffer] = state; - - buffer_destroy_listener *destroy_listener = new buffer_destroy_listener; - destroy_listener->d = this; - wl_signal_add(&buffer->destroy_signal, destroy_listener); -} - -void WaylandEglClientBufferIntegrationPrivate::bindBuffer(struct ::wl_resource *buffer) -{ - if (!valid) { - qWarning("QtCompositor: bindTextureToBuffer() failed"); - return; - } + auto newStream = funcs->stream_consumer_gltexture(egl_display, state.egl_stream); - if (!buffer || !buffers.contains(buffer)) - return; - - const BufferState state = buffers.value(buffer); - - if (state.egl_stream != EGL_NO_STREAM_KHR) { - EGLint stream_state; - funcs->query_stream(egl_display, state.egl_stream, EGL_STREAM_STATE_KHR, &stream_state); - - if (stream_state == EGL_STREAM_STATE_CREATED_KHR) - if (funcs->stream_consumer_gltexture(egl_display, state.egl_stream) != EGL_TRUE) - qWarning("%s:%d: eglStreamConsumerGLTextureExternalKHR failed: 0x%x", Q_FUNC_INFO, __LINE__, eglGetError()); - } else { - GLint previousTexture = GL_TEXTURE0; - glGetIntegerv(GL_ACTIVE_TEXTURE, &previousTexture); - - const GLenum target = (state.egl_format == EGL_TEXTURE_EXTERNAL_WL) ? GL_TEXTURE_EXTERNAL_OES - : GL_TEXTURE_2D; - - for (int i = 0; i < state.egl_images.size(); i++) { - glActiveTexture(GL_TEXTURE0 + i); - glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - gl_egl_image_target_texture_2d(target, state.egl_images[i]); - } - - glActiveTexture(previousTexture); + if (!newStream) { + EGLint code = eglGetError(); + qWarning() << "Could not initialize EGLStream:" << egl_error_string(code) << hex << (long)code; + funcs->destroy_stream(egl_display, state.egl_stream); + state.egl_stream = EGL_NO_STREAM_KHR; } } -void WaylandEglClientBufferIntegrationPrivate::handle_buffer_destroy(wl_listener *listener, void *data) -{ - buffer_destroy_listener *destroy_listener = static_cast<buffer_destroy_listener *>(listener); - WaylandEglClientBufferIntegrationPrivate *self = destroy_listener->d; - struct ::wl_resource *buffer = static_cast<struct ::wl_resource *>(data); - - wl_list_remove(&destroy_listener->link); - delete destroy_listener; - - if (!self->buffers.contains(buffer)) - return; - - Q_ASSERT(self); - Q_ASSERT(buffer); - - BufferState state = self->buffers.take(buffer); - - // We would need to delete the texture of the egl_stream here, but we can't as this breaks the - // texture of the new stream when the window is resized. It seems wayland takes care to delete the texture for us. - - for (int i = 0; i < state.egl_images.size(); i++) - self->egl_destroy_image(self->egl_display, state.egl_images[i]); - - if (state.egl_stream != EGL_NO_STREAM_KHR) - self->funcs->destroy_stream(self->egl_display, state.egl_stream); -} - WaylandEglClientBufferIntegration::WaylandEglClientBufferIntegration() : QtWayland::ClientBufferIntegration() , d_ptr(new WaylandEglClientBufferIntegrationPrivate) @@ -438,17 +395,27 @@ void WaylandEglClientBufferIntegration::initializeHardware(struct wl_display *di d->valid = true; } -void WaylandEglClientBufferIntegration::initializeBuffer(struct ::wl_resource *buffer) +QtWayland::ClientBuffer *WaylandEglClientBufferIntegration::createBufferFor(wl_resource *buffer) { - Q_D(WaylandEglClientBufferIntegration); - if (wl_shm_buffer_get(buffer)) - return; - - if (!buffer || d->buffers.contains(buffer)) - return; + return nullptr; + return new WaylandEglClientBuffer(this, buffer); +} - d->attach(buffer); +WaylandEglClientBuffer::WaylandEglClientBuffer(WaylandEglClientBufferIntegration *integration, wl_resource *buffer) + : ClientBuffer(buffer) + , m_integration(integration) +{ + auto *p = WaylandEglClientBufferIntegrationPrivate::get(m_integration); + d = new BufferState; + if (buffer && !wl_shm_buffer_get(buffer)) { + EGLint width, height; + p->egl_query_wayland_buffer(p->egl_display, buffer, EGL_WIDTH, &width); + p->egl_query_wayland_buffer(p->egl_display, buffer, EGL_HEIGHT, &height); + d->size = QSize(width, height); + + p->initBuffer(this); + } } static QWaylandBufferRef::BufferFormatEgl formatFromEglFormat(EGLint format) { @@ -470,117 +437,92 @@ static QWaylandBufferRef::BufferFormatEgl formatFromEglFormat(EGLint format) { return QWaylandBufferRef::BufferFormatEgl_RGBA; } -QWaylandBufferRef::BufferFormatEgl WaylandEglClientBufferIntegration::bufferFormat(wl_resource *buffer) -{ - Q_D(const WaylandEglClientBufferIntegration); - return formatFromEglFormat(d->buffers.value(buffer).egl_format); -} - -uint WaylandEglClientBufferIntegration::textureForBuffer(wl_resource *buffer, int plane) +QWaylandBufferRef::BufferFormatEgl WaylandEglClientBuffer::bufferFormatEgl() const { - Q_UNUSED(plane) - Q_D(WaylandEglClientBufferIntegration); - if (!buffer) - return 0; - - const BufferState state = d->buffers.value(buffer); - return state.eglstream_texture; + return formatFromEglFormat(d->egl_format); } -void WaylandEglClientBufferIntegration::bindTextureToBuffer(struct ::wl_resource *buffer) +QOpenGLTexture *WaylandEglClientBuffer::toOpenGlTexture(int plane) { - Q_D(WaylandEglClientBufferIntegration); - d->bindBuffer(buffer); -} - -// Update is only needed for the EGLStream path as that requires calling acquire -// on every frame. bindTextureToBuffer() is typically invoked only upon attach -// so that is insufficient. -void WaylandEglClientBufferIntegration::updateTextureForBuffer(struct ::wl_resource *buffer) -{ - Q_D(WaylandEglClientBufferIntegration); - if (!d->valid) { - qWarning("QtCompositor: updateTextureForBuffer() failed"); - return; + if (!m_buffer) + return nullptr; + + auto *p = WaylandEglClientBufferIntegrationPrivate::get(m_integration); + auto texture = d->textures[plane]; + const auto target = static_cast<QOpenGLTexture::Target>((d->eglMode == BufferState::ModeEGLStream || d->egl_format == EGL_TEXTURE_EXTERNAL_WL) ? GL_TEXTURE_EXTERNAL_OES + : GL_TEXTURE_2D); + if (!texture) { + texture = new QOpenGLTexture(target); + texture->create(); + d->textures[plane] = texture; } - if (!buffer) - return; - const BufferState state = d->buffers.value(buffer); + if (d->eglMode == BufferState::ModeEGLStream) { + // EGLStream requires calling acquire on every frame. + if (d->egl_stream != EGL_NO_STREAM_KHR) { + + texture->bind(); - if (state.egl_stream != EGL_NO_STREAM_KHR) { - EGLint stream_state; - d->funcs->query_stream(d->egl_display, state.egl_stream, EGL_STREAM_STATE_KHR, &stream_state); + EGLint stream_state; + p->funcs->query_stream(p->egl_display, d->egl_stream, EGL_STREAM_STATE_KHR, &stream_state); - if (stream_state == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR) { - if (d->funcs->stream_consumer_acquire(d->egl_display, state.egl_stream) != EGL_TRUE) - qWarning("%s:%d: eglStreamConsumerAcquireKHR failed: 0x%x", Q_FUNC_INFO, __LINE__, eglGetError()); + if (stream_state == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR) { + if (p->funcs->stream_consumer_acquire(p->egl_display, d->egl_stream) != EGL_TRUE) + qWarning("%s:%d: eglStreamConsumerAcquireKHR failed: 0x%x", Q_FUNC_INFO, __LINE__, eglGetError()); + } } + } else if (m_textureDirty) { + texture->bind(); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + p->gl_egl_image_target_texture_2d(target, d->egl_images[plane]); } + return texture; } -QWaylandSurface::Origin WaylandEglClientBufferIntegration::origin(struct ::wl_resource *buffer) const +void WaylandEglClientBuffer::setCommitted(QRegion &damage) { - Q_D(const WaylandEglClientBufferIntegration); - - if (d->buffers.contains(buffer)) - return d->buffers[buffer].isYInverted ? QWaylandSurface::OriginTopLeft : QWaylandSurface::OriginBottomLeft; - -#if defined(EGL_WAYLAND_Y_INVERTED_WL) - EGLint isYInverted; - EGLBoolean ret = EGL_FALSE; - if (buffer) - ret = d->egl_query_wayland_buffer(d->egl_display, buffer, EGL_WAYLAND_Y_INVERTED_WL, &isYInverted); - // Yes, this looks strange, but the specification says that EGL_FALSE return - // value (not supported) should be treated the same as EGL_TRUE return value - // and EGL_TRUE in value. - if (ret == EGL_FALSE || isYInverted == EGL_TRUE) - return QWaylandSurface::OriginTopLeft; - return QWaylandSurface::OriginBottomLeft; -#endif - - return QtWayland::ClientBufferIntegration::origin(buffer); + ClientBuffer::setCommitted(damage); + if (d->eglMode == BufferState::ModeNone) { + EGLNativeFileDescriptorKHR streamFd = EGL_NO_FILE_DESCRIPTOR_KHR; + auto *p = WaylandEglClientBufferIntegrationPrivate::get(m_integration); + if (p->egl_query_wayland_buffer(p->egl_display, waylandBufferHandle(), EGL_WAYLAND_BUFFER_WL, &streamFd)) + p->init_egl_fd_texture(this, streamFd); + } } +QWaylandSurface::Origin WaylandEglClientBuffer::origin() const +{ + return d->isYInverted ? QWaylandSurface::OriginTopLeft : QWaylandSurface::OriginBottomLeft; +} -void *WaylandEglClientBufferIntegration::lockNativeBuffer(struct ::wl_resource *buffer) const +void *WaylandEglClientBuffer::lockNativeBuffer() { - Q_D(const WaylandEglClientBufferIntegration); + auto *p = WaylandEglClientBufferIntegrationPrivate::get(m_integration); - if (d->buffers.contains(buffer) && d->buffers[buffer].egl_stream != EGL_NO_STREAM_KHR) - return 0; + if (d->egl_stream != EGL_NO_STREAM_KHR) + return nullptr; - EGLImageKHR image = d->egl_create_image(d->egl_display, EGL_NO_CONTEXT, + EGLImageKHR image = p->egl_create_image(p->egl_display, EGL_NO_CONTEXT, EGL_WAYLAND_BUFFER_WL, - buffer, NULL); + m_buffer, NULL); return image; } -void WaylandEglClientBufferIntegration::unlockNativeBuffer(void *native_buffer) const +void WaylandEglClientBuffer::unlockNativeBuffer(void *native_buffer) const { - Q_D(const WaylandEglClientBufferIntegration); - if (!native_buffer) return; + auto *p = WaylandEglClientBufferIntegrationPrivate::get(m_integration); + EGLImageKHR image = static_cast<EGLImageKHR>(native_buffer); - d->egl_destroy_image(d->egl_display, image); + p->egl_destroy_image(p->egl_display, image); } -QSize WaylandEglClientBufferIntegration::bufferSize(struct ::wl_resource *buffer) const +QSize WaylandEglClientBuffer::size() const { - Q_D(const WaylandEglClientBufferIntegration); - - if (d->buffers.contains(buffer)) { - return d->buffers[buffer].size; - } else { - int width, height; - d->egl_query_wayland_buffer(d->egl_display, buffer, EGL_WIDTH, &width); - d->egl_query_wayland_buffer(d->egl_display, buffer, EGL_HEIGHT, &height); - - return QSize(width, height); - } + return d->size; } QT_END_NAMESPACE diff --git a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.h b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.h index 74cad708d..5385ac25f 100644 --- a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.h +++ b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.h @@ -39,6 +39,7 @@ #include <QtWaylandCompositor/private/qwlclientbufferintegration_p.h> #include <QtCore/QScopedPointer> +#include <QtWaylandCompositor/private/qwlclientbuffer_p.h> QT_BEGIN_NAMESPACE @@ -52,22 +53,34 @@ public: void initializeHardware(struct ::wl_display *display) Q_DECL_OVERRIDE; - void initializeBuffer(struct ::wl_resource *buffer) Q_DECL_OVERRIDE; - QWaylandBufferRef::BufferFormatEgl bufferFormat(struct ::wl_resource *buffer) Q_DECL_OVERRIDE; - uint textureForBuffer(struct ::wl_resource *buffer, int plane) Q_DECL_OVERRIDE; - void bindTextureToBuffer(struct ::wl_resource *buffer) Q_DECL_OVERRIDE; - void updateTextureForBuffer(struct ::wl_resource *buffer) Q_DECL_OVERRIDE; + QtWayland::ClientBuffer *createBufferFor(wl_resource *buffer); - QWaylandSurface::Origin origin(struct ::wl_resource *) const Q_DECL_OVERRIDE; +private: + Q_DISABLE_COPY(WaylandEglClientBufferIntegration) + QScopedPointer<WaylandEglClientBufferIntegrationPrivate> d_ptr; +}; - void *lockNativeBuffer(struct ::wl_resource *buffer) const Q_DECL_OVERRIDE; - void unlockNativeBuffer(void *native_buffer) const Q_DECL_OVERRIDE; +struct BufferState; - QSize bufferSize(struct ::wl_resource *buffer) const Q_DECL_OVERRIDE; +class WaylandEglClientBuffer : public QtWayland::ClientBuffer +{ +public: + QWaylandBufferRef::BufferFormatEgl bufferFormatEgl() const Q_DECL_OVERRIDE; + QSize size() const Q_DECL_OVERRIDE; + QWaylandSurface::Origin origin() const Q_DECL_OVERRIDE; + void *lockNativeBuffer() Q_DECL_OVERRIDE; + void unlockNativeBuffer(void *native_buffer) const Q_DECL_OVERRIDE; + QOpenGLTexture *toOpenGlTexture(int plane) Q_DECL_OVERRIDE; + void setCommitted(QRegion &damage) Q_DECL_OVERRIDE; private: - Q_DISABLE_COPY(WaylandEglClientBufferIntegration) - QScopedPointer<WaylandEglClientBufferIntegrationPrivate> d_ptr; + friend class WaylandEglClientBufferIntegration; + friend class WaylandEglClientBufferIntegrationPrivate; + + WaylandEglClientBuffer(WaylandEglClientBufferIntegration* integration, wl_resource *bufferResource); + + BufferState *d; + WaylandEglClientBufferIntegration *m_integration; }; QT_END_NAMESPACE diff --git a/src/hardwareintegration/compositor/xcomposite-egl/xcompositeeglintegration.cpp b/src/hardwareintegration/compositor/xcomposite-egl/xcompositeeglintegration.cpp index e858a8e78..1a478052b 100644 --- a/src/hardwareintegration/compositor/xcomposite-egl/xcompositeeglintegration.cpp +++ b/src/hardwareintegration/compositor/xcomposite-egl/xcompositeeglintegration.cpp @@ -40,6 +40,7 @@ #include <QtWaylandCompositor/QWaylandCompositor> #include <QtGui/QGuiApplication> +#include <QtGui/QOpenGLTexture> #include <qpa/qplatformnativeinterface.h> #include <qpa/qplatformopenglcontext.h> @@ -83,23 +84,38 @@ void XCompositeEglClientBufferIntegration::initializeHardware(struct ::wl_displa } else { qFatal("Platform integration doesn't have native interface"); } - mScreen = XDefaultScreen(mDisplay); new XCompositeHandler(m_compositor, mDisplay); } -void XCompositeEglClientBufferIntegration::bindTextureToBuffer(struct ::wl_resource *buffer) +QtWayland::ClientBuffer *XCompositeEglClientBufferIntegration::createBufferFor(wl_resource *buffer) { - XCompositeBuffer *compositorBuffer = XCompositeBuffer::fromResource(buffer); - Pixmap pixmap = XCompositeNameWindowPixmap(mDisplay, compositorBuffer->window()); + if (wl_shm_buffer_get(buffer)) + return nullptr; + return new XCompositeEglClientBuffer(this, buffer); +} + + +XCompositeEglClientBuffer::XCompositeEglClientBuffer(XCompositeEglClientBufferIntegration *integration, wl_resource *bufferResource) + : QtWayland::ClientBuffer(bufferResource) + , m_texture(nullptr) + , m_integration(integration) +{ +} + +QOpenGLTexture *XCompositeEglClientBuffer::toOpenGlTexture(int plane) +{ + Q_UNUSED(plane); + XCompositeBuffer *compositorBuffer = XCompositeBuffer::fromResource(m_buffer); + Pixmap pixmap = XCompositeNameWindowPixmap(m_integration->xDisplay(), compositorBuffer->window()); QVector<EGLint> eglConfigSpec = eglbuildSpec(); EGLint matching = 0; EGLConfig config; - bool matched = eglChooseConfig(mEglDisplay,eglConfigSpec.constData(),&config,1,&matching); + bool matched = eglChooseConfig(m_integration->eglDisplay(),eglConfigSpec.constData(),&config,1,&matching); if (!matched || !matching) { qWarning("Could not retrieve a suitable EGL config"); - return; + return nullptr; } QVector<EGLint> attribList; @@ -110,29 +126,37 @@ void XCompositeEglClientBufferIntegration::bindTextureToBuffer(struct ::wl_resou attribList.append(EGL_TEXTURE_2D); attribList.append(EGL_NONE); - EGLSurface surface = eglCreatePixmapSurface(mEglDisplay,config,pixmap,attribList.constData()); + EGLSurface surface = eglCreatePixmapSurface(m_integration->eglDisplay(),config,pixmap,attribList.constData()); if (surface == EGL_NO_SURFACE) { qDebug() << "Failed to create eglsurface" << pixmap << compositorBuffer->window(); } compositorBuffer->setOrigin(QWaylandSurface::OriginTopLeft); - if (!eglBindTexImage(mEglDisplay,surface,EGL_BACK_BUFFER)) { - qDebug() << "Failed to bind"; + if (!m_texture) { + m_texture = new QOpenGLTexture(QOpenGLTexture::Target2D); + m_texture->create(); + } + m_texture->bind(); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + if (!eglBindTexImage(m_integration->eglDisplay(),surface,EGL_BACK_BUFFER)) { + qWarning() << "Failed to bind"; } // eglDestroySurface(mEglDisplay,surface); + return m_texture; } -QWaylandSurface::Origin XCompositeEglClientBufferIntegration::origin(struct ::wl_resource *buffer) const + +QWaylandSurface::Origin XCompositeEglClientBuffer::origin() const { - XCompositeBuffer *compositorBuffer = XCompositeBuffer::fromResource(buffer); + XCompositeBuffer *compositorBuffer = XCompositeBuffer::fromResource(m_buffer); return compositorBuffer->origin(); } -QSize XCompositeEglClientBufferIntegration::bufferSize(struct ::wl_resource *buffer) const +QSize XCompositeEglClientBuffer::size() const { - XCompositeBuffer *compositorBuffer = XCompositeBuffer::fromResource(buffer); + XCompositeBuffer *compositorBuffer = XCompositeBuffer::fromResource(m_buffer); return compositorBuffer->size(); } diff --git a/src/hardwareintegration/compositor/xcomposite-egl/xcompositeeglintegration.h b/src/hardwareintegration/compositor/xcomposite-egl/xcompositeeglintegration.h index c14e582ed..ec4ea284b 100644 --- a/src/hardwareintegration/compositor/xcomposite-egl/xcompositeeglintegration.h +++ b/src/hardwareintegration/compositor/xcomposite-egl/xcompositeeglintegration.h @@ -40,7 +40,7 @@ #include <QtWaylandCompositor/private/qwlclientbufferintegration_p.h> #include <QtWaylandCompositor/QWaylandCompositor> - +#include <QtWaylandCompositor/private/qwlclientbuffer_p.h> #include "xlibinclude.h" #include <EGL/egl.h> @@ -53,16 +53,30 @@ public: XCompositeEglClientBufferIntegration(); void initializeHardware(struct ::wl_display *display) Q_DECL_OVERRIDE; - - void bindTextureToBuffer(struct ::wl_resource *buffer) Q_DECL_OVERRIDE; - QWaylandSurface::Origin origin(struct ::wl_resource *) const Q_DECL_OVERRIDE; - - QSize bufferSize(struct ::wl_resource *buffer) const Q_DECL_OVERRIDE; + QtWayland::ClientBuffer *createBufferFor(wl_resource *buffer) Q_DECL_OVERRIDE; + inline Display *xDisplay() const { return mDisplay; } + inline EGLDisplay eglDisplay() const { return mEglDisplay; } private: Display *mDisplay; EGLDisplay mEglDisplay; - int mScreen; +}; + +class XCompositeEglClientBuffer : public QtWayland::ClientBuffer +{ +public: + XCompositeEglClientBuffer(XCompositeEglClientBufferIntegration *integration, wl_resource *bufferResource); + + QSize size() const; + QWaylandSurface::Origin origin() const; + QOpenGLTexture *toOpenGlTexture(int plane) Q_DECL_OVERRIDE; + QWaylandBufferRef::BufferFormatEgl bufferFormatEgl() const Q_DECL_OVERRIDE { + return QWaylandBufferRef::BufferFormatEgl_RGBA; + } + +private: + QOpenGLTexture *m_texture; + XCompositeEglClientBufferIntegration *m_integration; }; QT_END_NAMESPACE diff --git a/src/hardwareintegration/compositor/xcomposite-glx/xcompositeglxintegration.cpp b/src/hardwareintegration/compositor/xcomposite-glx/xcompositeglxintegration.cpp index 6f70d2bbf..0b11c2630 100644 --- a/src/hardwareintegration/compositor/xcomposite-glx/xcompositeglxintegration.cpp +++ b/src/hardwareintegration/compositor/xcomposite-glx/xcompositeglxintegration.cpp @@ -41,6 +41,7 @@ #include <qpa/qplatformnativeinterface.h> #include <qpa/qplatformintegration.h> #include <QtGui/QOpenGLContext> +#include <QtGui/QOpenGLTexture> #include "xcompositebuffer.h" #include "xcompositehandler.h" @@ -109,14 +110,31 @@ void XCompositeGLXClientBufferIntegration::initializeHardware(struct ::wl_displa delete glContext; } -void XCompositeGLXClientBufferIntegration::bindTextureToBuffer(struct ::wl_resource *buffer) +QtWayland::ClientBuffer *XCompositeGLXClientBufferIntegration::createBufferFor(wl_resource *buffer) { - XCompositeBuffer *compositorBuffer = XCompositeBuffer::fromResource(buffer); - Pixmap pixmap = XCompositeNameWindowPixmap(mDisplay, compositorBuffer->window()); + if (wl_shm_buffer_get(buffer)) + return nullptr; + return new XCompositeGLXClientBuffer(this, buffer); +} + +XCompositeGLXClientBuffer::XCompositeGLXClientBuffer(XCompositeGLXClientBufferIntegration *integration, wl_resource *bufferResource) + : QtWayland::ClientBuffer(bufferResource) + , m_texture(nullptr) + , m_integration(integration) + , m_glxPixmap(0) +{ +} + + +QOpenGLTexture *XCompositeGLXClientBuffer::toOpenGlTexture(int plane) +{ + Q_UNUSED(plane); + XCompositeBuffer *compositorBuffer = XCompositeBuffer::fromResource(m_buffer); + Pixmap pixmap = XCompositeNameWindowPixmap(m_integration->xDisplay(), compositorBuffer->window()); QVector<int> glxConfigSpec = qglx_buildSpec(); int numberOfConfigs; - GLXFBConfig *configs = glXChooseFBConfig(mDisplay,mScreen,glxConfigSpec.constData(),&numberOfConfigs); + GLXFBConfig *configs = glXChooseFBConfig(m_integration->xDisplay(),m_integration->xScreen(),glxConfigSpec.constData(),&numberOfConfigs); QVector<int> attribList; attribList.append(GLX_TEXTURE_FORMAT_EXT); @@ -124,28 +142,40 @@ void XCompositeGLXClientBufferIntegration::bindTextureToBuffer(struct ::wl_resou attribList.append(GLX_TEXTURE_TARGET_EXT); attribList.append(GLX_TEXTURE_2D_EXT); attribList.append(0); - GLXPixmap glxPixmap = glXCreatePixmap(mDisplay,*configs,pixmap,attribList.constData()); + + if (!m_glxPixmap) + m_glxPixmap = glXCreatePixmap(m_integration->xDisplay(), *configs, pixmap, attribList.constData()); uint inverted = 0; - glXQueryDrawable(mDisplay, glxPixmap, GLX_Y_INVERTED_EXT,&inverted); + glXQueryDrawable(m_integration->xDisplay(), m_glxPixmap, GLX_Y_INVERTED_EXT,&inverted); compositorBuffer->setOrigin(inverted ? QWaylandSurface::OriginBottomLeft : QWaylandSurface::OriginTopLeft); XFree(configs); + auto tex = m_texture; + if (!m_texture) { + tex = new QOpenGLTexture(QOpenGLTexture::Target2D); + tex->create(); + m_texture = tex; + } + tex->bind(); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + m_integration->m_glxBindTexImageEXT(m_integration->xDisplay(),m_glxPixmap,GLX_FRONT_EXT, 0); - m_glxBindTexImageEXT(mDisplay,glxPixmap,GLX_FRONT_EXT, 0); - //Do we need to change the api so that we do bind and release in the painevent? - //The specification states that when deleting the texture the color buffer is deleted -// m_glxReleaseTexImageEXT(mDisplay,glxPixmap,GLX_FRONT_EXT); + // TODO: release in the destructor? + // m_glxReleaseTexImageEXT(mDisplay,glxPixmap,GLX_FRONT_EXT); + return tex; } -QWaylandSurface::Origin XCompositeGLXClientBufferIntegration::origin(struct ::wl_resource *buffer) const + +QWaylandSurface::Origin XCompositeGLXClientBuffer::origin() const { - return XCompositeBuffer::fromResource(buffer)->origin(); + XCompositeBuffer *compositorBuffer = XCompositeBuffer::fromResource(m_buffer); + return compositorBuffer->origin(); } -QSize XCompositeGLXClientBufferIntegration::bufferSize(struct ::wl_resource *buffer) const +QSize XCompositeGLXClientBuffer::size() const { - XCompositeBuffer *compositorBuffer = XCompositeBuffer::fromResource(buffer); + XCompositeBuffer *compositorBuffer = XCompositeBuffer::fromResource(m_buffer); return compositorBuffer->size(); } diff --git a/src/hardwareintegration/compositor/xcomposite-glx/xcompositeglxintegration.h b/src/hardwareintegration/compositor/xcomposite-glx/xcompositeglxintegration.h index 9caeb4645..7b63f976e 100644 --- a/src/hardwareintegration/compositor/xcomposite-glx/xcompositeglxintegration.h +++ b/src/hardwareintegration/compositor/xcomposite-glx/xcompositeglxintegration.h @@ -38,7 +38,7 @@ #define XCOMPOSITEGLXINTEGRATION_H #include <QtWaylandCompositor/private/qwlclientbufferintegration_p.h> - +#include <QtWaylandCompositor/private/qwlclientbuffer_p.h> #include "xlibinclude.h" #define GLX_GLXEXT_PROTOTYPES @@ -56,21 +56,38 @@ public: ~XCompositeGLXClientBufferIntegration(); void initializeHardware(struct ::wl_display *display) Q_DECL_OVERRIDE; + QtWayland::ClientBuffer *createBufferFor(wl_resource *buffer) Q_DECL_OVERRIDE; - void bindTextureToBuffer(struct ::wl_resource *buffer) Q_DECL_OVERRIDE; - QWaylandSurface::Origin origin(struct ::wl_resource *) const Q_DECL_OVERRIDE; - - QSize bufferSize(struct ::wl_resource *buffer) const Q_DECL_OVERRIDE; + inline Display *xDisplay() const { return mDisplay; } + inline int xScreen() const { return mScreen; } -private: PFNGLXBINDTEXIMAGEEXTPROC m_glxBindTexImageEXT; PFNGLXRELEASETEXIMAGEEXTPROC m_glxReleaseTexImageEXT; +private: Display *mDisplay; int mScreen; XCompositeHandler *mHandler; }; +class XCompositeGLXClientBuffer : public QtWayland::ClientBuffer +{ +public: + XCompositeGLXClientBuffer(XCompositeGLXClientBufferIntegration *integration, wl_resource *bufferResource); + + QSize size() const; + QWaylandSurface::Origin origin() const; + QOpenGLTexture *toOpenGlTexture(int plane) Q_DECL_OVERRIDE; + QWaylandBufferRef::BufferFormatEgl bufferFormatEgl() const Q_DECL_OVERRIDE { + return QWaylandBufferRef::BufferFormatEgl_RGBA; + } + +private: + QOpenGLTexture *m_texture; + XCompositeGLXClientBufferIntegration *m_integration; + GLXPixmap m_glxPixmap; +}; + QT_END_NAMESPACE #endif // XCOMPOSITEGLXINTEGRATION_H |