diff options
author | Gunnar Sletta <gunnar.sletta@jollamobile.com> | 2014-01-18 07:40:21 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-01-21 14:09:18 +0100 |
commit | 36ff0f303b79dcd7aae93d5a73dfc1f179ac5560 (patch) | |
tree | 786453094160454edd96020901ef63a9bf9a0905 | |
parent | bbf7285b669b105c7ccb6629d963b5e2584453d8 (diff) | |
download | qtwayland-36ff0f303b79dcd7aae93d5a73dfc1f179ac5560.tar.gz qtwayland-36ff0f303b79dcd7aae93d5a73dfc1f179ac5560.tar.bz2 qtwayland-36ff0f303b79dcd7aae93d5a73dfc1f179ac5560.zip |
Fix buffer handling.
The surface now has a distinct back and front buffer. Front means it
is on the screen and being used as a texture. Back means it should be
put to screen in the next updatePaintNode().
For the purpose of QML and GUI-thread properties, the 'back' buffer is
what contains the correct properties as it is what it will eventually
be rendered with. For the purpose of rendering, the front buffer
contains the right texture. If no back buffer is present, then there
was no changes and front buffer applies to both.
The Surface's buffer queue has been updated to only fire damage and
advance once we swap back buffer to front buffer which happens during
updatePaintNode(). The fact that the buffer advancing happens during
sync also means that we are releasing buffers back to the client as
soon as another buffer is ready to be displayed in the compositor.
This is "half a frame" earlier than the current implementation (which
releases after the next swap). We consider this safe because:
- The compositor has a new buffer to display and does not need the
old one.
- If the GPU is not done rasterizing the scanout buffer for the
previous frame, it should hold a read-lock on the buffer so
preventing the client from starting a render to it. If this
assumption fails on any hardware we can make the time of
buffer-advance optional. Either during "sync" or during "after
rendering" as it is today, but "after rendering" will not offer any
guarantee, just more time, resulting in a higher chance of the
buffers being ready. Aka, without an internal read-lock and no
fence mechanism, there is no guarantee.
Texture cleanup is now explicit as we have a well defined location to
clean up textures, during updatePaintNode(). This avoids cleanup
issues which previously existed as buffer cleanup was happening on the
GUI thread. Surface and Buffer destruction coming over wayland is
queued up in compositor and handled before the next "sync", when it is
safe to do so.
The change also removes doUpdate, postBuffer and frameSwappedInternal
as these are no longer used. Direct rendering will need to be
considered in a new light with the new buffering scheme, and anyway
needs work.
Change-Id: I2db0385b4b8859f96caba374f3530448178e1473
Reviewed-by: Robin Burchell <robin+qt@viroteck.net>
Reviewed-by: Laszlo Agocs <laszlo.agocs@digia.com>
-rw-r--r-- | examples/qwidget-compositor/main.cpp | 13 | ||||
-rw-r--r-- | examples/qwindow-compositor/qwindowcompositor.cpp | 23 | ||||
-rw-r--r-- | examples/qwindow-compositor/qwindowcompositor.h | 2 | ||||
-rw-r--r-- | src/compositor/compositor_api/qwaylandcompositor.cpp | 5 | ||||
-rw-r--r-- | src/compositor/compositor_api/qwaylandcompositor.h | 2 | ||||
-rw-r--r-- | src/compositor/compositor_api/qwaylandsurface.cpp | 6 | ||||
-rw-r--r-- | src/compositor/compositor_api/qwaylandsurface.h | 2 | ||||
-rw-r--r-- | src/compositor/compositor_api/qwaylandsurfaceitem.cpp | 10 | ||||
-rw-r--r-- | src/compositor/wayland_wrapper/qwlcompositor.cpp | 35 | ||||
-rw-r--r-- | src/compositor/wayland_wrapper/qwlcompositor_p.h | 10 | ||||
-rw-r--r-- | src/compositor/wayland_wrapper/qwlsurface.cpp | 172 | ||||
-rw-r--r-- | src/compositor/wayland_wrapper/qwlsurface_p.h | 8 | ||||
-rw-r--r-- | src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp | 52 | ||||
-rw-r--r-- | src/compositor/wayland_wrapper/qwlsurfacebuffer_p.h | 6 |
14 files changed, 175 insertions, 171 deletions
diff --git a/examples/qwidget-compositor/main.cpp b/examples/qwidget-compositor/main.cpp index 2c58fe98..1badb06a 100644 --- a/examples/qwidget-compositor/main.cpp +++ b/examples/qwidget-compositor/main.cpp @@ -139,6 +139,9 @@ protected: GLuint texture = 0; QOpenGLFunctions *functions = QOpenGLContext::currentContext()->functions(); + QSize windowSize = surface->size(); + surface->advanceBufferQueue(); + if (!m_surfaceCompositorFbo) functions->glGenFramebuffers(1,&m_surfaceCompositorFbo); @@ -152,7 +155,7 @@ protected: functions->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); - paintChildren(surface,surface); + paintChildren(surface,surface,windowSize); functions->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); @@ -160,7 +163,7 @@ protected: return texture; } - void paintChildren(QWaylandSurface *surface, QWaylandSurface *window) { + void paintChildren(QWaylandSurface *surface, QWaylandSurface *window, const QSize &windowSize) { if (surface->subSurfaces().size() == 0) return; @@ -170,6 +173,7 @@ protected: QWaylandSurface *subSurface = i.next(); QPointF p = subSurface->mapTo(window,QPoint(0,0)); QSize size = subSurface->size(); + subSurface->advanceBufferQueue(); if (size.isValid()) { GLuint texture = 0; if (subSurface->type() == QWaylandSurface::Texture) { @@ -177,9 +181,9 @@ protected: } else if (surface->type() == QWaylandSurface::Shm ) { texture = m_textureCache->bindTexture(context()->contextHandle(), surface->image()); } - m_textureBlitter->drawTexture(texture,QRect(p.toPoint(),size),window->size(),0,window->isYInverted(),subSurface->isYInverted()); + m_textureBlitter->drawTexture(texture,QRect(p.toPoint(),size),windowSize,0,window->isYInverted(),subSurface->isYInverted()); } - paintChildren(subSurface,window); + paintChildren(subSurface,window,windowSize); } } #else //hmmm, this is actually untested :( @@ -220,6 +224,7 @@ protected: p.drawPixmap(rect(), m_backgroundScaled); #ifdef QT_COMPOSITOR_WAYLAND_GL + cleanupGraphicsResources(); if (!m_textureCache) { m_textureCache = new QOpenGLTextureCache(context()->contextHandle()); } diff --git a/examples/qwindow-compositor/qwindowcompositor.cpp b/examples/qwindow-compositor/qwindowcompositor.cpp index 79d5b111..19f7ce5e 100644 --- a/examples/qwindow-compositor/qwindowcompositor.cpp +++ b/examples/qwindow-compositor/qwindowcompositor.cpp @@ -252,6 +252,9 @@ GLuint QWindowCompositor::composeSurface(QWaylandSurface *surface, bool *texture { GLuint texture = 0; + QSize windowSize = surface->size(); + surface->advanceBufferQueue(); + QOpenGLFunctions *functions = QOpenGLContext::currentContext()->functions(); functions->glBindFramebuffer(GL_FRAMEBUFFER, m_surface_fbo); @@ -265,15 +268,17 @@ GLuint QWindowCompositor::composeSurface(QWaylandSurface *surface, bool *texture functions->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); - paintChildren(surface,surface); + paintChildren(surface, surface,windowSize); functions->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,0, 0); functions->glBindFramebuffer(GL_FRAMEBUFFER, 0); + + return texture; } -void QWindowCompositor::paintChildren(QWaylandSurface *surface, QWaylandSurface *window) { +void QWindowCompositor::paintChildren(QWaylandSurface *surface, QWaylandSurface *window, const QSize &windowSize) { if (surface->subSurfaces().size() == 0) return; @@ -282,19 +287,22 @@ void QWindowCompositor::paintChildren(QWaylandSurface *surface, QWaylandSurface while (i.hasNext()) { QWaylandSurface *subSurface = i.next(); QPointF p = subSurface->mapTo(window,QPointF(0,0)); - if (subSurface->size().isValid()) { + QSize subSize = subSurface->size(); + subSurface->advanceBufferQueue(); + if (subSize.isValid()) { GLuint texture = 0; if (subSurface->type() == QWaylandSurface::Texture) { texture = subSurface->texture(); } else if (surface->type() == QWaylandSurface::Shm) { texture = textureFromImage(subSurface->image()); } - QRect geo(p.toPoint(),subSurface->size()); - m_textureBlitter->drawTexture(texture,geo,window->size(),0,window->isYInverted(),subSurface->isYInverted()); + QRect geo(p.toPoint(),subSize); + if (texture > 0) + m_textureBlitter->drawTexture(texture,geo,windowSize,0,window->isYInverted(),subSurface->isYInverted()); if (surface->type() == QWaylandSurface::Shm) glDeleteTextures(1, &texture); } - paintChildren(subSurface,window); + paintChildren(subSurface,window,windowSize); } } @@ -302,6 +310,9 @@ void QWindowCompositor::paintChildren(QWaylandSurface *surface, QWaylandSurface void QWindowCompositor::render() { m_window->makeCurrent(); + + cleanupGraphicsResources(); + if (!m_backgroundTexture) m_backgroundTexture = textureFromImage(m_backgroundImage); diff --git a/examples/qwindow-compositor/qwindowcompositor.h b/examples/qwindow-compositor/qwindowcompositor.h index d09ffa89..c58c0d57 100644 --- a/examples/qwindow-compositor/qwindowcompositor.h +++ b/examples/qwindow-compositor/qwindowcompositor.h @@ -72,7 +72,7 @@ protected: QWaylandSurface* surfaceAt(const QPointF &point, QPointF *local = 0); GLuint composeSurface(QWaylandSurface *surface, bool *textureOwned); - void paintChildren(QWaylandSurface *surface, QWaylandSurface *window); + void paintChildren(QWaylandSurface *surface, QWaylandSurface *window, const QSize &windowSize); bool eventFilter(QObject *obj, QEvent *event); diff --git a/src/compositor/compositor_api/qwaylandcompositor.cpp b/src/compositor/compositor_api/qwaylandcompositor.cpp index 916dad91..35e39dc4 100644 --- a/src/compositor/compositor_api/qwaylandcompositor.cpp +++ b/src/compositor/compositor_api/qwaylandcompositor.cpp @@ -142,6 +142,11 @@ QWindow * QWaylandCompositor::window() const return m_toplevel_window; } +void QWaylandCompositor::cleanupGraphicsResources() +{ + m_compositor->cleanupGraphicsResources(); +} + void QWaylandCompositor::surfaceAboutToBeDestroyed(QWaylandSurface *surface) { Q_UNUSED(surface); diff --git a/src/compositor/compositor_api/qwaylandcompositor.h b/src/compositor/compositor_api/qwaylandcompositor.h index 40a151c5..338992e0 100644 --- a/src/compositor/compositor_api/qwaylandcompositor.h +++ b/src/compositor/compositor_api/qwaylandcompositor.h @@ -133,6 +133,8 @@ public: virtual void setCursorSurface(QWaylandSurface *surface, int hotspotX, int hotspotY); + void cleanupGraphicsResources(); + enum TouchExtensionFlag { TouchExtMouseFromTouch = 0x01 }; diff --git a/src/compositor/compositor_api/qwaylandsurface.cpp b/src/compositor/compositor_api/qwaylandsurface.cpp index 293ff932..01704160 100644 --- a/src/compositor/compositor_api/qwaylandsurface.cpp +++ b/src/compositor/compositor_api/qwaylandsurface.cpp @@ -104,6 +104,12 @@ QWaylandSurface::QWaylandSurface(QtWayland::Surface *surface) #endif } +void QWaylandSurface::advanceBufferQueue() +{ + Q_D(const QWaylandSurface); + d->surface->advanceBufferQueue(); +} + WaylandClient *QWaylandSurface::client() const { Q_D(const QWaylandSurface); diff --git a/src/compositor/compositor_api/qwaylandsurface.h b/src/compositor/compositor_api/qwaylandsurface.h index 18d4e7e7..e4126b80 100644 --- a/src/compositor/compositor_api/qwaylandsurface.h +++ b/src/compositor/compositor_api/qwaylandsurface.h @@ -180,6 +180,8 @@ public: Q_INVOKABLE void destroySurfaceByForce(); Q_INVOKABLE void ping(); + void advanceBufferQueue(); + public slots: void updateSelection(); diff --git a/src/compositor/compositor_api/qwaylandsurfaceitem.cpp b/src/compositor/compositor_api/qwaylandsurfaceitem.cpp index 55765c75..d932a837 100644 --- a/src/compositor/compositor_api/qwaylandsurfaceitem.cpp +++ b/src/compositor/compositor_api/qwaylandsurfaceitem.cpp @@ -389,8 +389,14 @@ QSGNode *QWaylandSurfaceItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeD return 0; } - updateTexture(); - if (!m_provider->t || !m_paintEnabled) { + // Order here is important, as the state of visible is that of the pending + // buffer but will be replaced after we advance the buffer queue. + bool visible = m_surface->visible(); + surface()->advanceBufferQueue(); + if (visible) + updateTexture(); + + if (!visible || !m_provider->t || !m_paintEnabled) { delete oldNode; return 0; } diff --git a/src/compositor/wayland_wrapper/qwlcompositor.cpp b/src/compositor/wayland_wrapper/qwlcompositor.cpp index 3c606d21..d798d5d7 100644 --- a/src/compositor/wayland_wrapper/qwlcompositor.cpp +++ b/src/compositor/wayland_wrapper/qwlcompositor.cpp @@ -70,6 +70,10 @@ #include <QtCore/QAbstractEventDispatcher> #include <QtGui/private/qguiapplication_p.h> +#ifdef QT_COMPOSITOR_QUICK +#include <QtQuick/QQuickWindow> +#endif + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -214,6 +218,17 @@ Compositor::Compositor(QWaylandCompositor *qt_compositor, QWaylandCompositor::Ex qRegisterMetaType<SurfaceBuffer*>("SurfaceBuffer*"); //initialize distancefieldglyphcache here + +#ifdef QT_COMPOSITOR_QUICK + if (QQuickWindow *w = qobject_cast<QQuickWindow *>(window)) { + connect(w, SIGNAL(beforeSynchronizing()), this, SLOT(cleanupGraphicsResources()), Qt::DirectConnection); + } else +#endif + { +#if !defined(QT_NO_DEBUG) && !defined(QT_WAYLAND_NO_CLEANUP_WARNING) + qWarning("QWaylandCompositor::cleanupGraphicsResources() must be called manually"); +#endif + } } Compositor::~Compositor() @@ -259,11 +274,6 @@ uint Compositor::currentTimeMsecs() const return m_timer.elapsed(); } -void Compositor::releaseBuffer(QPlatformScreenBuffer *screenBuffer) -{ - static_cast<SurfaceBuffer *>(screenBuffer)->scheduledRelease(); -} - void Compositor::processWaylandEvents() { int ret = wl_event_loop_dispatch(m_loop, 0); @@ -272,7 +282,7 @@ void Compositor::processWaylandEvents() wl_display_flush_clients(m_display->handle()); } -void Compositor::surfaceDestroyed(Surface *surface) +void Compositor::destroySurface(Surface *surface) { InputDevice *dev = defaultInputDevice(); if (dev->mouseFocus() == surface) { @@ -294,6 +304,19 @@ void Compositor::surfaceDestroyed(Surface *surface) setDirectRenderSurface(0, 0); waylandCompositor()->surfaceAboutToBeDestroyed(surface->waylandSurface()); + + surface->releaseSurfaces(); + m_destroyed_surfaces << surface; +} + +void Compositor::cleanupGraphicsResources() +{ + foreach (SurfaceBuffer *s, m_destroyed_buffers) + s->bufferWasDestroyed(); + m_destroyed_buffers.clear(); + + qDeleteAll(m_destroyed_surfaces); + m_destroyed_surfaces.clear(); } void Compositor::markSurfaceAsDirty(QtWayland::Surface *surface) diff --git a/src/compositor/wayland_wrapper/qwlcompositor_p.h b/src/compositor/wayland_wrapper/qwlcompositor_p.h index e223b03f..e6b82626 100644 --- a/src/compositor/wayland_wrapper/qwlcompositor_p.h +++ b/src/compositor/wayland_wrapper/qwlcompositor_p.h @@ -94,7 +94,7 @@ public: InputDevice *defaultInputDevice(); //we just have 1 default device for now (since QPA doesn't give us anything else) void createSurface(struct wl_client *client, uint32_t id); - void surfaceDestroyed(Surface *surface); + void destroySurface(Surface *surface); void markSurfaceAsDirty(Surface *surface); void destroyClient(WaylandClient *client); @@ -163,9 +163,11 @@ public: void scheduleReleaseBuffer(SurfaceBuffer *screenBuffer); -private slots: + void bufferWasDestroyed(SurfaceBuffer *buffer) { m_destroyed_buffers << buffer; } +public slots: + void cleanupGraphicsResources(); - void releaseBuffer(QPlatformScreenBuffer *screenBuffer); +private slots: void processWaylandEvents(); private: @@ -191,6 +193,8 @@ private: QElapsedTimer m_timer; QList<Surface *> m_surfaces; QSet<Surface *> m_dirty_surfaces; + QSet<Surface *> m_destroyed_surfaces; + QSet<SurfaceBuffer *> m_destroyed_buffers; /* Render state */ uint32_t m_current_frame; diff --git a/src/compositor/wayland_wrapper/qwlsurface.cpp b/src/compositor/wayland_wrapper/qwlsurface.cpp index 6d2d7325..1e514b6e 100644 --- a/src/compositor/wayland_wrapper/qwlsurface.cpp +++ b/src/compositor/wayland_wrapper/qwlsurface.cpp @@ -104,6 +104,14 @@ Surface::~Surface() } } +void Surface::releaseSurfaces() +{ + delete m_waylandSurface; + m_waylandSurface = 0; + delete m_subSurface; + m_subSurface = 0; +} + Surface *Surface::fromResource(struct ::wl_resource *resource) { return static_cast<Surface *>(Resource::fromResource(resource)->surface); @@ -206,7 +214,7 @@ QImage Surface::image() const #ifdef QT_COMPOSITOR_WAYLAND_GL GLuint Surface::textureId() const { - const SurfaceBuffer *surfacebuffer = currentSurfaceBuffer(); + const SurfaceBuffer *surfacebuffer = m_frontBuffer; if (m_compositor->clientBufferIntegration() && type() == QWaylandSurface::Texture && !surfacebuffer->textureCreated()) { @@ -218,16 +226,6 @@ GLuint Surface::textureId() const void Surface::sendFrameCallback() { - SurfaceBuffer *surfacebuffer = currentSurfaceBuffer(); - surfacebuffer->setDisplayed(); - if (m_backBuffer) { - if (m_frontBuffer) - m_frontBuffer->disown(); - m_frontBuffer = m_backBuffer; - } - - bool updateNeeded = advanceBufferQueue(); - uint time = m_compositor->currentTimeMsecs(); struct wl_resource *frame_callback, *next; wl_list_for_each_safe(frame_callback, next, &m_frame_callback_list, link) { @@ -235,9 +233,6 @@ void Surface::sendFrameCallback() wl_resource_destroy(frame_callback); } wl_list_init(&m_frame_callback_list); - - if (updateNeeded) - doUpdate(); } void Surface::frameFinished() @@ -302,76 +297,66 @@ Compositor *Surface::compositor() const return m_compositor; } -bool Surface::advanceBufferQueue() -{ - //has current buffer been displayed, - //do we have another buffer in the queue - //and does it have a valid damage rect +void Surface::advanceBufferQueue() + { + SurfaceBuffer *front = m_frontBuffer; - if (m_backBuffer && !m_backBuffer->isDisplayed()) { - if (m_backBuffer->waylandBufferHandle()) { - return true; - } else { + // Advance current back buffer to the front buffer. + if (m_backBuffer) { + if (m_backBuffer->isDestroyed()) { m_backBuffer->disown(); - } + m_backBuffer = 0; + } + m_frontBuffer = m_backBuffer; + m_backBuffer = 0; } - if (m_bufferQueue.size()) { - QSize size; - if (m_backBuffer && m_backBuffer->waylandBufferHandle()) { - size = m_backBuffer->size(); - } - - if (!m_bufferQueue.first()->isComitted()) - return false; - - m_backBuffer = m_bufferQueue.takeFirst(); - while (m_backBuffer && m_backBuffer->isDestroyed()) { - m_backBuffer->disown(); - m_backBuffer = m_bufferQueue.size() ? m_bufferQueue.takeFirst() : 0; - } - if (!m_backBuffer) - return false; //we have no new backbuffer; - - if (m_backBuffer->waylandBufferHandle()) { - size = m_backBuffer->size(); + // Set a new back buffer if there is something in the queue. + if (m_bufferQueue.size() && m_bufferQueue.first()->isComitted()) { + SurfaceBuffer *next = m_bufferQueue.takeFirst(); + while (next && next->isDestroyed()) { + next->disown(); + next = m_bufferQueue.size() ? m_bufferQueue.takeFirst() : 0; } - setSize(size); - - - if ((m_backBuffer && m_backBuffer->waylandBufferHandle()) && (!m_subSurface || !m_subSurface->parent()) && !m_surfaceMapped) { - m_surfaceMapped = true; - emit m_waylandSurface->mapped(); - } else if (m_backBuffer && !m_backBuffer->waylandBufferHandle() && m_surfaceMapped) { - m_surfaceMapped = false; - emit m_waylandSurface->unmapped(); - } - - } else { - m_backBuffer = 0; - return false; + setBackBuffer(next); } - return true; + // Release the old front buffer if we changed it. + if (front && front != m_frontBuffer) + front->disown(); } -void Surface::doUpdate() { - if (postBuffer()) { -#ifdef QT_COMPOSITOR_QUICK - QWaylandSurfaceItem *surfaceItem = waylandSurface()->surfaceItem(); - if (surfaceItem) - surfaceItem->setDamagedFlag(true); // avoid flicker when we switch back to composited mode -#endif - sendFrameCallback(); - } else { - SurfaceBuffer *surfaceBuffer = currentSurfaceBuffer(); +/*! + * Sets the backbuffer for this surface. The back buffer is not yet on + * screen and will become live during the next advanceBufferQueue(). + * + * The backbuffer represents the current state of the surface for the + * purpose of GUI-thread accessible properties such as size and visibility. + */ +void Surface::setBackBuffer(SurfaceBuffer *buffer) +{ + m_backBuffer = buffer; - if (surfaceBuffer) { - if (surfaceBuffer->damageRect().isValid()) { - m_compositor->markSurfaceAsDirty(this); - emit m_waylandSurface->damaged(surfaceBuffer->damageRect()); - } + if (m_backBuffer) { + bool valid = m_backBuffer->waylandBufferHandle() != 0; + setSize(valid ? m_backBuffer->size() : QSize()); + + if ((!m_subSurface || !m_subSurface->parent()) && !m_surfaceMapped) { + m_surfaceMapped = true; + emit m_waylandSurface->mapped(); + } else if (!valid && m_surfaceMapped) { + m_surfaceMapped = false; + emit m_waylandSurface->unmapped(); } + + m_compositor->markSurfaceAsDirty(this); + emit m_waylandSurface->damaged(m_backBuffer->damageRect()); + } else { + InputDevice *inputDevice = m_compositor->defaultInputDevice(); + if (inputDevice->keyboardFocus() == this) + inputDevice->setKeyboardFocus(0); + if (inputDevice->mouseFocus() == this) + inputDevice->setMouseFocus(0, QPointF(), QPointF()); } } @@ -390,27 +375,6 @@ SurfaceBuffer *Surface::createSurfaceBuffer(struct ::wl_resource *buffer) return newBuffer; } -bool Surface::postBuffer() { -#ifdef QT_COMPOSITOR_WAYLAND_GL - if (m_waylandSurface->handle() == m_compositor->directRenderSurface()) { - SurfaceBuffer *surfaceBuffer = currentSurfaceBuffer(); - if (surfaceBuffer && surfaceBuffer->waylandBufferHandle()) { - if (m_compositor->pageFlipper()) { - if (m_compositor->pageFlipper()->displayBuffer(surfaceBuffer)) { - surfaceBuffer->setPageFlipperHasBuffer(true); - m_compositor->setDirectRenderingActive(true); - return true; - } else { - if (QT_WAYLAND_PRINT_BUFFERING_WARNINGS) - qWarning() << "could not post buffer"; - } - } - } - } -#endif - return false; -} - void Surface::attach(struct ::wl_resource *buffer) { SurfaceBuffer *last = m_bufferQueue.size()?m_bufferQueue.last():0; @@ -428,14 +392,6 @@ void Surface::attach(struct ::wl_resource *buffer) SurfaceBuffer *surfBuf = createSurfaceBuffer(buffer); m_bufferQueue << surfBuf; - - if (!buffer) { - InputDevice *inputDevice = m_compositor->defaultInputDevice(); - if (inputDevice->keyboardFocus() == this) - inputDevice->setKeyboardFocus(0); - if (inputDevice->mouseFocus() == this) - inputDevice->setMouseFocus(0, QPointF(), QPointF()); - } } void Surface::damage(const QRect &rect) @@ -456,8 +412,7 @@ void Surface::damage(const QRect &rect) void Surface::surface_destroy_resource(Resource *) { - compositor()->surfaceDestroyed(this); - delete this; + compositor()->destroySurface(this); } void Surface::surface_destroy(Resource *resource) @@ -510,8 +465,13 @@ void Surface::surface_commit(Resource *) surfaceBuffer->setCommitted(); } - advanceBufferQueue(); - doUpdate(); + // A new buffer was added to the queue, so we set it as the current + // back buffer. Second and third buffers, if the come, will be handled + // in advanceBufferQueue(). + if (!m_backBuffer && m_bufferQueue.size() == 1) { + setBackBuffer(surfaceBuffer); + m_bufferQueue.takeFirst(); + } } void Surface::setClassName(const QString &className) diff --git a/src/compositor/wayland_wrapper/qwlsurface_p.h b/src/compositor/wayland_wrapper/qwlsurface_p.h index ea213435..8f4aff00 100644 --- a/src/compositor/wayland_wrapper/qwlsurface_p.h +++ b/src/compositor/wayland_wrapper/qwlsurface_p.h @@ -138,6 +138,9 @@ public: bool isCursorSurface() const { return m_isCursorSurface; } void setCursorSurface(bool isCursor) { m_isCursorSurface = isCursor; } + void advanceBufferQueue(); + void releaseSurfaces(); + private: Q_DISABLE_COPY(Surface) @@ -174,11 +177,8 @@ private: inline SurfaceBuffer *currentSurfaceBuffer() const; void damage(const QRect &rect); - bool advanceBufferQueue(); - void doUpdate(); + void setBackBuffer(SurfaceBuffer *buffer); SurfaceBuffer *createSurfaceBuffer(struct ::wl_resource *buffer); - void frameFinishedInternal(); - bool postBuffer(); void attach(struct ::wl_resource *buffer); diff --git a/src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp b/src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp index 90570031..b4b26ee6 100644 --- a/src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp +++ b/src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp @@ -65,7 +65,6 @@ SurfaceBuffer::SurfaceBuffer(Surface *surface) , m_page_flipper_has_buffer(false) , m_is_displayed(false) , m_texture(0) - , m_guard(0) , m_is_shm_resolved(false) , m_shmBuffer(0) , m_isSizeResolved(false) @@ -84,7 +83,6 @@ void SurfaceBuffer::initialize(struct ::wl_resource *buffer) { m_buffer = buffer; m_texture = 0; - m_guard = 0; m_committed = false; m_is_registered_for_buffer = true; m_surface_has_buffer = true; @@ -175,17 +173,6 @@ void SurfaceBuffer::setPageFlipperHasBuffer(bool owns) void SurfaceBuffer::release() { - m_compositor->scheduleReleaseBuffer(this); -} - -void SurfaceBuffer::scheduledRelease() -{ - m_page_flipper_has_buffer = false; - if (!m_surface_has_buffer) - destructBufferState(); - if (!m_surface) { - delete this; - } } void SurfaceBuffer::disown() @@ -218,16 +205,13 @@ void SurfaceBuffer::destroyTexture() { #ifdef QT_COMPOSITOR_WAYLAND_GL if (m_texture) { - /* When QOpenGLSharedResourceGuard is freed, destroyTexture might be reentered - to cause double free. So clear m_texture first. */ - m_texture = 0; - if (m_guard) { - m_guard->free(); - m_guard = 0; - } else { - QWaylandClientBufferIntegration *hwIntegration = m_compositor->clientBufferIntegration(); + Q_ASSERT(QOpenGLContext::currentContext()); + QWaylandClientBufferIntegration *hwIntegration = m_compositor->clientBufferIntegration(); + if (hwIntegration->textureForBuffer(m_buffer) == 0) + glDeleteTextures(1, &m_texture); + else hwIntegration->destroyTextureForBuffer(m_buffer); - } + m_texture = 0; } #endif } @@ -284,20 +268,20 @@ QImage SurfaceBuffer::image() return m_image; } -void SurfaceBuffer::destroy_listener_callback(wl_listener *listener, void *data) +void SurfaceBuffer::bufferWasDestroyed() { - Q_UNUSED(data); - struct surface_buffer_destroy_listener *destroy_listener = - reinterpret_cast<struct surface_buffer_destroy_listener *>(listener); - SurfaceBuffer *d = destroy_listener->surfaceBuffer; - d->destroyTexture(); - d->m_destroyed = true; - d->m_buffer = 0; + destroyTexture(); + m_destroyed = true; + m_buffer = 0; } -void freeTexture(QOpenGLFunctions *, GLuint id) +void SurfaceBuffer::destroy_listener_callback(wl_listener *listener, void *data) { - glDeleteTextures(1, &id); + Q_UNUSED(data); + struct surface_buffer_destroy_listener *destroy_listener = + reinterpret_cast<struct surface_buffer_destroy_listener *>(listener); + SurfaceBuffer *d = destroy_listener->surfaceBuffer; + d->m_compositor->bufferWasDestroyed(d); } void SurfaceBuffer::createTexture() @@ -306,10 +290,8 @@ void SurfaceBuffer::createTexture() #ifdef QT_COMPOSITOR_WAYLAND_GL if (!m_texture) m_texture = hwIntegration->textureForBuffer(m_buffer); - if (!m_texture) { + if (!m_texture) glGenTextures(1, &m_texture); - m_guard = new QOpenGLSharedResourceGuard(QOpenGLContext::currentContext(), m_texture, freeTexture); - } glBindTexture(GL_TEXTURE_2D, m_texture); hwIntegration->bindTextureToBuffer(m_buffer); #else diff --git a/src/compositor/wayland_wrapper/qwlsurfacebuffer_p.h b/src/compositor/wayland_wrapper/qwlsurfacebuffer_p.h index 42c26e7d..3754d9b0 100644 --- a/src/compositor/wayland_wrapper/qwlsurfacebuffer_p.h +++ b/src/compositor/wayland_wrapper/qwlsurfacebuffer_p.h @@ -43,7 +43,6 @@ #include <QtCore/QRect> #include <QtGui/qopengl.h> -#include <QtGui/private/qopenglcontext_p.h> #include <qpa/qplatformscreenpageflipper.h> #include <QImage> @@ -84,7 +83,6 @@ public: void setPageFlipperHasBuffer(bool owns); bool pageFlipperHasBuffer() const { return m_page_flipper_has_buffer; } void release(); - void scheduledRelease(); void disown(); void setDisplayed(); @@ -107,6 +105,8 @@ public: void handleAboutToBeDisplayed(); void handleDisplayed(); + void bufferWasDestroyed(); + void *handle() const; QImage image(); private: @@ -123,10 +123,8 @@ private: bool m_is_displayed; #ifdef QT_COMPOSITOR_WAYLAND_GL GLuint m_texture; - QOpenGLSharedResourceGuard *m_guard; #else uint m_texture; - uint m_guard; #endif void *m_handle; mutable bool m_is_shm_resolved; |