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.
This commit is contained in:
parent
cfeeb817bf
commit
f2b29e3555
19 changed files with 237 additions and 65 deletions
|
@ -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];
|
||||
}
|
||||
|
||||
if (fallbackConfig) {
|
||||
m_gbmFormat = fallbackFormat;
|
||||
setConfig(fallbackConfig);
|
||||
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;
|
||||
}
|
||||
|
||||
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…
Reference in a new issue