backends/drm: refactor format choosing and prefer alpha formats

Prefering alpha is needed for some interactions with video underlays; more
directly choosing formats with an alpha channel will be needed for overlay
planes, too.
This commit is contained in:
Xaver Hugl 2022-04-08 04:35:08 +02:00
parent 5cf2e1e84d
commit 432fb52788
4 changed files with 45 additions and 66 deletions

View file

@ -161,42 +161,19 @@ bool EglGbmBackend::initBufferConfigs()
GbmFormat format;
format.drmFormat = gbmFormat;
EGLint red, green, blue;
// Query number of bits for color channel
eglGetConfigAttrib(eglDisplay(), configs[i], EGL_RED_SIZE, &format.redSize);
eglGetConfigAttrib(eglDisplay(), configs[i], EGL_GREEN_SIZE, &format.greenSize);
eglGetConfigAttrib(eglDisplay(), configs[i], EGL_BLUE_SIZE, &format.blueSize);
eglGetConfigAttrib(eglDisplay(), configs[i], EGL_RED_SIZE, &red);
eglGetConfigAttrib(eglDisplay(), configs[i], EGL_GREEN_SIZE, &green);
eglGetConfigAttrib(eglDisplay(), configs[i], EGL_BLUE_SIZE, &blue);
eglGetConfigAttrib(eglDisplay(), configs[i], EGL_ALPHA_SIZE, &format.alphaSize);
if (m_formats.contains(format)) {
format.bpp = red + green + blue;
if (m_formats.contains(gbmFormat)) {
continue;
}
m_formats << format;
m_formats[gbmFormat] = format;
m_configs[format.drmFormat] = configs[i];
}
QVector<int> colorDepthOrder = {30, 24};
bool ok = false;
const int preferred = qEnvironmentVariableIntValue("KWIN_DRM_PREFER_COLOR_DEPTH", &ok);
if (ok) {
colorDepthOrder.prepend(preferred);
}
std::sort(m_formats.begin(), m_formats.end(), [&colorDepthOrder](const auto &lhs, const auto &rhs) {
const int ls = lhs.redSize + lhs.greenSize + lhs.blueSize;
const int rs = rhs.redSize + rhs.greenSize + rhs.blueSize;
if (ls == rs) {
return lhs.alphaSize < rhs.alphaSize;
} else {
for (const int &d : qAsConst(colorDepthOrder)) {
if (ls == d) {
return true;
} else if (rs == d) {
return false;
}
}
return ls > rs;
}
});
if (!m_formats.isEmpty()) {
return true;
}
@ -242,23 +219,11 @@ QSharedPointer<GLTexture> EglGbmBackend::textureForOutput(AbstractOutput *output
return static_cast<EglGbmLayer *>(drmOutput->outputLayer())->texture();
}
GbmFormat EglGbmBackend::gbmFormatForDrmFormat(uint32_t format) const
std::optional<GbmFormat> EglGbmBackend::gbmFormatForDrmFormat(uint32_t format) const
{
// TODO use a hardcoded lookup table where needed instead?
const auto it = std::find_if(m_formats.begin(), m_formats.end(), [format](const auto &gbmFormat) {
return gbmFormat.drmFormat == format;
});
if (it == m_formats.end()) {
return GbmFormat{
.drmFormat = DRM_FORMAT_XRGB8888,
.redSize = 8,
.greenSize = 8,
.blueSize = 8,
.alphaSize = 0,
};
} else {
return *it;
}
const auto it = m_formats.constFind(format);
return it == m_formats.constEnd() ? std::optional<GbmFormat>() : *it;
}
bool EglGbmBackend::prefer10bpc() const

View file

@ -12,6 +12,7 @@
#include <kwinglutils.h>
#include <QHash>
#include <QPointer>
#include <QSharedPointer>
#include <optional>
@ -44,9 +45,7 @@ class DrmPipeline;
struct GbmFormat
{
uint32_t drmFormat = 0;
EGLint redSize = -1;
EGLint greenSize = -1;
EGLint blueSize = -1;
uint32_t bpp;
EGLint alphaSize = -1;
};
bool operator==(const GbmFormat &lhs, const GbmFormat &rhs);
@ -76,7 +75,7 @@ public:
QSharedPointer<DrmBuffer> testBuffer(DrmAbstractOutput *output);
EGLConfig config(uint32_t format) const;
GbmFormat gbmFormatForDrmFormat(uint32_t format) const;
std::optional<GbmFormat> gbmFormatForDrmFormat(uint32_t format) const;
DrmGpu *gpu() const;
Q_SIGNALS:
@ -88,8 +87,8 @@ private:
bool initRenderingContext();
DrmBackend *m_backend;
QVector<GbmFormat> m_formats;
QMap<uint32_t, EGLConfig> m_configs;
QHash<uint32_t, GbmFormat> m_formats;
QHash<uint32_t, EGLConfig> m_configs;
friend class EglGbmTexture;
};

View file

@ -100,7 +100,7 @@ OutputLayerBeginFrameInfo EglGbmLayer::beginFrame()
m_shadowBuffer = m_oldShadowBuffer;
} else {
if (m_pipeline->pending.bufferTransformation != m_pipeline->pending.sourceTransformation) {
const auto format = m_eglBackend->gbmFormatForDrmFormat(m_gbmSurface->format());
const auto format = m_eglBackend->gbmFormatForDrmFormat(m_gbmSurface->format()).value();
m_shadowBuffer = QSharedPointer<ShadowBuffer>::create(m_pipeline->sourceSize(), format);
if (!m_shadowBuffer->isComplete()) {
return {};
@ -238,18 +238,35 @@ bool EglGbmLayer::createGbmSurface(uint32_t format, const QVector<uint64_t> &mod
bool EglGbmLayer::createGbmSurface()
{
const auto tranches = m_eglBackend->dmabuf()->tranches();
for (const auto &tranche : tranches) {
for (auto it = tranche.formatTable.constBegin(); it != tranche.formatTable.constEnd(); it++) {
const uint32_t &format = it.key();
if (m_importMode == MultiGpuImportMode::DumbBufferXrgb8888 && format != DRM_FORMAT_XRGB8888) {
continue;
}
if (m_pipeline->isFormatSupported(format) && createGbmSurface(format, m_pipeline->supportedModifiers(format))) {
return true;
}
const auto formats = m_pipeline->supportedFormats();
QVector<GbmFormat> sortedFormats;
for (auto it = formats.begin(); it != formats.end(); it++) {
const auto format = m_eglBackend->gbmFormatForDrmFormat(it.key());
if (format.has_value()) {
sortedFormats << format.value();
}
}
std::sort(sortedFormats.begin(), sortedFormats.end(), [this](const auto &lhs, const auto &rhs) {
if (lhs.drmFormat == rhs.drmFormat) {
// prefer having an alpha channel
return lhs.alphaSize > rhs.alphaSize;
} else if (m_eglBackend->prefer10bpc() && ((lhs.bpp == 30) != (rhs.bpp == 30))) {
// prefer 10bpc / 30bpp formats
return lhs.bpp == 30 ? true : false;
} else {
// fallback
return lhs.drmFormat < rhs.drmFormat;
}
});
for (const auto &format : qAsConst(sortedFormats)) {
if (m_importMode == MultiGpuImportMode::DumbBufferXrgb8888 && format.drmFormat != DRM_FORMAT_XRGB8888) {
continue;
}
if (formats.contains(format.drmFormat) && createGbmSurface(format.drmFormat, formats[format.drmFormat])) {
return true;
}
}
qCCritical(KWIN_DRM, "Failed to create a gbm surface!");
return false;
}

View file

@ -108,12 +108,10 @@ uint32_t ShadowBuffer::drmFormat() const
GLint ShadowBuffer::internalFormat(const GbmFormat &format) const
{
if (format.redSize <= 8 && format.greenSize <= 8 && format.blueSize <= 8) {
if (format.bpp <= 24) {
return GL_RGBA8;
} else if (format.redSize <= 10 && format.greenSize <= 10 && format.blueSize <= 10) {
} else if (format.bpp <= 30) {
return GL_RGB10_A2;
} else if (format.redSize <= 12 && format.greenSize <= 12 && format.blueSize <= 12) {
return GL_RGBA12;
} else {
return GL_RGBA16;
}