Fix scanout device information when running nested kwin

Without it, there are issues with running Xwayland.
This commit is contained in:
Vlad Zahorodnii 2024-04-26 11:15:18 +03:00
parent 75ab5b8353
commit 5c93c4251b
3 changed files with 69 additions and 76 deletions

View file

@ -28,8 +28,7 @@ namespace KWin
{
EglGbmBackend::EglGbmBackend(DrmBackend *drmBackend)
: AbstractEglBackend(drmBackend->primaryGpu()->drmDevice()->deviceId())
, m_backend(drmBackend)
: m_backend(drmBackend)
{
drmBackend->setRenderBackend(this);
connect(m_backend, &DrmBackend::gpuRemoved, this, [this](DrmGpu *gpu) {

View file

@ -8,6 +8,7 @@
*/
#include "platformsupport/scenes/opengl/abstract_egl_backend.h"
#include "compositor.h"
#include "core/drmdevice.h"
#include "core/outputbackend.h"
#include "main.h"
#include "opengl/egl_context_attribute_builder.h"
@ -34,8 +35,7 @@ namespace KWin
static std::unique_ptr<EglContext> s_globalShareContext;
AbstractEglBackend::AbstractEglBackend(dev_t deviceId)
: m_deviceId(deviceId)
AbstractEglBackend::AbstractEglBackend()
{
connect(Compositor::self(), &Compositor::aboutToDestroy, this, &AbstractEglBackend::teardown);
}
@ -100,11 +100,11 @@ void AbstractEglBackend::initWayland()
return;
}
if (m_deviceId) {
if (DrmDevice *scanoutDevice = drmDevice()) {
QString renderNode = m_display->renderNode();
if (renderNode.isEmpty()) {
::drmDevice *device = nullptr;
if (drmGetDeviceFromDevId(deviceId(), 0, &device) != 0) {
if (drmGetDeviceFromDevId(scanoutDevice->deviceId(), 0, &device) != 0) {
qCWarning(KWIN_OPENGL) << "drmGetDeviceFromDevId() failed:" << strerror(errno);
} else {
if (device->available_nodes & (1 << DRM_NODE_RENDER)) {
@ -122,81 +122,82 @@ void AbstractEglBackend::initWayland()
} else {
qCWarning(KWIN_OPENGL) << "No render node have been found, not initializing wl-drm";
}
}
const auto formats = m_display->allSupportedDrmFormats();
auto filterFormats = [this, &formats](std::optional<uint32_t> bpc, bool withExternalOnlyYUV) {
QHash<uint32_t, QList<uint64_t>> set;
for (auto it = formats.constBegin(); it != formats.constEnd(); it++) {
const auto info = FormatInfo::get(it.key());
if (bpc && (!info || bpc != info->bitsPerColor)) {
continue;
}
const auto formats = m_display->allSupportedDrmFormats();
auto filterFormats = [this, &formats](std::optional<uint32_t> bpc, bool withExternalOnlyYUV) {
QHash<uint32_t, QList<uint64_t>> set;
for (auto it = formats.constBegin(); it != formats.constEnd(); it++) {
const auto info = FormatInfo::get(it.key());
if (bpc && (!info || bpc != info->bitsPerColor)) {
continue;
}
const bool externalOnlySupported = withExternalOnlyYUV && info && info->yuvConversion();
QList<uint64_t> modifiers = externalOnlySupported ? it->allModifiers : it->nonExternalOnlyModifiers;
const bool externalOnlySupported = withExternalOnlyYUV && info && info->yuvConversion();
QList<uint64_t> modifiers = externalOnlySupported ? it->allModifiers : it->nonExternalOnlyModifiers;
if (externalOnlySupported && !modifiers.isEmpty()) {
if (auto yuv = info->yuvConversion()) {
for (auto plane : std::as_const(yuv->plane)) {
const auto planeModifiers = formats.value(plane.format).allModifiers;
modifiers.erase(std::remove_if(modifiers.begin(), modifiers.end(), [&planeModifiers](uint64_t mod) {
return !planeModifiers.contains(mod);
}),
modifiers.end());
if (externalOnlySupported && !modifiers.isEmpty()) {
if (auto yuv = info->yuvConversion()) {
for (auto plane : std::as_const(yuv->plane)) {
const auto planeModifiers = formats.value(plane.format).allModifiers;
modifiers.erase(std::remove_if(modifiers.begin(), modifiers.end(), [&planeModifiers](uint64_t mod) {
return !planeModifiers.contains(mod);
}),
modifiers.end());
}
}
}
for (const auto &tranche : std::as_const(m_tranches)) {
if (modifiers.isEmpty()) {
break;
}
const auto trancheModifiers = tranche.formatTable.value(it.key());
for (auto trancheModifier : trancheModifiers) {
modifiers.removeAll(trancheModifier);
}
}
}
for (const auto &tranche : std::as_const(m_tranches)) {
if (modifiers.isEmpty()) {
break;
continue;
}
const auto trancheModifiers = tranche.formatTable.value(it.key());
for (auto trancheModifier : trancheModifiers) {
modifiers.removeAll(trancheModifier);
set.insert(it.key(), modifiers);
}
return set;
};
auto includeShaderConversions = [](QHash<uint32_t, QList<uint64_t>> &&formats) -> QHash<uint32_t, QList<uint64_t>> {
for (auto format : s_drmConversions.keys()) {
auto &modifiers = formats[format];
if (modifiers.isEmpty()) {
modifiers = {DRM_FORMAT_MOD_LINEAR};
}
}
if (modifiers.isEmpty()) {
continue;
}
set.insert(it.key(), modifiers);
}
return set;
};
return formats;
};
auto includeShaderConversions = [](QHash<uint32_t, QList<uint64_t>> &&formats) -> QHash<uint32_t, QList<uint64_t>> {
for (auto format : s_drmConversions.keys()) {
auto &modifiers = formats[format];
if (modifiers.isEmpty()) {
modifiers = {DRM_FORMAT_MOD_LINEAR};
}
}
return formats;
};
m_tranches.append({
.device = scanoutDevice->deviceId(),
.flags = {},
.formatTable = filterFormats(10, false),
});
m_tranches.append({
.device = scanoutDevice->deviceId(),
.flags = {},
.formatTable = filterFormats(8, false),
});
m_tranches.append({
.device = scanoutDevice->deviceId(),
.flags = {},
.formatTable = includeShaderConversions(filterFormats({}, true)),
});
m_tranches.append({
.device = deviceId(),
.flags = {},
.formatTable = filterFormats(10, false),
});
m_tranches.append({
.device = deviceId(),
.flags = {},
.formatTable = filterFormats(8, false),
});
m_tranches.append({
.device = deviceId(),
.flags = {},
.formatTable = includeShaderConversions(filterFormats({}, true)),
});
LinuxDmaBufV1ClientBufferIntegration *dmabuf = waylandServer()->linuxDmabuf();
dmabuf->setRenderBackend(this);
dmabuf->setSupportedFormatsWithModifiers(m_tranches);
if (auto syncObj = waylandServer()->linuxSyncObj()) {
syncObj->setRenderBackend(this);
}
}
waylandServer()->setRenderBackend(this);
LinuxDmaBufV1ClientBufferIntegration *dmabuf = waylandServer()->linuxDmabuf();
dmabuf->setRenderBackend(this);
dmabuf->setSupportedFormatsWithModifiers(m_tranches);
if (auto syncObj = waylandServer()->linuxSyncObj()) {
syncObj->setRenderBackend(this);
}
}
void AbstractEglBackend::initClientExtensions()
@ -251,11 +252,6 @@ QList<LinuxDmaBufV1Feedback::Tranche> AbstractEglBackend::tranches() const
return m_tranches;
}
dev_t AbstractEglBackend::deviceId() const
{
return m_deviceId;
}
EGLImageKHR AbstractEglBackend::importBufferAsImage(GraphicsBuffer *buffer, int plane, int format, const QSize &size)
{
std::pair key(buffer, plane);

View file

@ -40,7 +40,6 @@ public:
QHash<uint32_t, QList<uint64_t>> supportedFormats() const override;
QList<LinuxDmaBufV1Feedback::Tranche> tranches() const;
dev_t deviceId() const;
std::shared_ptr<GLTexture> importDmaBufAsTexture(const DmaBufAttributes &attributes) const;
EGLImageKHR importDmaBufAsImage(const DmaBufAttributes &attributes) const;
@ -49,7 +48,7 @@ public:
EGLImageKHR importBufferAsImage(GraphicsBuffer *buffer, int plane, int format, const QSize &size);
protected:
AbstractEglBackend(dev_t deviceId = 0);
AbstractEglBackend();
void cleanup();
virtual void cleanupSurfaces();
void setEglDisplay(EglDisplay *display);
@ -67,7 +66,6 @@ protected:
EglDisplay *m_display = nullptr;
std::shared_ptr<EglContext> m_context;
QList<QByteArray> m_clientExtensions;
const dev_t m_deviceId;
QList<LinuxDmaBufV1Feedback::Tranche> m_tranches;
QHash<std::pair<GraphicsBuffer *, int>, EGLImageKHR> m_importedBuffers;
};