backends: use explicit sync for reusing graphics buffers with EGL

Otherwise there can be glitches on NVidia, and this also makes some future
code changes around multi gpu copies and shadow buffers easier
This commit is contained in:
Xaver Hugl 2024-03-15 00:58:46 +01:00
parent af3bf939c5
commit 5fd96620ed
7 changed files with 33 additions and 17 deletions

View file

@ -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<DrmFramebuffer> 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

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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"

View file

@ -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<GLTexture> X11WindowedEglPrimaryLayer::texture() const

View file

@ -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> EglSwapchainSlot::create(EglContext *context, GraphicsBuffer *buffer)
{
auto texture = context->importDmaBufAsTexture(*buffer->dmabufAttributes());
@ -100,10 +105,11 @@ uint64_t EglSwapchain::modifier() const
std::shared_ptr<EglSwapchainSlot> 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<EglSwapchainSlot> EglSwapchain::acquire()
return slot;
}
void EglSwapchain::release(std::shared_ptr<EglSwapchainSlot> slot)
void EglSwapchain::release(std::shared_ptr<EglSwapchainSlot> 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;

View file

@ -9,6 +9,7 @@
#pragma once
#include "kwin_export.h"
#include "utils/filedescriptor.h"
#include <QList>
#include <QSize>
@ -40,10 +41,13 @@ public:
static std::shared_ptr<EglSwapchainSlot> create(EglContext *context, GraphicsBuffer *buffer);
private:
bool isBusy() const;
GraphicsBuffer *m_buffer;
std::unique_ptr<GLFramebuffer> m_framebuffer;
std::shared_ptr<GLTexture> m_texture;
int m_age = 0;
FileDescriptor m_releaseFd;
friend class EglSwapchain;
};
@ -58,7 +62,7 @@ public:
uint64_t modifier() const;
std::shared_ptr<EglSwapchainSlot> acquire();
void release(std::shared_ptr<EglSwapchainSlot> slot);
void release(std::shared_ptr<EglSwapchainSlot> slot, FileDescriptor &&releaseFence);
static std::shared_ptr<EglSwapchain> create(GraphicsBufferAllocator *allocator, EglContext *context, const QSize &size, uint32_t format, const QList<uint64_t> &modifiers);