Add a DrmOutput class to be used by the DrmBackend
The DrmOutput corresponds to one output we perform mode setting on. This implies that page flip is now performed on the DrmOutput. As our compositor cannot drive multiple outputs yet, we only use the first one and call into bufferSwapComplete and aboutToBufferSwap when either all page flips are completed or respectivly the first one is performed. Setting cursor is also handled on each DrmOutput. When the DrmOutput is initialized it is blanked with a black buffer which gets destroyed once the first page flip event has occurred (meanig the buffer is no longer needed). Before setting the black buffer we store the current buffer which will be set back on tear down. Because of that tearing down the DrmBackend needs to wait till all page flips ended.
This commit is contained in:
parent
38b676d809
commit
2f312f35c9
2 changed files with 175 additions and 43 deletions
163
drm_backend.cpp
163
drm_backend.cpp
|
@ -67,7 +67,11 @@ DrmBackend::DrmBackend(QObject *parent)
|
|||
DrmBackend::~DrmBackend()
|
||||
{
|
||||
if (m_fd >= 0) {
|
||||
hideCursor();
|
||||
// wait for pageflips
|
||||
while (m_pageFlipsPending != 0) {
|
||||
QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
|
||||
}
|
||||
qDeleteAll(m_outputs);
|
||||
delete m_cursor[0];
|
||||
delete m_cursor[1];
|
||||
close(m_fd);
|
||||
|
@ -99,15 +103,16 @@ void DrmBackend::pageFlipHandler(int fd, unsigned int frame, unsigned int sec, u
|
|||
Q_UNUSED(frame)
|
||||
Q_UNUSED(sec)
|
||||
Q_UNUSED(usec)
|
||||
DrmBuffer *buffer = reinterpret_cast<DrmBuffer*>(data);
|
||||
buffer->m_backend->m_pageFlipPending = false;
|
||||
#if HAVE_GBM
|
||||
if (buffer->m_bo) {
|
||||
gbm_surface_release_buffer(buffer->m_surface, buffer->m_bo);
|
||||
buffer->m_bo = nullptr;
|
||||
auto output = reinterpret_cast<DrmOutput*>(data);
|
||||
output->pageFlipped();
|
||||
output->m_backend->m_pageFlipsPending--;
|
||||
if (output->m_backend->m_pageFlipsPending == 0) {
|
||||
// TODO: improve, this currently means we wait for all page flips or all outputs.
|
||||
// It would be better to driver the repaint per output
|
||||
if (Compositor::self()) {
|
||||
Compositor::self()->bufferSwapComplete();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Compositor::self()->bufferSwapComplete();
|
||||
}
|
||||
|
||||
void DrmBackend::openDrm()
|
||||
|
@ -178,31 +183,28 @@ void DrmBackend::queryResources()
|
|||
if (!crtc) {
|
||||
continue;
|
||||
}
|
||||
m_resolution = QSize(crtc->mode.hdisplay, crtc->mode.vdisplay);
|
||||
m_crtcId = encoder->crtc_id;
|
||||
m_connector = connector->connector_id;
|
||||
m_mode = crtc->mode;
|
||||
// TODO: improve
|
||||
DrmBuffer *b = new DrmBuffer(this, m_resolution);
|
||||
b->map();
|
||||
b->image()->fill(Qt::black);
|
||||
drmModeSetCrtc(m_fd, m_crtcId, b->m_bufferId, 0, 0, &m_connector, 1, &m_mode);
|
||||
// for the moment only one crtc
|
||||
break;
|
||||
DrmOutput *drmOutput = new DrmOutput(this);
|
||||
drmOutput->m_crtcId = encoder->crtc_id;
|
||||
drmOutput->m_mode = crtc->mode;
|
||||
drmOutput->m_connector = connector->connector_id;
|
||||
drmOutput->init();
|
||||
m_outputs << drmOutput;
|
||||
}
|
||||
// TODO: install global space
|
||||
}
|
||||
|
||||
void DrmBackend::present(DrmBuffer *buffer)
|
||||
{
|
||||
if (!buffer || buffer->m_bufferId == 0) {
|
||||
if (m_outputs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (m_pageFlipPending) {
|
||||
return;
|
||||
// TODO: correct output
|
||||
if (m_outputs.first()->present(buffer)) {
|
||||
m_pageFlipsPending++;
|
||||
if (m_pageFlipsPending == 1 && Compositor::self()) {
|
||||
Compositor::self()->aboutToSwapBuffers();
|
||||
}
|
||||
}
|
||||
m_pageFlipPending = true;
|
||||
Compositor::self()->aboutToSwapBuffers();
|
||||
drmModePageFlip(m_fd, m_crtcId, buffer->m_bufferId, DRM_MODE_PAGE_FLIP_EVENT, buffer);
|
||||
}
|
||||
|
||||
void DrmBackend::installCursorFromServer()
|
||||
|
@ -245,7 +247,9 @@ void DrmBackend::setCursor()
|
|||
{
|
||||
DrmBuffer *c = m_cursor[m_cursorIndex];
|
||||
m_cursorIndex = (m_cursorIndex + 1) % 2;
|
||||
drmModeSetCursor(m_fd, m_crtcId, c->m_handle, c->m_size.width(), c->m_size.height());
|
||||
for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) {
|
||||
(*it)->showCursor(c);
|
||||
}
|
||||
}
|
||||
|
||||
void DrmBackend::updateCursor()
|
||||
|
@ -268,13 +272,25 @@ void DrmBackend::updateCursor()
|
|||
|
||||
void DrmBackend::hideCursor()
|
||||
{
|
||||
drmModeSetCursor(m_fd, m_crtcId, 0, 0, 0);
|
||||
for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) {
|
||||
(*it)->hideCursor();
|
||||
}
|
||||
}
|
||||
|
||||
void DrmBackend::moveCursor()
|
||||
{
|
||||
const QPoint p = Cursor::pos() - softwareCursorHotspot();
|
||||
drmModeMoveCursor(m_fd, m_crtcId, p.x(), p.y());
|
||||
for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) {
|
||||
(*it)->moveCursor(p);
|
||||
}
|
||||
}
|
||||
|
||||
QSize DrmBackend::size() const
|
||||
{
|
||||
if (m_outputs.isEmpty()) {
|
||||
return QSize();
|
||||
}
|
||||
return m_outputs.first()->size();
|
||||
}
|
||||
|
||||
Screens *DrmBackend::createScreens(QObject *parent)
|
||||
|
@ -307,6 +323,79 @@ DrmBuffer *DrmBackend::createBuffer(gbm_surface *surface)
|
|||
#endif
|
||||
}
|
||||
|
||||
DrmOutput::DrmOutput(DrmBackend *backend)
|
||||
: m_backend(backend)
|
||||
{
|
||||
}
|
||||
|
||||
DrmOutput::~DrmOutput()
|
||||
{
|
||||
hideCursor();
|
||||
if (!m_savedCrtc.isNull()) {
|
||||
drmModeSetCrtc(m_backend->fd(), m_savedCrtc->crtc_id, m_savedCrtc->buffer_id,
|
||||
m_savedCrtc->x, m_savedCrtc->y, &m_connector, 1, &m_savedCrtc->mode);
|
||||
}
|
||||
cleanupBlackBuffer();
|
||||
}
|
||||
|
||||
void DrmOutput::hideCursor()
|
||||
{
|
||||
drmModeSetCursor(m_backend->fd(), m_crtcId, 0, 0, 0);
|
||||
}
|
||||
|
||||
void DrmOutput::showCursor(DrmBuffer *c)
|
||||
{
|
||||
const QSize &s = c->size();
|
||||
drmModeSetCursor(m_backend->fd(), m_crtcId, c->handle(), s.width(), s.height());
|
||||
}
|
||||
|
||||
void DrmOutput::moveCursor(const QPoint &globalPos)
|
||||
{
|
||||
const QPoint p = globalPos - m_globalPos;
|
||||
drmModeMoveCursor(m_backend->fd(), m_crtcId, p.x(), p.y());
|
||||
}
|
||||
|
||||
QSize DrmOutput::size() const
|
||||
{
|
||||
return QSize(m_mode.hdisplay, m_mode.vdisplay);
|
||||
}
|
||||
|
||||
bool DrmOutput::present(DrmBuffer *buffer)
|
||||
{
|
||||
if (!buffer || buffer->bufferId() == 0) {
|
||||
return false;
|
||||
}
|
||||
if (m_currentBuffer) {
|
||||
return false;
|
||||
}
|
||||
m_currentBuffer = buffer;
|
||||
return drmModePageFlip(m_backend->fd(), m_crtcId, buffer->bufferId(), DRM_MODE_PAGE_FLIP_EVENT, this) == 0;
|
||||
}
|
||||
|
||||
void DrmOutput::pageFlipped()
|
||||
{
|
||||
m_currentBuffer->releaseGbm();
|
||||
m_currentBuffer = nullptr;
|
||||
cleanupBlackBuffer();
|
||||
}
|
||||
|
||||
void DrmOutput::cleanupBlackBuffer()
|
||||
{
|
||||
if (m_blackBuffer) {
|
||||
delete m_blackBuffer;
|
||||
m_blackBuffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void DrmOutput::init()
|
||||
{
|
||||
m_savedCrtc.reset(drmModeGetCrtc(m_backend->fd(), m_crtcId));
|
||||
m_blackBuffer = m_backend->createBuffer(size());
|
||||
m_blackBuffer->map();
|
||||
m_blackBuffer->image()->fill(Qt::black);
|
||||
drmModeSetCrtc(m_backend->fd(), m_crtcId, m_blackBuffer->bufferId(), 0, 0, &m_connector, 1, &m_mode);
|
||||
}
|
||||
|
||||
DrmBuffer::DrmBuffer(DrmBackend *backend, const QSize &size)
|
||||
: m_backend(backend)
|
||||
, m_size(size)
|
||||
|
@ -368,11 +457,7 @@ DrmBuffer::~DrmBuffer()
|
|||
destroyArgs.handle = m_handle;
|
||||
drmIoctl(m_backend->fd(), DRM_IOCTL_MODE_DESTROY_DUMB, &destroyArgs);
|
||||
}
|
||||
#if HAVE_GBM
|
||||
if (m_bo) {
|
||||
gbm_surface_release_buffer(m_surface, m_bo);
|
||||
}
|
||||
#endif
|
||||
releaseGbm();
|
||||
}
|
||||
|
||||
bool DrmBuffer::map(QImage::Format format)
|
||||
|
@ -395,4 +480,14 @@ bool DrmBuffer::map(QImage::Format format)
|
|||
return !m_image->isNull();
|
||||
}
|
||||
|
||||
void DrmBuffer::releaseGbm()
|
||||
{
|
||||
#if HAVE_GBM
|
||||
if (m_bo) {
|
||||
gbm_surface_release_buffer(m_surface, m_bo);
|
||||
m_bo = nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ namespace KWin
|
|||
class Udev;
|
||||
|
||||
class DrmBuffer;
|
||||
class DrmOutput;
|
||||
|
||||
class KWIN_EXPORT DrmBackend : public AbstractBackend
|
||||
{
|
||||
|
@ -53,10 +54,7 @@ public:
|
|||
DrmBuffer *createBuffer(gbm_surface *surface);
|
||||
void present(DrmBuffer *buffer);
|
||||
|
||||
QSize size() const {
|
||||
// TODO: this is wrong
|
||||
return m_resolution;
|
||||
}
|
||||
QSize size() const;
|
||||
int fd() const {
|
||||
return m_fd;
|
||||
}
|
||||
|
@ -76,14 +74,43 @@ private:
|
|||
QScopedPointer<Udev> m_udev;
|
||||
int m_fd = -1;
|
||||
int m_drmId = 0;
|
||||
// TODO: this is wrong
|
||||
QSize m_resolution;
|
||||
QVector<DrmOutput*> m_outputs;
|
||||
DrmBuffer *m_cursor[2];
|
||||
int m_cursorIndex = 0;
|
||||
int m_pageFlipsPending = 0;
|
||||
};
|
||||
|
||||
class DrmOutput
|
||||
{
|
||||
public:
|
||||
virtual ~DrmOutput();
|
||||
void showCursor(DrmBuffer *buffer);
|
||||
void hideCursor();
|
||||
void moveCursor(const QPoint &globalPos);
|
||||
bool present(DrmBuffer *buffer);
|
||||
void pageFlipped();
|
||||
void init();
|
||||
|
||||
QSize size() const;
|
||||
|
||||
private:
|
||||
friend class DrmBackend;
|
||||
DrmOutput(DrmBackend *backend);
|
||||
void cleanupBlackBuffer();
|
||||
|
||||
DrmBackend *m_backend;
|
||||
QPoint m_globalPos;
|
||||
quint32 m_crtcId = 0;
|
||||
quint32 m_connector = 0;
|
||||
drmModeModeInfo m_mode;
|
||||
bool m_pageFlipPending = false;
|
||||
DrmBuffer *m_cursor[2];
|
||||
int m_cursorIndex = 0;
|
||||
DrmBuffer *m_currentBuffer = nullptr;
|
||||
DrmBuffer *m_blackBuffer = nullptr;
|
||||
struct CrtcCleanup {
|
||||
static void inline cleanup(_drmModeCrtc *ptr) {
|
||||
drmModeFreeCrtc(ptr);
|
||||
}
|
||||
};
|
||||
QScopedPointer<_drmModeCrtc, CrtcCleanup> m_savedCrtc;
|
||||
};
|
||||
|
||||
class DrmBuffer
|
||||
|
@ -95,6 +122,16 @@ public:
|
|||
QImage *image() const {
|
||||
return m_image;
|
||||
}
|
||||
quint32 handle() const {
|
||||
return m_handle;
|
||||
}
|
||||
const QSize &size() const {
|
||||
return m_size;
|
||||
}
|
||||
quint32 bufferId() const {
|
||||
return m_bufferId;
|
||||
}
|
||||
void releaseGbm();
|
||||
|
||||
private:
|
||||
friend class DrmBackend;
|
||||
|
|
Loading…
Reference in a new issue