diff options
Diffstat (limited to 'src/compositor')
18 files changed, 551 insertions, 485 deletions
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 |