[platforms/drm] Move cursor dumb buffers to Output

Summary:
So far all outputs shared the same dumb buffer for the cursor image.
This doesn't work any more when screen rotation is enabled. For rotated
screens the cursor image per output is different. On some it might be
rotated, on some not.

To solve this problem the dumb buffers are moved from the DrmBackend to
the DrmOutput. The DrmOutput now creates the cursor images itself and
can rotate them if needed. Thus we get nicely transformed cursors.

Test Plan: Rotated screens, moved cursor around, image properly rotated

Reviewers: #kwin, #plasma

Subscribers: plasma-devel, kwin

Tags: #kwin

Differential Revision: https://phabricator.kde.org/D8664
icc-effect-5.14.5
Martin Flöser 2017-11-05 11:59:24 +01:00
parent 1a6662e796
commit c9c26019a1
4 changed files with 74 additions and 33 deletions

View File

@ -74,8 +74,6 @@ DrmBackend::DrmBackend(QObject *parent)
, m_dpmsFilter()
{
handleOutputs();
m_cursor[0] = nullptr;
m_cursor[1] = nullptr;
}
DrmBackend::~DrmBackend()
@ -94,8 +92,6 @@ DrmBackend::~DrmBackend()
qDeleteAll(m_planes);
qDeleteAll(m_crtcs);
qDeleteAll(m_connectors);
delete m_cursor[0];
delete m_cursor[1];
close(m_fd);
}
}
@ -170,7 +166,6 @@ void DrmBackend::reactivate()
}
m_active = true;
if (!usesSoftwareCursor()) {
DrmDumbBuffer *c = m_cursor[(m_cursorIndex + 1) % 2];
const QPoint cp = Cursor::pos() - softwareCursorHotspot();
for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) {
DrmOutput *o = *it;
@ -178,7 +173,7 @@ void DrmBackend::reactivate()
o->m_modesetRequested = true;
o->pageFlipped(); // TODO: Do we really need this?
o->m_crtc->blank();
o->showCursor(c);
o->showCursor();
o->moveCursor(cp);
}
}
@ -327,6 +322,7 @@ void DrmBackend::openDrm()
m_crtcs.erase(std::remove_if(m_crtcs.begin(), m_crtcs.end(), tryAtomicInit), m_crtcs.end());
}
initCursor();
updateOutputs();
if (m_outputs.isEmpty()) {
@ -353,7 +349,6 @@ void DrmBackend::openDrm()
if (device->hasProperty("HOTPLUG", "1")) {
qCDebug(KWIN_DRM) << "Received hot plug event for monitored drm device";
updateOutputs();
m_cursorIndex = (m_cursorIndex + 1) % 2;
updateCursor();
}
}
@ -362,8 +357,6 @@ void DrmBackend::openDrm()
}
}
setReady(true);
initCursor();
}
void DrmBackend::updateOutputs()
@ -467,6 +460,9 @@ void DrmBackend::updateOutputs()
delete output;
continue;
}
if (!output->initCursor(m_cursorSize)) {
setSoftWareCursor(true);
}
qCDebug(KWIN_DRM) << "Found new output with uuid" << output->uuid();
connectedOutputs << output;
@ -594,7 +590,7 @@ void DrmBackend::initCursor()
}
for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) {
if (m_cursorEnabled) {
(*it)->showCursor(m_cursor[m_cursorIndex]);
(*it)->showCursor();
} else {
(*it)->hideCursor();
}
@ -613,18 +609,7 @@ void DrmBackend::initCursor()
} else {
cursorSize.setHeight(64);
}
auto createCursor = [this, cursorSize] (int index) {
m_cursor[index] = createBuffer(cursorSize);
if (!m_cursor[index]->map(QImage::Format_ARGB32_Premultiplied)) {
return false;
}
m_cursor[index]->image()->fill(Qt::transparent);
return true;
};
if (!createCursor(0) || !createCursor(1)) {
setSoftWareCursor(true);
return;
}
m_cursorSize = cursorSize;
// now we have screens and can set cursors, so start tracking
connect(this, &DrmBackend::cursorChanged, this, &DrmBackend::updateCursor);
connect(Cursor::self(), &Cursor::posChanged, this, &DrmBackend::moveCursor);
@ -632,11 +617,9 @@ void DrmBackend::initCursor()
void DrmBackend::setCursor()
{
DrmDumbBuffer *c = m_cursor[m_cursorIndex];
m_cursorIndex = (m_cursorIndex + 1) % 2;
if (m_cursorEnabled) {
for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) {
(*it)->showCursor(c);
(*it)->showCursor();
}
}
markCursorAsRendered();
@ -655,12 +638,9 @@ void DrmBackend::updateCursor()
doHideCursor();
return;
}
QImage *c = m_cursor[m_cursorIndex]->image();
c->fill(Qt::transparent);
QPainter p;
p.begin(c);
p.drawImage(QPoint(0, 0), cursorImage);
p.end();
for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) {
(*it)->updateCursor();
}
setCursor();
moveCursor();

View File

@ -158,11 +158,10 @@ private:
QVector<DrmConnector*> m_connectors;
// currently active output pipelines (planes + crtc + encoder + connector)
QVector<DrmOutput*> m_outputs;
DrmDumbBuffer *m_cursor[2];
bool m_deleteBufferAfterPageFlip;
bool m_atomicModeSetting = false;
bool m_cursorEnabled = false;
int m_cursorIndex = 0;
QSize m_cursorSize;
int m_pageFlipsPending = 0;
bool m_active = false;
// all available planes: primarys, cursors and overlays

View File

@ -45,6 +45,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// Qt
#include <QMatrix4x4>
#include <QCryptographicHash>
#include <QPainter>
// drm
#include <xf86drm.h>
#include <xf86drmMode.h>
@ -80,6 +81,8 @@ DrmOutput::~DrmOutput()
delete m_waylandOutput.data();
delete m_waylandOutputDevice.data();
delete m_cursor[0];
delete m_cursor[1];
}
void DrmOutput::releaseGbm()
@ -103,6 +106,37 @@ void DrmOutput::showCursor(DrmDumbBuffer *c)
drmModeSetCursor(m_backend->fd(), m_crtc->id(), c->handle(), s.width(), s.height());
}
void DrmOutput::showCursor()
{
showCursor(m_cursor[m_cursorIndex]);
if (m_hasNewCursor) {
m_cursorIndex = (m_cursorIndex + 1) % 2;
m_hasNewCursor = false;
}
}
void DrmOutput::updateCursor()
{
QImage cursorImage = m_backend->softwareCursor();
if (cursorImage.isNull()) {
return;
}
m_hasNewCursor = true;
QImage *c = m_cursor[m_cursorIndex]->image();
c->fill(Qt::transparent);
QPainter p;
p.begin(c);
if (m_orientation == Qt::InvertedLandscapeOrientation) {
QMatrix4x4 matrix;
matrix.translate(cursorImage.width() / 2.0, cursorImage.height() / 2.0);
matrix.rotate(180.0f, 0.0f, 0.0f, 1.0f);
matrix.translate(-cursorImage.width() / 2.0, -cursorImage.height() / 2.0);
p.setWorldTransform(matrix.toTransform());
}
p.drawImage(QPoint(0, 0), cursorImage);
p.end();
}
void DrmOutput::moveCursor(const QPoint &globalPos)
{
QMatrix4x4 matrix;
@ -787,6 +821,9 @@ bool DrmOutput::commitChanges()
break;
}
m_modesetRequested = true;
// the cursor might need to get rotated
updateCursor();
showCursor();
emit modeChanged();
}
if (m_changeset->positionChanged()) {
@ -926,6 +963,9 @@ bool DrmOutput::presentAtomically(DrmBuffer *buffer)
m_primaryPlane->setTransformation(m_lastWorkingState.planeTransformations);
}
m_modesetRequested = true;
// the cursor might need to get rotated
updateCursor();
showCursor();
// TODO: forward to OutputInterface and OutputDeviceInterface
emit modeChanged();
emit screens()->changed();
@ -1122,4 +1162,19 @@ bool DrmOutput::atomicReqModesetPopulate(drmModeAtomicReq *req, bool enable)
return ret;
}
bool DrmOutput::initCursor(const QSize &cursorSize)
{
auto createCursor = [this, cursorSize] (int index) {
m_cursor[index] = m_backend->createBuffer(cursorSize);
if (!m_cursor[index]->map(QImage::Format_ARGB32_Premultiplied)) {
return false;
}
return true;
};
if (!createCursor(0) || !createCursor(1)) {
return false;
}
return true;
}
}

View File

@ -65,7 +65,9 @@ public:
virtual ~DrmOutput();
void releaseGbm();
void showCursor(DrmDumbBuffer *buffer);
void showCursor();
void hideCursor();
void updateCursor();
void moveCursor(const QPoint &globalPos);
bool init(drmModeConnector *connector);
bool present(DrmBuffer *buffer);
@ -106,6 +108,8 @@ public:
QSize physicalSize() const;
bool initCursor(const QSize &cursorSize);
Q_SIGNALS:
void dpmsChanged();
void modeChanged();
@ -174,6 +178,9 @@ private:
QPoint globalPos;
bool valid = false;
} m_lastWorkingState;
DrmDumbBuffer *m_cursor[2] = {nullptr, nullptr};
int m_cursorIndex = 0;
bool m_hasNewCursor = false;
};
}