backends/drm: support dmabuf-feedback
dmabuf-feedback allows the compositor to give the clients better feedback on what formats and modifiers they should use, and for which device they should allocate. This way they can reallocate for scanout whenever the compositor tells them to, which makes direct scanout work for a lot more devices and applications.
This commit is contained in:
parent
3d0bdc56a4
commit
8d08306c48
7 changed files with 58 additions and 17 deletions
|
@ -44,7 +44,8 @@ namespace KWin
|
|||
{
|
||||
|
||||
EglGbmBackend::EglGbmBackend(DrmBackend *drmBackend, DrmGpu *gpu)
|
||||
: m_backend(drmBackend)
|
||||
: AbstractEglBackend(gpu->deviceId())
|
||||
, m_backend(drmBackend)
|
||||
, m_gpu(gpu)
|
||||
{
|
||||
m_gpu->setEglBackend(this);
|
||||
|
@ -502,10 +503,16 @@ QRegion EglGbmBackend::beginFrame(AbstractOutput *drmOutput)
|
|||
{
|
||||
Q_ASSERT(m_outputs.contains(drmOutput));
|
||||
Output &output = m_outputs[drmOutput];
|
||||
if (output.surfaceInterface) {
|
||||
if (output.scanoutSurface) {
|
||||
qCDebug(KWIN_DRM) << "Direct scanout stopped on output" << output.output->name();
|
||||
}
|
||||
output.surfaceInterface = nullptr;
|
||||
output.scanoutSurface = nullptr;
|
||||
if (output.scanoutCandidate) {
|
||||
output.oldScanoutCandidate = output.scanoutCandidate;
|
||||
output.scanoutCandidate = nullptr;
|
||||
} else if (output.oldScanoutCandidate && output.oldScanoutCandidate->dmabufFeedbackV1()) {
|
||||
output.oldScanoutCandidate->dmabufFeedbackV1()->setTranches({});
|
||||
}
|
||||
if (isPrimary()) {
|
||||
return prepareRenderingForOutput(output);
|
||||
} else {
|
||||
|
@ -616,10 +623,31 @@ bool EglGbmBackend::scanout(AbstractOutput *drmOutput, SurfaceItem *surfaceItem)
|
|||
if (buffer->size() != output.output->modeSize()) {
|
||||
return false;
|
||||
}
|
||||
if (!buffer->planes().count()) {
|
||||
return false;
|
||||
if (output.oldScanoutCandidate && output.oldScanoutCandidate != surface) {
|
||||
output.oldScanoutCandidate->dmabufFeedbackV1()->setTranches({});
|
||||
output.oldScanoutCandidate = nullptr;
|
||||
}
|
||||
if (!output.output->isFormatSupported(buffer->format())) {
|
||||
output.scanoutCandidate = surface;
|
||||
const auto &sendFeedback = [&output, this]() {
|
||||
if (const auto &drmOutput = qobject_cast<DrmOutput *>(output.output); drmOutput && output.scanoutCandidate->dmabufFeedbackV1()) {
|
||||
KWaylandServer::LinuxDmaBufV1Feedback::Tranche tranche;
|
||||
tranche.device = m_gpu->deviceId();
|
||||
tranche.flags = KWaylandServer::LinuxDmaBufV1Feedback::TrancheFlag::Scanout;
|
||||
// atm no format changes are sent as those might require a modeset
|
||||
// and thus require more elaborate feedback
|
||||
const auto &mods = drmOutput->pipeline()->supportedModifiers(m_gbmFormat);
|
||||
for (const auto &mod : mods) {
|
||||
tranche.formatTable[m_gbmFormat] << mod;
|
||||
}
|
||||
if (tranche.formatTable.isEmpty()) {
|
||||
output.scanoutCandidate->dmabufFeedbackV1()->setTranches({});
|
||||
} else {
|
||||
output.scanoutCandidate->dmabufFeedbackV1()->setTranches({tranche});
|
||||
}
|
||||
}
|
||||
};
|
||||
if (!buffer->planes().count() || !output.output->isFormatSupported(buffer->format())) {
|
||||
sendFeedback();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -629,6 +657,7 @@ bool EglGbmBackend::scanout(AbstractOutput *drmOutput, SurfaceItem *surfaceItem)
|
|||
|| planes.first().offset > 0
|
||||
|| planes.count() > 1) {
|
||||
if (!m_gpu->addFB2ModifiersSupported() || !output.output->supportedModifiers(buffer->format()).contains(planes.first().modifier)) {
|
||||
sendFeedback();
|
||||
return false;
|
||||
}
|
||||
gbm_import_fd_modifier_data data = {};
|
||||
|
@ -654,6 +683,7 @@ bool EglGbmBackend::scanout(AbstractOutput *drmOutput, SurfaceItem *surfaceItem)
|
|||
importedBuffer = gbm_bo_import(m_gpu->gbmDevice(), GBM_BO_IMPORT_FD, &data, GBM_BO_USE_SCANOUT);
|
||||
}
|
||||
if (!importedBuffer) {
|
||||
sendFeedback();
|
||||
if (errno != EINVAL) {
|
||||
qCWarning(KWIN_DRM) << "Importing buffer for direct scanout failed:" << strerror(errno);
|
||||
}
|
||||
|
@ -661,7 +691,7 @@ bool EglGbmBackend::scanout(AbstractOutput *drmOutput, SurfaceItem *surfaceItem)
|
|||
}
|
||||
// damage tracking for screen casting
|
||||
QRegion damage;
|
||||
if (output.surfaceInterface == surface && buffer->size() == output.output->modeSize()) {
|
||||
if (output.scanoutSurface == surface && buffer->size() == output.output->modeSize()) {
|
||||
QRegion trackedDamage = surfaceItem->damage();
|
||||
surfaceItem->resetDamage();
|
||||
for (const auto &rect : trackedDamage) {
|
||||
|
@ -677,13 +707,14 @@ bool EglGbmBackend::scanout(AbstractOutput *drmOutput, SurfaceItem *surfaceItem)
|
|||
makeCurrent();
|
||||
if (output.output->present(bo, damage)) {
|
||||
output.current.damageJournal.clear();
|
||||
if (output.surfaceInterface != surface) {
|
||||
if (output.scanoutSurface != surface) {
|
||||
auto path = surface->client()->executablePath();
|
||||
qCDebug(KWIN_DRM).nospace() << "Direct scanout starting on output " << output.output->name() << " for application \"" << path << "\"";
|
||||
}
|
||||
output.surfaceInterface = surface;
|
||||
output.scanoutSurface = surface;
|
||||
return true;
|
||||
} else {
|
||||
sendFeedback();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <kwinglutils.h>
|
||||
|
||||
#include <QPointer>
|
||||
#include <QSharedPointer>
|
||||
|
||||
struct gbm_surface;
|
||||
|
@ -94,7 +95,9 @@ private:
|
|||
QSharedPointer<DumbSwapchain> importSwapchain;
|
||||
} old, current;
|
||||
|
||||
KWaylandServer::SurfaceInterface *surfaceInterface = nullptr;
|
||||
KWaylandServer::SurfaceInterface *scanoutSurface = nullptr;
|
||||
QPointer<KWaylandServer::SurfaceInterface> scanoutCandidate;
|
||||
QPointer<KWaylandServer::SurfaceInterface> oldScanoutCandidate;
|
||||
};
|
||||
|
||||
bool doesRenderFit(DrmAbstractOutput *output, const Output::RenderData &render);
|
||||
|
|
|
@ -53,9 +53,9 @@ KWaylandServer::LinuxDmaBufV1ClientBuffer *LinuxDmaBufV1RendererInterface::impor
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void LinuxDmaBufV1RendererInterface::setSupportedFormatsAndModifiers(const QHash<uint32_t, QSet<uint64_t>> &set)
|
||||
void LinuxDmaBufV1RendererInterface::setSupportedFormatsAndModifiers(dev_t device, const QHash<uint32_t, QSet<uint64_t>> &set)
|
||||
{
|
||||
waylandServer()->linuxDmabuf()->setSupportedFormatsWithModifiers(set);
|
||||
waylandServer()->linuxDmabuf()->setSupportedFormatsWithModifiers(device, set);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ public:
|
|||
quint32 flags) override;
|
||||
|
||||
protected:
|
||||
void setSupportedFormatsAndModifiers(const QHash<uint32_t, QSet<uint64_t>> &set);
|
||||
void setSupportedFormatsAndModifiers(dev_t device, const QHash<uint32_t, QSet<uint64_t>> &set);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -38,7 +38,8 @@ static bool isOpenGLES_helper()
|
|||
|
||||
AbstractEglBackend *AbstractEglBackend::s_primaryBackend = nullptr;
|
||||
|
||||
AbstractEglBackend::AbstractEglBackend()
|
||||
AbstractEglBackend::AbstractEglBackend(dev_t deviceId)
|
||||
: m_deviceId(deviceId)
|
||||
{
|
||||
if (s_primaryBackend == nullptr) {
|
||||
setPrimaryBackend(this);
|
||||
|
@ -387,4 +388,8 @@ QSharedPointer<GLTexture> AbstractEglBackend::textureForOutput(AbstractOutput *r
|
|||
return texture;
|
||||
}
|
||||
|
||||
dev_t AbstractEglBackend::deviceId() const
|
||||
{
|
||||
return m_deviceId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,8 +70,10 @@ public:
|
|||
return this == s_primaryBackend;
|
||||
}
|
||||
|
||||
dev_t deviceId() const;
|
||||
|
||||
protected:
|
||||
AbstractEglBackend();
|
||||
AbstractEglBackend(dev_t deviceId = 0);
|
||||
void setEglDisplay(const EGLDisplay &display);
|
||||
void setSurface(const EGLSurface &surface);
|
||||
void setConfig(const EGLConfig &config);
|
||||
|
@ -101,6 +103,7 @@ private:
|
|||
// note: m_dmaBuf is nullptr if this is not the primary backend
|
||||
EglDmabuf *m_dmaBuf = nullptr;
|
||||
QList<QByteArray> m_clientExtensions;
|
||||
const dev_t m_deviceId;
|
||||
|
||||
static AbstractEglBackend * s_primaryBackend;
|
||||
};
|
||||
|
|
|
@ -435,8 +435,7 @@ void EglDmabuf::setSupportedFormatsAndModifiers()
|
|||
}
|
||||
set.insert(format, QSet<uint64_t>());
|
||||
}
|
||||
|
||||
LinuxDmaBufV1RendererInterface::setSupportedFormatsAndModifiers(set);
|
||||
LinuxDmaBufV1RendererInterface::setSupportedFormatsAndModifiers(m_backend->deviceId(), set);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue