backends/drm: deep color support

This commit makes 10 bits per color channel the default color depth, which
should reduce banding on outputs that support color formats with more than
8 bits per color channel. In order to support this the commit also removes
the dependency of the EglGbmBackend on a specific format and EglConfig and
instead makes those per-Output properties.
master
Xaver Hugl 3 years ago
parent cfeeb817bf
commit f2b29e3555

@ -33,6 +33,10 @@ public:
virtual QSize sourceSize() const = 0;
virtual bool isFormatSupported(uint32_t drmFormat) const = 0;
virtual QVector<uint64_t> supportedModifiers(uint32_t drmFormat) const = 0;
/**
* returns the maximum bits per color channel that make sense to be used for this output
*/
virtual int maxBpc() const = 0;
DrmGpu *gpu() const;
RenderLoop *renderLoop() const override;

@ -100,6 +100,7 @@ DrmConnector::DrmConnector(DrmGpu *gpu, uint32_t connectorId)
QByteArrayLiteral("Full"),
QByteArrayLiteral("Limited 16:235")
}),
PropertyDefinition(QByteArrayLiteral("max bpc"), Requirement::Optional),
}, DRM_MODE_OBJECT_CONNECTOR)
, m_pipeline(new DrmPipeline(this))
, m_conn(drmModeGetConnector(gpu->fd(), connectorId))
@ -295,6 +296,9 @@ bool DrmConnector::needsModeset() const
if (getProp(PropertyIndex::CrtcId)->needsCommit()) {
return true;
}
if (const auto &prop = getProp(PropertyIndex::MaxBpc); prop && prop->needsCommit()) {
return true;
}
const auto &rgb = getProp(PropertyIndex::Broadcast_RGB);
return rgb && rgb->needsCommit();
}
@ -380,6 +384,11 @@ bool DrmConnector::updateProperties()
m_physicalSize = overwriteSize;
}
if (auto bpc = getProp(PropertyIndex::MaxBpc)) {
// make sure the driver allows us to use high bpc
bpc->setPending(bpc->maxValue());
}
// init modes
updateModes();

@ -65,6 +65,7 @@ public:
Underscan_vborder = 7,
Underscan_hborder = 8,
Broadcast_RGB = 9,
MaxBpc = 10,
Count
};

@ -485,4 +485,10 @@ void DrmOutput::presentFailed()
RenderLoopPrivate::get(m_renderLoop)->notifyFrameFailed();
}
int DrmOutput::maxBpc() const
{
auto prop = m_connector->getProp(DrmConnector::PropertyIndex::MaxBpc);
return prop ? prop->maxValue() : 8;
}
}

@ -57,6 +57,7 @@ public:
bool isFormatSupported(uint32_t drmFormat) const override;
QVector<uint64_t> supportedModifiers(uint32_t drmFormat) const override;
bool needsSoftwareTransformation() const override;
int maxBpc() const override;
bool queueChanges(const WaylandOutputConfig &config);
void applyQueuedChanges(const WaylandOutputConfig &config);

@ -299,7 +299,7 @@ bool DrmPipeline::checkTestBuffer()
// try to re-use buffers if possible.
const auto &checkBuffer = [this, backend, &buffer](const QSharedPointer<DrmBuffer> &buf){
const auto &mods = supportedModifiers(buf->format());
if (backend && buf->format() == backend->drmFormat()
if (backend && buf->format() == backend->drmFormat(m_output)
&& (mods.isEmpty() || mods.contains(buf->modifier()))
&& buf->size() == sourceSize()) {
buffer = buf;

@ -109,4 +109,9 @@ bool DrmVirtualOutput::needsSoftwareTransformation() const
return false;
}
int DrmVirtualOutput::maxBpc() const
{
return 8;
}
}

@ -33,6 +33,7 @@ public:
bool isFormatSupported(uint32_t drmFormat) const override;
QVector<uint64_t> supportedModifiers(uint32_t drmFormat) const override;
int maxBpc() const override;
int gammaRampSize() const override;
bool setGammaRamp(const GammaRamp &gamma) override;

@ -149,8 +149,15 @@ bool EglGbmBackend::initRenderingContext()
bool EglGbmBackend::resetOutput(Output &output)
{
std::optional<GbmFormat> gbmFormat = chooseFormat(output);
if (!gbmFormat.has_value()) {
qCCritical(KWIN_DRM) << "Could not find a suitable format for output" << output.output;
return false;
}
output.current.format = gbmFormat.value();
uint32_t format = gbmFormat.value().drmFormat;
const QSize size = output.output->sourceSize();
QVector<uint64_t> modifiers = output.output->supportedModifiers(m_gbmFormat);
QVector<uint64_t> modifiers = output.output->supportedModifiers(format);
QSharedPointer<GbmSurface> gbmSurface;
bool modifiersEnvSet = false;
@ -168,14 +175,14 @@ bool EglGbmBackend::resetOutput(Output &output)
} else {
flags |= GBM_BO_USE_LINEAR;
}
gbmSurface = QSharedPointer<GbmSurface>::create(m_gpu, size, m_gbmFormat, flags);
gbmSurface = QSharedPointer<GbmSurface>::create(m_gpu, size, format, flags, m_configs[format]);
} else {
gbmSurface = QSharedPointer<GbmSurface>::create(m_gpu, size, m_gbmFormat, modifiers);
gbmSurface = QSharedPointer<GbmSurface>::create(m_gpu, size, format, modifiers, m_configs[format]);
if (!gbmSurface->isValid()) {
// the egl / gbm implementation may reject the modifier list from another gpu
// as a fallback use linear, to at least make CPU copy more efficient
modifiers = {DRM_FORMAT_MOD_LINEAR};
gbmSurface = QSharedPointer<GbmSurface>::create(m_gpu, size, m_gbmFormat, modifiers);
gbmSurface = QSharedPointer<GbmSurface>::create(m_gpu, size, format, modifiers, m_configs[format]);
}
}
if (!gbmSurface->isValid()) {
@ -191,7 +198,7 @@ bool EglGbmBackend::resetOutput(Output &output)
output.current.shadowBuffer = nullptr;
} else {
makeContextCurrent(output.current);
output.current.shadowBuffer = QSharedPointer<ShadowBuffer>::create(output.output->pixelSize());
output.current.shadowBuffer = QSharedPointer<ShadowBuffer>::create(output.output->pixelSize(), output.current.format);
if (!output.current.shadowBuffer->isComplete()) {
return false;
}
@ -391,10 +398,7 @@ bool EglGbmBackend::initBufferConfigs()
return false;
}
qCDebug(KWIN_DRM) << "EGL buffer configs count:" << count;
uint32_t fallbackFormat = 0;
EGLConfig fallbackConfig = nullptr;
setConfig(EGL_NO_CONFIG_KHR);
// Loop through all configs, choosing the first one that has suitable format.
for (EGLint i = 0; i < count; i++) {
@ -405,32 +409,49 @@ bool EglGbmBackend::initBufferConfigs()
continue;
}
GbmFormat format;
format.drmFormat = gbmFormat;
// Query number of bits for color channel
EGLint blueSize, redSize, greenSize, alphaSize;
eglGetConfigAttrib(eglDisplay(), configs[i], EGL_RED_SIZE, &redSize);
eglGetConfigAttrib(eglDisplay(), configs[i], EGL_GREEN_SIZE, &greenSize);
eglGetConfigAttrib(eglDisplay(), configs[i], EGL_BLUE_SIZE, &blueSize);
eglGetConfigAttrib(eglDisplay(), configs[i], EGL_ALPHA_SIZE, &alphaSize);
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_ALPHA_SIZE, &format.alphaSize);
// prefer XRGB8888 as it's most likely to be supported by secondary GPUs as well
if (gbmFormat == GBM_FORMAT_XRGB8888) {
m_gbmFormat = gbmFormat;
setConfig(configs[i]);
return true;
} else if (!fallbackConfig && blueSize >= 8 && redSize >= 8 && greenSize >= 8) {
fallbackFormat = gbmFormat;
fallbackConfig = configs[i];
if (m_formats.contains(format)) {
continue;
}
m_formats << 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);
}
if (fallbackConfig) {
m_gbmFormat = fallbackFormat;
setConfig(fallbackConfig);
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;
}
qCCritical(KWIN_DRM) << "Choosing EGL config did not return a suitable config. There were"
<< count << "configs:";
qCCritical(KWIN_DRM, "Choosing EGL config did not return a supported config. There were %u configs", count);
for (EGLint i = 0; i < count; i++) {
EGLint gbmFormat, blueSize, redSize, greenSize, alphaSize;
eglGetConfigAttrib(eglDisplay(), configs[i], EGL_NATIVE_VISUAL_ID, &gbmFormat);
@ -637,9 +658,9 @@ bool EglGbmBackend::scanout(AbstractOutput *drmOutput, SurfaceItem *surfaceItem)
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);
const auto &mods = drmOutput->pipeline()->supportedModifiers(output.current.format.drmFormat);
for (const auto &mod : mods) {
tranche.formatTable[m_gbmFormat] << mod;
tranche.formatTable[output.current.format.drmFormat] << mod;
}
if (tranche.formatTable.isEmpty()) {
output.scanoutCandidate->dmabufFeedbackV1()->setTranches({});
@ -760,9 +781,10 @@ bool EglGbmBackend::hasOutput(AbstractOutput *output) const
return m_outputs.contains(output);
}
uint32_t EglGbmBackend::drmFormat() const
uint32_t EglGbmBackend::drmFormat(DrmAbstractOutput *output) const
{
return m_gbmFormat;
const auto &o = m_outputs[output];
return o.output ? o.current.format.drmFormat : DRM_FORMAT_XRGB8888;
}
DrmGpu *EglGbmBackend::gpu() const
@ -770,9 +792,38 @@ DrmGpu *EglGbmBackend::gpu() const
return m_gpu;
}
std::optional<GbmFormat> EglGbmBackend::chooseFormat(Output &output) const
{
// formats are already sorted by order of preference
std::optional<GbmFormat> fallback;
for (const auto &format : qAsConst(m_formats)) {
if (output.output->isFormatSupported(format.drmFormat)) {
int bpc = std::max(format.redSize, std::max(format.greenSize, format.blueSize));
if (bpc <= output.output->maxBpc() && !fallback.has_value()) {
fallback = format;
} else {
return format;
}
}
}
return fallback;
}
EglGbmBackend *EglGbmBackend::renderingBackend()
{
return static_cast<EglGbmBackend*>(primaryBackend());
}
bool EglGbmBackend::prefer10bpc() const
{
static bool ok = false;
static const int preferred = qEnvironmentVariableIntValue("KWIN_DRM_PREFER_COLOR_DEPTH", &ok);
return !ok || preferred == 30;
}
bool operator==(const GbmFormat &lhs, const GbmFormat &rhs)
{
return lhs.drmFormat == rhs.drmFormat;
}
}

