summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGunnar Sletta <gunnar.sletta@jollamobile.com>2014-01-18 07:40:21 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-01-21 14:09:18 +0100
commit36ff0f303b79dcd7aae93d5a73dfc1f179ac5560 (patch)
tree786453094160454edd96020901ef63a9bf9a0905
parentbbf7285b669b105c7ccb6629d963b5e2584453d8 (diff)
downloadqtwayland-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.cpp13
-rw-r--r--examples/qwindow-compositor/qwindowcompositor.cpp23
-rw-r--r--examples/qwindow-compositor/qwindowcompositor.h2
-rw-r--r--src/compositor/compositor_api/qwaylandcompositor.cpp5
-rw-r--r--src/compositor/compositor_api/qwaylandcompositor.h2
-rw-r--r--src/compositor/compositor_api/qwaylandsurface.cpp6
-rw-r--r--src/compositor/compositor_api/qwaylandsurface.h2
-rw-r--r--src/compositor/compositor_api/qwaylandsurfaceitem.cpp10
-rw-r--r--src/compositor/wayland_wrapper/qwlcompositor.cpp35
-rw-r--r--src/compositor/wayland_wrapper/qwlcompositor_p.h10
-rw-r--r--src/compositor/wayland_wrapper/qwlsurface.cpp172
-rw-r--r--src/compositor/wayland_wrapper/qwlsurface_p.h8
-rw-r--r--src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp52
-rw-r--r--src/compositor/wayland_wrapper/qwlsurfacebuffer_p.h6
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;