7283c98f27
When we switch CRTCs it can happen that a CRTC would stay enabled yet has no connectors anymore. In this case the kernel may reject our atomic commit, which would cause the modeset to fail. To counteract that, properly disable unused drm objects
217 lines
7.5 KiB
C++
217 lines
7.5 KiB
C++
/*
|
|
KWin - the KDE window manager
|
|
This file is part of the KDE project.
|
|
|
|
SPDX-FileCopyrightText: 2016 Roman Gilg <subdiff@gmail.com>
|
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
#include "drm_object_plane.h"
|
|
#include "drm_buffer.h"
|
|
#include "drm_gpu.h"
|
|
#include "drm_pointer.h"
|
|
#include "logging.h"
|
|
#include "config-kwin.h"
|
|
|
|
#include <drm_fourcc.h>
|
|
|
|
namespace KWin
|
|
{
|
|
|
|
DrmPlane::DrmPlane(DrmGpu *gpu, uint32_t planeId)
|
|
: DrmObject(gpu, planeId, {
|
|
PropertyDefinition(QByteArrayLiteral("type"), Requirement::Required, {
|
|
QByteArrayLiteral("Overlay"),
|
|
QByteArrayLiteral("Primary"),
|
|
QByteArrayLiteral("Cursor")}),
|
|
PropertyDefinition(QByteArrayLiteral("SRC_X"), Requirement::Required),
|
|
PropertyDefinition(QByteArrayLiteral("SRC_Y"), Requirement::Required),
|
|
PropertyDefinition(QByteArrayLiteral("SRC_W"), Requirement::Required),
|
|
PropertyDefinition(QByteArrayLiteral("SRC_H"), Requirement::Required),
|
|
PropertyDefinition(QByteArrayLiteral("CRTC_X"), Requirement::Required),
|
|
PropertyDefinition(QByteArrayLiteral("CRTC_Y"), Requirement::Required),
|
|
PropertyDefinition(QByteArrayLiteral("CRTC_W"), Requirement::Required),
|
|
PropertyDefinition(QByteArrayLiteral("CRTC_H"), Requirement::Required),
|
|
PropertyDefinition(QByteArrayLiteral("FB_ID"), Requirement::Required),
|
|
PropertyDefinition(QByteArrayLiteral("CRTC_ID"), Requirement::Required),
|
|
PropertyDefinition(QByteArrayLiteral("rotation"), Requirement::Optional, {
|
|
QByteArrayLiteral("rotate-0"),
|
|
QByteArrayLiteral("rotate-90"),
|
|
QByteArrayLiteral("rotate-180"),
|
|
QByteArrayLiteral("rotate-270"),
|
|
QByteArrayLiteral("reflect-x"),
|
|
QByteArrayLiteral("reflect-y")}),
|
|
PropertyDefinition(QByteArrayLiteral("IN_FORMATS"), Requirement::Optional),
|
|
}, DRM_MODE_OBJECT_PLANE)
|
|
{
|
|
}
|
|
|
|
bool DrmPlane::init()
|
|
{
|
|
DrmScopedPointer<drmModePlane> p(drmModeGetPlane(gpu()->fd(), id()));
|
|
|
|
if (!p) {
|
|
qCWarning(KWIN_DRM) << "Failed to get kernel plane" << id();
|
|
return false;
|
|
}
|
|
|
|
m_possibleCrtcs = p->possible_crtcs;
|
|
|
|
bool success = initProps();
|
|
if (success) {
|
|
m_supportedTransformations = Transformations();
|
|
auto checkSupport = [this] (uint64_t value, Transformation t) {
|
|
if (propHasEnum(PropertyIndex::Rotation, value)) {
|
|
m_supportedTransformations |= t;
|
|
}
|
|
};
|
|
checkSupport(0, Transformation::Rotate0);
|
|
checkSupport(1, Transformation::Rotate90);
|
|
checkSupport(2, Transformation::Rotate180);
|
|
checkSupport(3, Transformation::Rotate270);
|
|
checkSupport(4, Transformation::ReflectX);
|
|
checkSupport(5, Transformation::ReflectY);
|
|
|
|
// read formats from blob if available and if modifiers are supported, and from the plane object if not
|
|
bool modifiersEnvSet = false;
|
|
bool modifiersEnv = qEnvironmentVariableIntValue("KWIN_DRM_USE_MODIFIERS", &modifiersEnvSet) != 0;
|
|
bool allowModifiers = (gpu()->isNVidia() && !modifiersEnvSet) || (modifiersEnvSet && modifiersEnv);
|
|
if (auto formatProp = getProp(PropertyIndex::In_Formats); formatProp && gpu()->addFB2ModifiersSupported() && allowModifiers) {
|
|
DrmScopedPointer<drmModePropertyBlobRes> propertyBlob(drmModeGetPropertyBlob(gpu()->fd(), formatProp->current()));
|
|
if (propertyBlob && propertyBlob->data) {
|
|
auto blob = static_cast<drm_format_modifier_blob*>(propertyBlob->data);
|
|
auto modifiers = reinterpret_cast<drm_format_modifier*>(reinterpret_cast<uint8_t*>(blob) + blob->modifiers_offset);
|
|
uint32_t *formatarr = reinterpret_cast<uint32_t*>(reinterpret_cast<uint8_t*>(blob) + blob->formats_offset);
|
|
|
|
for (uint32_t f = 0; f < blob->count_formats; f++) {
|
|
auto format = formatarr[f];
|
|
QVector<uint64_t> mods;
|
|
for (uint32_t m = 0; m < blob->count_modifiers; m++) {
|
|
auto modifier = &modifiers[m];
|
|
// The modifier advertisement blob is partitioned into groups of 64 formats
|
|
if (m < modifier->offset || m > modifier->offset + 63) {
|
|
continue;
|
|
}
|
|
if (!(modifier->formats & (1 << (f - modifier->offset)))) {
|
|
continue;
|
|
}
|
|
mods << modifier->modifier;
|
|
}
|
|
m_supportedFormats.insert(format, mods);
|
|
}
|
|
}
|
|
} else {
|
|
for (uint32_t i = 0; i < p->count_formats; i++) {
|
|
m_supportedFormats.insert(p->formats[i], {});
|
|
}
|
|
}
|
|
if (m_supportedFormats.isEmpty()) {
|
|
qCWarning(KWIN_DRM) << "Driver doesn't advertise any formats for this plane. Falling back to XRGB8888 and ARGB8888 without modifiers";
|
|
m_supportedFormats.insert(DRM_FORMAT_XRGB8888, {});
|
|
m_supportedFormats.insert(DRM_FORMAT_ARGB8888, {});
|
|
}
|
|
}
|
|
return success;
|
|
}
|
|
|
|
DrmPlane::TypeIndex DrmPlane::type()
|
|
{
|
|
const auto &prop = getProp(PropertyIndex::Type);
|
|
return prop->enumForValue<DrmPlane::TypeIndex>(prop->current());
|
|
}
|
|
|
|
void DrmPlane::setNext(const QSharedPointer<DrmBuffer> &b)
|
|
{
|
|
m_next = b;
|
|
}
|
|
|
|
bool DrmPlane::setTransformation(Transformations t)
|
|
{
|
|
if (m_supportedTransformations & t) {
|
|
return setPending(PropertyIndex::Rotation, t);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
DrmPlane::Transformations DrmPlane::transformation()
|
|
{
|
|
if (auto property = getProp(PropertyIndex::Rotation)) {
|
|
return Transformations(static_cast<uint32_t>(property->pending()));
|
|
}
|
|
return Transformations(Transformation::Rotate0);
|
|
}
|
|
|
|
void DrmPlane::flipBuffer()
|
|
{
|
|
m_current = m_next;
|
|
m_next = nullptr;
|
|
}
|
|
|
|
void DrmPlane::set(const QPoint &srcPos, const QSize &srcSize, const QPoint &dstPos, const QSize &dstSize)
|
|
{
|
|
// Src* are in 16.16 fixed point format
|
|
setPending(PropertyIndex::SrcX, srcPos.x() << 16);
|
|
setPending(PropertyIndex::SrcY, srcPos.y() << 16);
|
|
setPending(PropertyIndex::SrcW, srcSize.width() << 16);
|
|
setPending(PropertyIndex::SrcH, srcSize.height() << 16);
|
|
setPending(PropertyIndex::CrtcX, dstPos.x());
|
|
setPending(PropertyIndex::CrtcY, dstPos.y());
|
|
setPending(PropertyIndex::CrtcW, dstSize.width());
|
|
setPending(PropertyIndex::CrtcH, dstSize.height());
|
|
}
|
|
|
|
void DrmPlane::setBuffer(DrmBuffer *buffer)
|
|
{
|
|
setPending(PropertyIndex::FbId, buffer ? buffer->bufferId() : 0);
|
|
}
|
|
|
|
bool DrmPlane::needsModeset() const
|
|
{
|
|
if (!gpu()->atomicModeSetting()) {
|
|
return false;
|
|
}
|
|
auto rotation = getProp(PropertyIndex::Rotation);
|
|
if (rotation && rotation->needsCommit()) {
|
|
return true;
|
|
}
|
|
return getProp(PropertyIndex::CrtcId)->needsCommit();
|
|
}
|
|
|
|
bool DrmPlane::isCrtcSupported(int pipeIndex) const
|
|
{
|
|
return (m_possibleCrtcs & (1 << pipeIndex));
|
|
}
|
|
|
|
QMap<uint32_t, QVector<uint64_t>> DrmPlane::formats() const
|
|
{
|
|
return m_supportedFormats;
|
|
}
|
|
|
|
QSharedPointer<DrmBuffer> DrmPlane::current() const
|
|
{
|
|
return m_current;
|
|
}
|
|
|
|
QSharedPointer<DrmBuffer> DrmPlane::next() const
|
|
{
|
|
return m_next;
|
|
}
|
|
|
|
void DrmPlane::setCurrent(const QSharedPointer<DrmBuffer> &b)
|
|
{
|
|
m_current = b;
|
|
}
|
|
|
|
DrmPlane::Transformations DrmPlane::supportedTransformations() const
|
|
{
|
|
return m_supportedTransformations;
|
|
}
|
|
|
|
void DrmPlane::disable()
|
|
{
|
|
setPending(PropertyIndex::CrtcId, 0);
|
|
setPending(PropertyIndex::FbId, 0);
|
|
}
|
|
|
|
}
|