@ -15,6 +15,7 @@
#include <QPointer>
#include <QSharedPointer>
#include <optional>
struct gbm_surface;
struct gbm_bo;
@ -38,6 +39,15 @@ class ShadowBuffer;
class DrmBackend;
class DrmGpu;
struct GbmFormat {
uint32_t drmFormat;
EGLint redSize;
EGLint greenSize;
EGLint blueSize;
EGLint alphaSize;
};
bool operator==(const GbmFormat &lhs, const GbmFormat &rhs);
/**
* @brief OpenGL Backend using Egl on a GBM surface.
*/
@ -55,6 +65,7 @@ public:
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
void init() override;
bool scanout(AbstractOutput *output, SurfaceItem *surfaceItem) override;
bool prefer10bpc() const override;
QSharedPointer<GLTexture> textureForOutput(AbstractOutput *requestedOutput) const override;
@ -66,7 +77,7 @@ public:
bool directScanoutAllowed(AbstractOutput *output) const override;
QSharedPointer<DrmBuffer> renderTestFrame(DrmAbstractOutput *output);
uint32_t drmFormat() const;
uint32_t drmFormat(DrmAbstractOutput *output) const;
DrmGpu *gpu() const;
protected:
@ -89,6 +100,7 @@ private:
QSharedPointer<GbmSurface> gbmSurface;
int bufferAge = 0;
DamageJournal damageJournal;
GbmFormat format;
// for secondary GPU import
ImportMode importMode = ImportMode::Dmabuf;
@ -113,13 +125,15 @@ private:
QSharedPointer<DrmBuffer> importFramebuffer(Output &output, const QRegion &dirty) const;
QSharedPointer<DrmBuffer> endFrameWithBuffer(AbstractOutput *output, const QRegion &dirty);
void updateBufferAge(Output &output, const QRegion &dirty);
std::optional<GbmFormat> chooseFormat(Output &output) const;
void cleanupRenderData(Output::RenderData &output);
QMap<AbstractOutput *, Output> m_outputs;
uint32_t m_gbmFormat;
DrmBackend *m_backend;
DrmGpu *m_gpu;
QVector<GbmFormat> m_formats;
QMap<uint32_t, EGLConfig> m_configs;
static EglGbmBackend *renderingBackend();

@ -19,31 +19,33 @@
namespace KWin
{
GbmSurface::GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, uint32_t flags)
GbmSurface::GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, uint32_t flags, EGLConfig config)
: m_surface(gbm_surface_create(gpu->gbmDevice(), size.width(), size.height(), format, flags))
, m_gpu(gpu)
, m_size(size)
, m_format(format)
{
if (!m_surface) {
qCCritical(KWIN_DRM) << "Could not create gbm surface!" << strerror(errno);
return;
}
m_eglSurface = eglCreatePlatformWindowSurfaceEXT(m_gpu->eglDisplay(), m_gpu->eglBackend()->config(), m_surface, nullptr);
m_eglSurface = eglCreatePlatformWindowSurfaceEXT(m_gpu->eglDisplay(), config, m_surface, nullptr);
if (m_eglSurface == EGL_NO_SURFACE) {
qCCritical(KWIN_DRM) << "Creating EGL surface failed!" << getEglErrorString();
}
}
GbmSurface::GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, QVector<uint64_t> modifiers)
GbmSurface::GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, QVector<uint64_t> modifiers, EGLConfig config)
: m_surface(gbm_surface_create_with_modifiers(gpu->gbmDevice(), size.width(), size.height(), format, modifiers.isEmpty() ? nullptr : modifiers.constData(), modifiers.count()))
, m_gpu(gpu)
, m_size(size)
, m_format(format)
{
if (!m_surface) {
qCCritical(KWIN_DRM) << "Could not create gbm surface!" << strerror(errno);
return;
}
m_eglSurface = eglCreatePlatformWindowSurfaceEXT(m_gpu->eglDisplay(), m_gpu->eglBackend()->config(), m_surface, nullptr);
m_eglSurface = eglCreatePlatformWindowSurfaceEXT(m_gpu->eglDisplay(), config, m_surface, nullptr);
if (m_eglSurface == EGL_NO_SURFACE) {
qCCritical(KWIN_DRM) << "Creating EGL surface failed!" << getEglErrorString();
}
@ -131,4 +133,9 @@ bool GbmSurface::isValid() const
return m_surface != nullptr && m_eglSurface != EGL_NO_SURFACE;
}
uint32_t GbmSurface::format() const
{
return m_format;
}
}

@ -24,8 +24,8 @@ namespace KWin
class GbmSurface
{
public:
explicit GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, uint32_t flags);
explicit GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, QVector<uint64_t> modifiers);
explicit GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, uint32_t flags, EGLConfig config);
explicit GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, QVector<uint64_t> modifiers, EGLConfig config);
~GbmSurface();
QSharedPointer<DrmGbmBuffer> swapBuffersForDrm();
@ -39,12 +39,14 @@ public:
EGLSurface eglSurface() const;
QSize size() const;
bool isValid() const;
uint32_t format() const;
private:
gbm_surface *m_surface;
DrmGpu *m_gpu;
EGLSurface m_eglSurface = EGL_NO_SURFACE;
QSize m_size;
const uint32_t m_format;
QSharedPointer<GbmBuffer> m_currentBuffer;
QSharedPointer<DrmGbmBuffer> m_currentDrmBuffer;

@ -34,7 +34,7 @@ static const float texCoords[] = {
1.0f, 1.0f
};
ShadowBuffer::ShadowBuffer(const QSize &size)
ShadowBuffer::ShadowBuffer(const QSize &size, const GbmFormat &format)
: m_size(size)
{
glGenFramebuffers(1, &m_framebuffer);
@ -43,7 +43,7 @@ ShadowBuffer::ShadowBuffer(const QSize &size)
glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_2D, m_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat(format), size.width(), size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
@ -134,4 +134,17 @@ QSize ShadowBuffer::textureSize() const
return m_size;
}
GLint ShadowBuffer::internalFormat(const GbmFormat &format)
{
if (format.redSize <= 8 && format.greenSize <= 8 && format.blueSize <= 8) {
return GL_RGBA8;
} else if (format.redSize <= 10 && format.greenSize <= 10 && format.blueSize <= 10) {
return GL_RGB10_A2;
} else if (format.redSize <= 12 && format.greenSize <= 12 && format.blueSize <= 12) {
return GL_RGBA12;
} else {
return GL_RGBA16;
}
}
}

@ -11,6 +11,8 @@
#include <QSize>
#include <kwinglutils.h>
#include "egl_gbm_backend.h"
namespace KWin
{
@ -19,7 +21,7 @@ class DrmAbstractOutput;
class ShadowBuffer
{
public:
ShadowBuffer(const QSize &size);
ShadowBuffer(const QSize &size, const GbmFormat &format);
~ShadowBuffer();
bool isComplete() const;
@ -32,6 +34,7 @@ public:
QSize textureSize() const;
private:
GLint internalFormat(const GbmFormat &format);
GLuint m_texture;
GLuint m_framebuffer;
QScopedPointer<GLVertexBuffer> m_vbo;

@ -53,9 +53,9 @@ KWaylandServer::LinuxDmaBufV1ClientBuffer *LinuxDmaBufV1RendererInterface::impor
return nullptr;
}
void LinuxDmaBufV1RendererInterface::setSupportedFormatsAndModifiers(dev_t device, const QHash<uint32_t, QSet<uint64_t>> &set)
void LinuxDmaBufV1RendererInterface::setSupportedFormatsAndModifiers(const QVector<KWaylandServer::LinuxDmaBufV1Feedback::Tranche> &tranches)
{
waylandServer()->linuxDmabuf()->setSupportedFormatsWithModifiers(device, set);
waylandServer()->linuxDmabuf()->setSupportedFormatsWithModifiers(tranches);
}
}

@ -37,7 +37,7 @@ public:
quint32 flags) override;
protected:
void setSupportedFormatsAndModifiers(dev_t device, const QHash<uint32_t, QSet<uint64_t>> &set);
void setSupportedFormatsAndModifiers(const QVector<KWaylandServer::LinuxDmaBufV1Feedback::Tranche> &tranches);
};
}

@ -392,4 +392,10 @@ dev_t AbstractEglBackend::deviceId() const
{
return m_deviceId;
}
bool AbstractEglBackend::prefer10bpc() const
{
return false;
}
}

@ -71,6 +71,7 @@ public:
}
dev_t deviceId() const;
virtual bool prefer10bpc() const;
protected:
AbstractEglBackend(dev_t deviceId = 0);

@ -395,6 +395,34 @@ void filterFormatsWithMultiplePlanes(QVector<uint32_t> &formats)
}
}
static int bpcForFormat(uint32_t format)
{
switch(format) {
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_RGBX8888:
case DRM_FORMAT_BGRX8888:
case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_ABGR8888:
case DRM_FORMAT_RGBA8888:
case DRM_FORMAT_BGRA8888:
case DRM_FORMAT_RGB888:
case DRM_FORMAT_BGR888:
return 8;
case DRM_FORMAT_XRGB2101010:
case DRM_FORMAT_XBGR2101010:
case DRM_FORMAT_RGBX1010102:
case DRM_FORMAT_BGRX1010102:
case DRM_FORMAT_ARGB2101010:
case DRM_FORMAT_ABGR2101010:
case DRM_FORMAT_RGBA1010102:
case DRM_FORMAT_BGRA1010102:
return 10;
default:
return -1;
}
};
void EglDmabuf::setSupportedFormatsAndModifiers()
{
const EGLDisplay eglDisplay = m_backend->eglDisplay();
@ -412,30 +440,50 @@ void EglDmabuf::setSupportedFormatsAndModifiers()
filterFormatsWithMultiplePlanes(formats);
QHash<uint32_t, QSet<uint64_t> > set;
for (auto format : qAsConst(formats)) {
if (eglQueryDmaBufModifiersEXT != nullptr) {
count = 0;
success = eglQueryDmaBufModifiersEXT(eglDisplay, format, 0, nullptr, nullptr, &count);
if (success && count > 0) {
QVector<uint64_t> modifiers(count);
if (eglQueryDmaBufModifiersEXT(eglDisplay,
format, count, modifiers.data(),
nullptr, &count)) {
QSet<uint64_t> modifiersSet;
for (auto mod : qAsConst(modifiers)) {
modifiersSet.insert(mod);
auto queryFormats = [&formats, &eglDisplay](int bpc) {
QHash<uint32_t, QSet<uint64_t>> set;
for (auto format : qAsConst(formats)) {
if (bpc != bpcForFormat(format)) {
continue;
}
if (eglQueryDmaBufModifiersEXT != nullptr) {
EGLint count = 0;
const EGLBoolean success = eglQueryDmaBufModifiersEXT(eglDisplay, format, 0, nullptr, nullptr, &count);
if (success && count > 0) {
QVector<uint64_t> modifiers(count);
if (eglQueryDmaBufModifiersEXT(eglDisplay, format, count, modifiers.data(), nullptr, &count)) {
QSet<uint64_t> modifiersSet;
for (const uint64_t &mod : qAsConst(modifiers)) {
modifiersSet.insert(mod);
}
set.insert(format, modifiersSet);
continue;
}
set.insert(format, modifiersSet);
continue;
}
}
set.insert(format, QSet<uint64_t>());
}
set.insert(format, QSet<uint64_t>());
return set;
};
QVector<KWaylandServer::LinuxDmaBufV1Feedback::Tranche> tranches;
if (m_backend->prefer10bpc()) {
tranches.append({
.device = m_backend->deviceId(),
.flags = {},
.formatTable = queryFormats(10),
});
}
LinuxDmaBufV1RendererInterface::setSupportedFormatsAndModifiers(m_backend->deviceId(), set);
tranches.append({
.device = m_backend->deviceId(),
.flags = {},
.formatTable = queryFormats(8),
});
tranches.append({
.device = m_backend->deviceId(),
.flags = {},
.formatTable = queryFormats(-1),
});
LinuxDmaBufV1RendererInterface::setSupportedFormatsAndModifiers(tranches);
}
}

Loading…
Cancel
Save