diff --git a/src/backends/drm/drm_egl_layer_surface.cpp b/src/backends/drm/drm_egl_layer_surface.cpp index dc06c1c603..9c10980c2e 100644 --- a/src/backends/drm/drm_egl_layer_surface.cpp +++ b/src/backends/drm/drm_egl_layer_surface.cpp @@ -177,7 +177,6 @@ bool EglGbmLayerSurface::endRendering(const QRegion &damagedRegion) GLFramebuffer::popFramebuffer(); } m_surface->damageJournal.add(damagedRegion); - m_surface->gbmSwapchain->release(m_surface->currentSlot); m_surface->timeQuery->end(); glFlush(); EGLNativeFence sourceFence(m_eglBackend->eglDisplayObject()); @@ -186,6 +185,7 @@ bool EglGbmLayerSurface::endRendering(const QRegion &damagedRegion) // and NVidia doesn't support implicit sync glFinish(); } + m_surface->gbmSwapchain->release(m_surface->currentSlot, sourceFence.fileDescriptor().duplicate()); const auto buffer = importBuffer(m_surface.get(), m_surface->currentSlot.get(), sourceFence.fileDescriptor()); m_surface->renderEnd = std::chrono::steady_clock::now(); if (buffer) { @@ -579,7 +579,7 @@ std::shared_ptr EglGbmLayerSurface::importWithEgl(Surface *surfa if (!endFence.isValid()) { glFinish(); } - surface->importGbmSwapchain->release(slot); + surface->importGbmSwapchain->release(slot, endFence.fileDescriptor().duplicate()); surface->importTimeQuery->end(); // restore the old context diff --git a/src/backends/drm/drm_virtual_egl_layer.cpp b/src/backends/drm/drm_virtual_egl_layer.cpp index 67e26342af..c45eb72133 100644 --- a/src/backends/drm/drm_virtual_egl_layer.cpp +++ b/src/backends/drm/drm_virtual_egl_layer.cpp @@ -11,6 +11,7 @@ #include "drm_gpu.h" #include "drm_logging.h" #include "drm_virtual_output.h" +#include "opengl/eglnativefence.h" #include "opengl/eglswapchain.h" #include "opengl/glrendertimequery.h" #include "scene/surfaceitem_wayland.h" @@ -89,7 +90,9 @@ bool VirtualEglGbmLayer::endFrame(const QRegion &renderedRegion, const QRegion & glFlush(); m_currentDamage = damagedRegion; m_damageJournal.add(damagedRegion); - m_gbmSwapchain->release(m_currentSlot); + + EGLNativeFence releaseFence{m_eglBackend->eglDisplayObject()}; + m_gbmSwapchain->release(m_currentSlot, releaseFence.fileDescriptor().duplicate()); return true; } diff --git a/src/backends/wayland/wayland_egl_backend.cpp b/src/backends/wayland/wayland_egl_backend.cpp index b4d7e16996..2e7de81827 100644 --- a/src/backends/wayland/wayland_egl_backend.cpp +++ b/src/backends/wayland/wayland_egl_backend.cpp @@ -106,6 +106,10 @@ bool WaylandEglPrimaryLayer::endFrame(const QRegion &renderedRegion, const QRegi m_query->end(); // Flush rendering commands to the dmabuf. glFlush(); + EGLNativeFence releaseFence{m_backend->eglDisplayObject()}; + + m_presentationBuffer = m_backend->backend()->importBuffer(m_buffer->buffer()); + m_swapchain->release(m_buffer, releaseFence.fileDescriptor().duplicate()); m_damageJournal.add(damagedRegion); return true; @@ -127,10 +131,6 @@ bool WaylandEglPrimaryLayer::scanout(SurfaceItem *surfaceItem) void WaylandEglPrimaryLayer::present() { - if (!m_presentationBuffer) { - m_presentationBuffer = m_backend->backend()->importBuffer(m_buffer->buffer()); - Q_ASSERT(m_presentationBuffer); - } KWayland::Client::Surface *surface = m_waylandOutput->surface(); surface->attachBuffer(m_presentationBuffer); @@ -139,8 +139,6 @@ void WaylandEglPrimaryLayer::present() surface->commit(); Q_EMIT m_waylandOutput->outputChange(m_damageJournal.lastDamage()); m_presentationBuffer = nullptr; - - m_swapchain->release(m_buffer); } std::chrono::nanoseconds WaylandEglPrimaryLayer::queryRenderTime() const @@ -217,7 +215,8 @@ bool WaylandEglCursorLayer::endFrame(const QRegion &renderedRegion, const QRegio m_output->cursor()->update(buffer, scale(), hotspot().toPoint()); - m_swapchain->release(m_buffer); + EGLNativeFence releaseFence{m_backend->eglDisplayObject()}; + m_swapchain->release(m_buffer, releaseFence.fileDescriptor().duplicate()); return true; } diff --git a/src/backends/wayland/wayland_egl_backend.h b/src/backends/wayland/wayland_egl_backend.h index 3a7bdac382..4cee304253 100644 --- a/src/backends/wayland/wayland_egl_backend.h +++ b/src/backends/wayland/wayland_egl_backend.h @@ -10,6 +10,7 @@ #pragma once #include "core/outputlayer.h" +#include "opengl/eglnativefence.h" #include "platformsupport/scenes/opengl/abstract_egl_backend.h" #include "utils/damagejournal.h" diff --git a/src/backends/x11/windowed/x11_windowed_egl_backend.cpp b/src/backends/x11/windowed/x11_windowed_egl_backend.cpp index 8b4f33669d..37112d97cd 100644 --- a/src/backends/x11/windowed/x11_windowed_egl_backend.cpp +++ b/src/backends/x11/windowed/x11_windowed_egl_backend.cpp @@ -8,6 +8,7 @@ */ #include "x11_windowed_egl_backend.h" #include "core/gbmgraphicsbufferallocator.h" +#include "opengl/eglnativefence.h" #include "opengl/eglswapchain.h" #include "opengl/glrendertimequery.h" #include "platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.h" @@ -104,7 +105,8 @@ void X11WindowedEglPrimaryLayer::present() Q_EMIT m_output->outputChange(infiniteRegion()); - m_swapchain->release(m_buffer); + EGLNativeFence releaseFence{m_backend->eglDisplayObject()}; + m_swapchain->release(m_buffer, releaseFence.fileDescriptor().duplicate()); } std::shared_ptr X11WindowedEglPrimaryLayer::texture() const diff --git a/src/opengl/eglswapchain.cpp b/src/opengl/eglswapchain.cpp index 1ee35f9fef..984f944dd1 100644 --- a/src/opengl/eglswapchain.cpp +++ b/src/opengl/eglswapchain.cpp @@ -54,6 +54,11 @@ int EglSwapchainSlot::age() const return m_age; } +bool EglSwapchainSlot::isBusy() const +{ + return m_buffer->isReferenced() || (m_releaseFd.isValid() && !m_releaseFd.isReadable()); +} + std::shared_ptr EglSwapchainSlot::create(EglContext *context, GraphicsBuffer *buffer) { auto texture = context->importDmaBufAsTexture(*buffer->dmabufAttributes()); @@ -100,10 +105,11 @@ uint64_t EglSwapchain::modifier() const std::shared_ptr EglSwapchain::acquire() { - for (const auto &slot : std::as_const(m_slots)) { - if (!slot->buffer()->isReferenced()) { - return slot; - } + const auto it = std::ranges::find_if(std::as_const(m_slots), [](const auto &slot) { + return !slot->isBusy(); + }); + if (it != m_slots.cend()) { + return *it; } GraphicsBuffer *buffer = m_allocator->allocate(GraphicsBufferOptions{ @@ -124,8 +130,9 @@ std::shared_ptr EglSwapchain::acquire() return slot; } -void EglSwapchain::release(std::shared_ptr slot) +void EglSwapchain::release(std::shared_ptr slot, FileDescriptor &&releaseFence) { + slot->m_releaseFd = std::move(releaseFence); for (qsizetype i = 0; i < m_slots.count(); ++i) { if (m_slots[i] == slot) { m_slots[i]->m_age = 1; diff --git a/src/opengl/eglswapchain.h b/src/opengl/eglswapchain.h index d326c26ccb..c591013844 100644 --- a/src/opengl/eglswapchain.h +++ b/src/opengl/eglswapchain.h @@ -9,6 +9,7 @@ #pragma once #include "kwin_export.h" +#include "utils/filedescriptor.h" #include #include @@ -40,10 +41,13 @@ public: static std::shared_ptr create(EglContext *context, GraphicsBuffer *buffer); private: + bool isBusy() const; + GraphicsBuffer *m_buffer; std::unique_ptr m_framebuffer; std::shared_ptr m_texture; int m_age = 0; + FileDescriptor m_releaseFd; friend class EglSwapchain; }; @@ -58,7 +62,7 @@ public: uint64_t modifier() const; std::shared_ptr acquire(); - void release(std::shared_ptr slot); + void release(std::shared_ptr slot, FileDescriptor &&releaseFence); static std::shared_ptr create(GraphicsBufferAllocator *allocator, EglContext *context, const QSize &size, uint32_t format, const QList &modifiers);