backends/drm: extract dmabuf feedback into its own class
This should reduce code duplication with overlay planes
This commit is contained in:
parent
5df65e4be5
commit
c43eb6ec42
5 changed files with 147 additions and 58 deletions
|
@ -29,6 +29,7 @@ set(DRM_SOURCES
|
|||
virtual_egl_gbm_layer.cpp
|
||||
drm_lease_egl_gbm_layer.cpp
|
||||
egl_gbm_layer_surface.cpp
|
||||
dmabuf_feedback.cpp
|
||||
)
|
||||
|
||||
add_library(KWinWaylandDrmBackend MODULE ${DRM_SOURCES})
|
||||
|
|
89
src/backends/drm/dmabuf_feedback.cpp
Normal file
89
src/backends/drm/dmabuf_feedback.cpp
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
SPDX-FileCopyrightText: 2022 Xaver Hugl <xaver.hugl@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#include "dmabuf_feedback.h"
|
||||
|
||||
#include "drm_gpu.h"
|
||||
#include "egl_dmabuf.h"
|
||||
#include "egl_gbm_backend.h"
|
||||
|
||||
#include <KWaylandServer/linuxdmabufv1clientbuffer.h>
|
||||
#include <KWaylandServer/surface_interface.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
DmabufFeedback::DmabufFeedback(DrmGpu *gpu, EglGbmBackend *eglBackend)
|
||||
: m_gpu(gpu)
|
||||
, m_eglBackend(eglBackend)
|
||||
{
|
||||
}
|
||||
|
||||
void DmabufFeedback::renderingSurface()
|
||||
{
|
||||
if (m_surface && !m_attemptedThisFrame) {
|
||||
if (const auto &feedback = m_surface->dmabufFeedbackV1()) {
|
||||
feedback->setTranches({});
|
||||
}
|
||||
m_surface = nullptr;
|
||||
}
|
||||
m_attemptedThisFrame = false;
|
||||
}
|
||||
|
||||
void DmabufFeedback::scanoutSuccessful(KWaylandServer::SurfaceInterface *surface)
|
||||
{
|
||||
if (surface != m_surface) {
|
||||
if (m_surface && m_surface->dmabufFeedbackV1()) {
|
||||
m_surface->dmabufFeedbackV1()->setTranches({});
|
||||
}
|
||||
m_surface = surface;
|
||||
m_attemptedFormats = {};
|
||||
}
|
||||
}
|
||||
|
||||
void DmabufFeedback::scanoutFailed(KWaylandServer::SurfaceInterface *surface, const QMap<uint32_t, QVector<uint64_t>> &formats)
|
||||
{
|
||||
m_attemptedThisFrame = true;
|
||||
if (surface != m_surface) {
|
||||
m_attemptedFormats = {};
|
||||
if (m_surface && m_surface->dmabufFeedbackV1()) {
|
||||
m_surface->dmabufFeedbackV1()->setTranches({});
|
||||
}
|
||||
m_surface = surface;
|
||||
}
|
||||
if (const auto &feedback = m_surface->dmabufFeedbackV1()) {
|
||||
const auto buffer = qobject_cast<KWaylandServer::LinuxDmaBufV1ClientBuffer *>(surface->buffer());
|
||||
Q_ASSERT(buffer);
|
||||
if (!m_attemptedFormats[buffer->format()].contains(buffer->planes().first().modifier)) {
|
||||
m_attemptedFormats[buffer->format()] << buffer->planes().first().modifier;
|
||||
QVector<KWaylandServer::LinuxDmaBufV1Feedback::Tranche> scanoutTranches;
|
||||
const auto tranches = m_eglBackend->dmabuf()->tranches();
|
||||
for (const auto &tranche : tranches) {
|
||||
KWaylandServer::LinuxDmaBufV1Feedback::Tranche scanoutTranche;
|
||||
for (auto it = tranche.formatTable.constBegin(); it != tranche.formatTable.constEnd(); it++) {
|
||||
const uint32_t format = it.key();
|
||||
const auto trancheModifiers = it.value();
|
||||
const auto drmModifiers = formats[format];
|
||||
for (const auto &mod : trancheModifiers) {
|
||||
if (drmModifiers.contains(mod) && !m_attemptedFormats[format].contains(mod)) {
|
||||
scanoutTranche.formatTable[format] << mod;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!scanoutTranche.formatTable.isEmpty()) {
|
||||
scanoutTranche.device = m_gpu->deviceId();
|
||||
scanoutTranche.flags = KWaylandServer::LinuxDmaBufV1Feedback::TrancheFlag::Scanout;
|
||||
scanoutTranches << scanoutTranche;
|
||||
}
|
||||
}
|
||||
feedback->setTranches(scanoutTranches);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
45
src/backends/drm/dmabuf_feedback.h
Normal file
45
src/backends/drm/dmabuf_feedback.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
SPDX-FileCopyrightText: 2022 Xaver Hugl <xaver.hugl@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QMap>
|
||||
#include <QPointer>
|
||||
#include <QVector>
|
||||
|
||||
namespace KWaylandServer
|
||||
{
|
||||
class SurfaceInterface;
|
||||
class LinuxDmaBufV1ClientBuffer;
|
||||
}
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
class EglGbmBackend;
|
||||
class DrmGpu;
|
||||
|
||||
class DmabufFeedback
|
||||
{
|
||||
public:
|
||||
DmabufFeedback(DrmGpu *gpu, EglGbmBackend *eglBackend);
|
||||
|
||||
void renderingSurface();
|
||||
void scanoutSuccessful(KWaylandServer::SurfaceInterface *surface);
|
||||
void scanoutFailed(KWaylandServer::SurfaceInterface *surface, const QMap<uint32_t, QVector<uint64_t>> &formats);
|
||||
|
||||
private:
|
||||
QPointer<KWaylandServer::SurfaceInterface> m_surface;
|
||||
QMap<uint32_t, QVector<uint64_t>> m_attemptedFormats;
|
||||
bool m_attemptedThisFrame = false;
|
||||
|
||||
DrmGpu *const m_gpu;
|
||||
EglGbmBackend *const m_eglBackend;
|
||||
};
|
||||
|
||||
}
|
|
@ -33,6 +33,7 @@ namespace KWin
|
|||
EglGbmLayer::EglGbmLayer(EglGbmBackend *eglBackend, DrmPipeline *pipeline)
|
||||
: DrmPipelineLayer(pipeline)
|
||||
, m_surface(pipeline->gpu(), eglBackend)
|
||||
, m_dmabufFeedback(pipeline->gpu(), eglBackend)
|
||||
{
|
||||
connect(eglBackend, &EglGbmBackend::aboutToBeDestroyed, this, &EglGbmLayer::destroyResources);
|
||||
}
|
||||
|
@ -50,14 +51,7 @@ void EglGbmLayer::destroyResources()
|
|||
OutputLayerBeginFrameInfo EglGbmLayer::beginFrame()
|
||||
{
|
||||
m_scanoutBuffer.reset();
|
||||
// dmabuf feedback
|
||||
if (!m_scanoutCandidate.attemptedThisFrame && m_scanoutCandidate.surface) {
|
||||
if (const auto feedback = m_scanoutCandidate.surface->dmabufFeedbackV1()) {
|
||||
feedback->setTranches({});
|
||||
}
|
||||
m_scanoutCandidate.surface = nullptr;
|
||||
}
|
||||
m_scanoutCandidate.attemptedThisFrame = false;
|
||||
m_dmabufFeedback.renderingSurface();
|
||||
|
||||
return m_surface.startRendering(m_pipeline->bufferSize(), m_pipeline->pending.sourceTransformation, m_pipeline->pending.bufferTransformation, m_pipeline->formats());
|
||||
}
|
||||
|
@ -119,70 +113,37 @@ bool EglGbmLayer::scanout(SurfaceItem *surfaceItem)
|
|||
if (!item || !item->surface()) {
|
||||
return false;
|
||||
}
|
||||
const auto buffer = qobject_cast<KWaylandServer::LinuxDmaBufV1ClientBuffer *>(item->surface()->buffer());
|
||||
const auto surface = item->surface();
|
||||
const auto buffer = qobject_cast<KWaylandServer::LinuxDmaBufV1ClientBuffer *>(surface->buffer());
|
||||
if (!buffer || buffer->planes().isEmpty() || buffer->size() != m_pipeline->sourceSize()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_scanoutCandidate.surface && m_scanoutCandidate.surface != item->surface() && m_scanoutCandidate.surface->dmabufFeedbackV1()) {
|
||||
m_scanoutCandidate.surface->dmabufFeedbackV1()->setTranches({});
|
||||
}
|
||||
m_scanoutCandidate.surface = item->surface();
|
||||
m_scanoutCandidate.attemptedThisFrame = true;
|
||||
|
||||
if (!m_pipeline->formats().contains(buffer->format())) {
|
||||
sendDmabufFeedback(buffer);
|
||||
const auto formats = m_pipeline->formats();
|
||||
if (!formats.contains(buffer->format())) {
|
||||
m_dmabufFeedback.scanoutFailed(surface, formats);
|
||||
return false;
|
||||
}
|
||||
m_scanoutBuffer = QSharedPointer<DrmGbmBuffer>::create(m_pipeline->gpu(), buffer);
|
||||
if (!m_scanoutBuffer || !m_scanoutBuffer->bufferId()) {
|
||||
sendDmabufFeedback(buffer);
|
||||
m_dmabufFeedback.scanoutFailed(surface, formats);
|
||||
m_scanoutBuffer.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_pipeline->testScanout()) {
|
||||
m_dmabufFeedback.scanoutSuccessful(surface);
|
||||
m_currentBuffer = m_scanoutBuffer;
|
||||
m_currentDamage = surfaceItem->damage();
|
||||
surfaceItem->resetDamage();
|
||||
return true;
|
||||
} else {
|
||||
m_dmabufFeedback.scanoutFailed(surface, formats);
|
||||
m_scanoutBuffer.reset();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void EglGbmLayer::sendDmabufFeedback(KWaylandServer::LinuxDmaBufV1ClientBuffer *failedBuffer)
|
||||
{
|
||||
if (!m_scanoutCandidate.attemptedFormats[failedBuffer->format()].contains(failedBuffer->planes().first().modifier)) {
|
||||
m_scanoutCandidate.attemptedFormats[failedBuffer->format()] << failedBuffer->planes().first().modifier;
|
||||
}
|
||||
if (m_scanoutCandidate.surface->dmabufFeedbackV1()) {
|
||||
QVector<KWaylandServer::LinuxDmaBufV1Feedback::Tranche> scanoutTranches;
|
||||
const auto drmFormats = m_pipeline->formats();
|
||||
const auto tranches = m_surface.eglBackend()->dmabuf()->tranches();
|
||||
for (const auto &tranche : tranches) {
|
||||
KWaylandServer::LinuxDmaBufV1Feedback::Tranche scanoutTranche;
|
||||
for (auto it = tranche.formatTable.constBegin(); it != tranche.formatTable.constEnd(); it++) {
|
||||
const uint32_t format = it.key();
|
||||
const auto trancheModifiers = it.value();
|
||||
const auto drmModifiers = drmFormats[format];
|
||||
for (const auto &mod : trancheModifiers) {
|
||||
if (drmModifiers.contains(mod) && !m_scanoutCandidate.attemptedFormats[format].contains(mod)) {
|
||||
scanoutTranche.formatTable[format] << mod;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!scanoutTranche.formatTable.isEmpty()) {
|
||||
scanoutTranche.device = m_pipeline->gpu()->deviceId();
|
||||
scanoutTranche.flags = KWaylandServer::LinuxDmaBufV1Feedback::TrancheFlag::Scanout;
|
||||
scanoutTranches << scanoutTranche;
|
||||
}
|
||||
}
|
||||
m_scanoutCandidate.surface->dmabufFeedbackV1()->setTranches(scanoutTranches);
|
||||
}
|
||||
}
|
||||
|
||||
QSharedPointer<DrmBuffer> EglGbmLayer::currentBuffer() const
|
||||
{
|
||||
return m_scanoutBuffer ? m_scanoutBuffer : m_currentBuffer;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#pragma once
|
||||
#include "drm_layer.h"
|
||||
|
||||
#include "dmabuf_feedback.h"
|
||||
#include "egl_gbm_layer_surface.h"
|
||||
|
||||
#include <QMap>
|
||||
|
@ -28,7 +29,6 @@ namespace KWin
|
|||
{
|
||||
|
||||
class EglGbmBackend;
|
||||
class EglGbmLayerSurface;
|
||||
class DrmGbmBuffer;
|
||||
|
||||
class EglGbmLayer : public DrmPipelineLayer
|
||||
|
@ -48,22 +48,15 @@ public:
|
|||
QSharedPointer<GLTexture> texture() const override;
|
||||
|
||||
private:
|
||||
void sendDmabufFeedback(KWaylandServer::LinuxDmaBufV1ClientBuffer *failedBuffer);
|
||||
bool renderTestBuffer();
|
||||
void destroyResources();
|
||||
|
||||
struct
|
||||
{
|
||||
QPointer<KWaylandServer::SurfaceInterface> surface;
|
||||
QMap<uint32_t, QVector<uint64_t>> attemptedFormats;
|
||||
bool attemptedThisFrame = false;
|
||||
} m_scanoutCandidate;
|
||||
|
||||
QSharedPointer<DrmGbmBuffer> m_scanoutBuffer;
|
||||
QSharedPointer<DrmBuffer> m_currentBuffer;
|
||||
QRegion m_currentDamage;
|
||||
|
||||
EglGbmLayerSurface m_surface;
|
||||
DmabufFeedback m_dmabufFeedback;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue