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:
parent
af3bf939c5
commit
5fd96620ed
7 changed files with 33 additions and 17 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue