Commit 33a4cf40 authored by Martin Flöser's avatar Martin Flöser

[drm] Implement changing of modes

Summary:
This change hooks up the bits for changing the mode when a request to
change mode from kscreen is received. This includes:
 * setting new mode in DrmOutput
 * creating new buffers in SceneQPainter backend
 * creating new GbmSurface in SceneOpenGL backend

Room for improvement:
 * detect whether the new mode works and go back to old one if it fails

Test Plan:
Started both a QPainter/OpenGL session. Used kcmshell5 kscreen
to modify the resolution. Saw that it got applied, maximized a window to
verify it's correct. Changed back to original resolution. Verified it looked
good by maximizing a window.

Reviewers: #kwin, #plasma, subdiff, sebas

Subscribers: plasma-devel, kwin

Tags: #kwin

Differential Revision: https://phabricator.kde.org/D8398
parent a5b17b22
......@@ -696,6 +696,7 @@ bool DrmOutput::commitChanges()
if (m_changeset->modeChanged()) {
qCDebug(KWIN_DRM) << "Setting new mode:" << m_changeset->mode();
m_waylandOutputDevice->setCurrentMode(m_changeset->mode());
updateMode(m_changeset->mode());
// FIXME: implement for wl_output
}
if (m_changeset->transformChanged()) {
......@@ -717,6 +718,24 @@ bool DrmOutput::commitChanges()
return true;
}
void DrmOutput::updateMode(int modeIndex)
{
// get all modes on the connector
ScopedDrmPointer<_drmModeConnector, &drmModeFreeConnector> connector(drmModeGetConnector(m_backend->fd(), m_conn->id()));
if (connector->count_modes <= modeIndex) {
// TODO: error?
return;
}
if (isCurrentMode(&connector->modes[modeIndex])) {
// nothing to do
return;
}
m_previousMode = m_mode;
m_mode = connector->modes[modeIndex];
m_modesetRequested = true;
emit modeChanged();
}
void DrmOutput::pageFlipped()
{
m_pageFlipPending = false;
......
......@@ -109,6 +109,7 @@ public:
Q_SIGNALS:
void dpmsChanged();
void modeChanged();
private:
friend class DrmBackend;
......@@ -139,6 +140,7 @@ private:
void dpmsOffHandler();
bool dpmsAtomicOff();
bool atomicReqModesetPopulate(drmModeAtomicReq *req, bool enable);
void updateMode(int modeIndex);
DrmBackend *m_backend;
DrmConnector *m_conn = nullptr;
......@@ -147,6 +149,7 @@ private:
qreal m_scale = 1;
bool m_lastGbm = false;
drmModeModeInfo m_mode;
drmModeModeInfo m_previousMode;
Edid m_edid;
QPointer<KWayland::Server::OutputInterface> m_waylandOutput;
QPointer<KWayland::Server::OutputDeviceInterface> m_waylandOutputDevice;
......
......@@ -150,25 +150,51 @@ bool EglGbmBackend::initRenderingContext()
return makeContextCurrent(m_outputs.first());
}
void EglGbmBackend::createOutput(DrmOutput *drmOutput)
bool EglGbmBackend::resetOutput(Output &o, DrmOutput *drmOutput)
{
Output o;
o.output = drmOutput;
auto size = drmOutput->pixelSize();
o.gbmSurface = std::make_shared<GbmSurface>(m_backend->gbmDevice(), size.width(), size.height(),
auto gbmSurface = std::make_shared<GbmSurface>(m_backend->gbmDevice(), size.width(), size.height(),
GBM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
if (!o.gbmSurface) {
if (!gbmSurface) {
qCCritical(KWIN_DRM) << "Create gbm surface failed";
return;
return false;
}
o.eglSurface = eglCreatePlatformWindowSurfaceEXT(eglDisplay(), config(), (void *)(o.gbmSurface->surface()), nullptr);
if (o.eglSurface == EGL_NO_SURFACE) {
auto eglSurface = eglCreatePlatformWindowSurfaceEXT(eglDisplay(), config(), (void *)(gbmSurface->surface()), nullptr);
if (eglSurface == EGL_NO_SURFACE) {
qCCritical(KWIN_DRM) << "Create Window Surface failed";
o.gbmSurface.reset();
return;
return false;
} else {
// destroy previous surface
if (o.eglSurface != EGL_NO_SURFACE) {
eglDestroySurface(eglDisplay(), eglSurface);
}
o.eglSurface = eglSurface;
o.gbmSurface = gbmSurface;
}
return true;
}
void EglGbmBackend::createOutput(DrmOutput *drmOutput)
{
Output o;
if (resetOutput(o, drmOutput)) {
connect(drmOutput, &DrmOutput::modeChanged, this,
[drmOutput, this] {
auto it = std::find_if(m_outputs.begin(), m_outputs.end(),
[drmOutput] (const auto &o) {
return o.output == drmOutput;
}
);
if (it == m_outputs.end()) {
return;
}
resetOutput(*it, drmOutput);
}
);
m_outputs << o;
}
m_outputs << o;
}
bool EglGbmBackend::makeContextCurrent(const Output &output)
......
......@@ -70,6 +70,7 @@ private:
*/
QList<QRegion> damageHistory;
};
bool resetOutput(Output &output, DrmOutput *drmOutput);
bool makeContextCurrent(const Output &output);
void presentOnOutput(Output &output);
void cleanupOutput(const Output &output);
......
......@@ -68,6 +68,27 @@ void DrmQPainterBackend::initOutput(DrmOutput *output)
o.buffer[index]->map();
o.buffer[index]->image()->fill(Qt::black);
};
connect(output, &DrmOutput::modeChanged, this,
[output, this] {
auto it = std::find_if(m_outputs.begin(), m_outputs.end(),
[output] (const auto &o) {
return o.output == output;
}
);
if (it == m_outputs.end()) {
return;
}
delete (*it).buffer[0];
delete (*it).buffer[1];
auto initBuffer = [it, output, this] (int index) {
it->buffer[index] = m_backend->createBuffer(output->pixelSize());
it->buffer[index]->map();
it->buffer[index]->image()->fill(Qt::black);
};
initBuffer(0);
initBuffer(1);
}
);
initBuffer(0);
initBuffer(1);
o.output = output;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment