[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/D8664icc-effect-5.14.5
parent
1a6662e796
commit
c9c26019a1
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue