diff --git a/src/plugins/platforms/drm/drm_gpu.cpp b/src/plugins/platforms/drm/drm_gpu.cpp
index e4b23cfad5..e080ad8653 100644
--- a/src/plugins/platforms/drm/drm_gpu.cpp
+++ b/src/plugins/platforms/drm/drm_gpu.cpp
@@ -275,9 +275,8 @@ bool DrmGpu::updateOutputs()
                 output->m_conn = con;
                 output->m_crtc = crtc;
                 output->m_primaryPlane = primary;
-                output->m_mode = connector->modes[0];
 
-                if (!output->init(connector.data())) {
+                if (!output->init()) {
                     qCWarning(KWIN_DRM) << "Failed to create output for connector " << con->id();
                     delete output;
                     continue;
diff --git a/src/plugins/platforms/drm/drm_object_connector.cpp b/src/plugins/platforms/drm/drm_object_connector.cpp
index cb061ed6a3..1a66cfdc0e 100644
--- a/src/plugins/platforms/drm/drm_object_connector.cpp
+++ b/src/plugins/platforms/drm/drm_object_connector.cpp
@@ -3,6 +3,7 @@
     This file is part of the KDE project.
 
     SPDX-FileCopyrightText: 2016 Roman Gilg <subdiff@gmail.com>
+    SPDX-FileCopyrightText: 2021 Xaver Hugl <xaver.hugl@gmail.com>
 
     SPDX-License-Identifier: GPL-2.0-or-later
 */
@@ -35,6 +36,25 @@ DrmConnector::DrmConnector(DrmGpu *gpu, uint32_t connectorId)
 
 DrmConnector::~DrmConnector() = default;
 
+namespace {
+quint64 refreshRateForMode(_drmModeModeInfo *m)
+{
+    // Calculate higher precision (mHz) refresh rate
+    // logic based on Weston, see compositor-drm.c
+    quint64 refreshRate = (m->clock * 1000000LL / m->htotal + m->vtotal / 2) / m->vtotal;
+    if (m->flags & DRM_MODE_FLAG_INTERLACE) {
+        refreshRate *= 2;
+    }
+    if (m->flags & DRM_MODE_FLAG_DBLSCAN) {
+        refreshRate /= 2;
+    }
+    if (m->vscan > 1) {
+        refreshRate /= m->vscan;
+    }
+    return refreshRate;
+}
+}
+
 bool DrmConnector::init()
 {
     if (!m_conn || !m_conn->count_modes) {
@@ -108,16 +128,26 @@ bool DrmConnector::init()
         m_physicalSize = overwriteSize;
     }
 
+    // init modes
+    for (int i = 0; i < m_conn->count_modes; i++) {
+        auto mode = m_conn->modes[i];
+        Mode m;
+        m.mode = mode;
+        m.size = QSize(mode.hdisplay, mode.vdisplay);
+        m.refreshRate = refreshRateForMode(&mode);
+        m_modes << m;
+    }
+
     return true;
 }
 
 bool DrmConnector::isConnected()
 {
-    DrmScopedPointer<drmModeConnector> con(drmModeGetConnector(gpu()->fd(), id()));
-    if (!con) {
+    m_conn.reset(drmModeGetConnector(gpu()->fd(), id()));
+    if (!m_conn) {
         return false;
     }
-    return con->connection == DRM_MODE_CONNECTED;
+    return m_conn->connection == DRM_MODE_CONNECTED;
 }
 
 static QHash<int, QByteArray> s_connectorNames = {
@@ -168,6 +198,73 @@ QSize DrmConnector::physicalSize() const
     return m_physicalSize;
 }
 
+const DrmConnector::Mode &DrmConnector::currentMode() const
+{
+    return m_modes[m_modeIndex];
+}
+
+int DrmConnector::currentModeIndex() const
+{
+    return m_modeIndex;
+}
+
+const QVector<DrmConnector::Mode> &DrmConnector::modes()
+{
+    return m_modes;
+}
+
+void DrmConnector::setModeIndex(int index)
+{
+    m_modeIndex = index;
+}
+
+static bool checkIfEqual(drmModeModeInfo one, drmModeModeInfo two)
+{
+    return one.clock       == two.clock
+        && one.hdisplay    == two.hdisplay
+        && one.hsync_start == two.hsync_start
+        && one.hsync_end   == two.hsync_end
+        && one.htotal      == two.htotal
+        && one.hskew       == two.hskew
+        && one.vdisplay    == two.vdisplay
+        && one.vsync_start == two.vsync_start
+        && one.vsync_end   == two.vsync_end
+        && one.vtotal      == two.vtotal
+        && one.vscan       == two.vscan
+        && one.vrefresh    == two.vrefresh;
+}
+
+void DrmConnector::findCurrentMode(drmModeModeInfo currentMode)
+{
+    for (int i = 0; i < m_modes.count(); i++) {
+        if (checkIfEqual(m_modes[i].mode, currentMode)) {
+            m_modeIndex = i;
+            return;
+        }
+    }
+    m_modeIndex = 0;
+}
+
+AbstractWaylandOutput::SubPixel DrmConnector::subpixel() const
+{
+    switch (m_conn->subpixel) {
+    case DRM_MODE_SUBPIXEL_UNKNOWN:
+        return AbstractWaylandOutput::SubPixel::Unknown;
+    case DRM_MODE_SUBPIXEL_NONE:
+        return AbstractWaylandOutput::SubPixel::None;
+    case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
+        return AbstractWaylandOutput::SubPixel::Horizontal_RGB;
+    case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
+        return AbstractWaylandOutput::SubPixel::Horizontal_BGR;
+    case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
+        return AbstractWaylandOutput::SubPixel::Vertical_RGB;
+    case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
+        return AbstractWaylandOutput::SubPixel::Vertical_BGR;
+    default:
+        Q_UNREACHABLE();
+    }
+}
+
 bool DrmConnector::hasOverscan() const
 {
     return m_props[static_cast<uint32_t>(PropertyIndex::Overscan)] || m_props[static_cast<uint32_t>(PropertyIndex::Underscan)];
diff --git a/src/plugins/platforms/drm/drm_object_connector.h b/src/plugins/platforms/drm/drm_object_connector.h
index 34dedafd7c..89ae8ee1fb 100644
--- a/src/plugins/platforms/drm/drm_object_connector.h
+++ b/src/plugins/platforms/drm/drm_object_connector.h
@@ -3,16 +3,21 @@
     This file is part of the KDE project.
 
     SPDX-FileCopyrightText: 2016 Roman Gilg <subdiff@gmail.com>
+    SPDX-FileCopyrightText: 2021 Xaver Hugl <xaver.hugl@gmail.com>
 
     SPDX-License-Identifier: GPL-2.0-or-later
 */
-#ifndef KWIN_DRM_OBJECT_CONNECTOR_H
-#define KWIN_DRM_OBJECT_CONNECTOR_H
+#pragma once
+
+#include <QPoint>
+#include <QSize>
 
 #include <QSize>
 
 #include "drm_object.h"
 #include "edid.h"
+#include "drm_pointer.h"
+#include "abstract_wayland_output.h"
 
 namespace KWin
 {
@@ -72,6 +77,19 @@ public:
     bool isInternal() const;
     QSize physicalSize() const;
 
+    struct Mode {
+        drmModeModeInfo mode;
+        QSize size;
+        uint32_t refreshRate;
+    };
+    const Mode &currentMode() const;
+    int currentModeIndex() const;
+    const QVector<Mode> &modes();
+    void setModeIndex(int index);
+    void findCurrentMode(drmModeModeInfo currentMode);
+
+    AbstractWaylandOutput::SubPixel subpixel() const;
+
     bool hasOverscan() const;
     uint32_t overscan() const;
     void setOverscan(uint32_t overscan, const QSize &modeSize);
@@ -83,10 +101,9 @@ private:
     QVector<uint32_t> m_encoders;
     Edid m_edid;
     QSize m_physicalSize = QSize(-1, -1);
+    QVector<Mode> m_modes;
+    int m_modeIndex = 0;
 
 };
 
 }
-
-#endif
-
diff --git a/src/plugins/platforms/drm/drm_object_crtc.cpp b/src/plugins/platforms/drm/drm_object_crtc.cpp
index 0fe81131f2..cc5686ac43 100644
--- a/src/plugins/platforms/drm/drm_object_crtc.cpp
+++ b/src/plugins/platforms/drm/drm_object_crtc.cpp
@@ -108,4 +108,10 @@ bool DrmCrtc::isVrrEnabled() const
     return false;
 }
 
+drmModeModeInfo DrmCrtc::queryCurrentMode()
+{
+    m_crtc.reset(drmModeGetCrtc(gpu()->fd(), id()));
+    return m_crtc->mode;
+}
+
 }
diff --git a/src/plugins/platforms/drm/drm_object_crtc.h b/src/plugins/platforms/drm/drm_object_crtc.h
index ed9dd93e22..b77ca8ff78 100644
--- a/src/plugins/platforms/drm/drm_object_crtc.h
+++ b/src/plugins/platforms/drm/drm_object_crtc.h
@@ -64,6 +64,8 @@ public:
     bool setVrr(bool enable);
     bool isVrrEnabled() const;
 
+    drmModeModeInfo queryCurrentMode();
+
 private:
     DrmScopedPointer<drmModeCrtc> m_crtc;
     QSharedPointer<DrmBuffer> m_currentBuffer;
diff --git a/src/plugins/platforms/drm/drm_output.cpp b/src/plugins/platforms/drm/drm_output.cpp
index 53b53924a8..78d1f9dc00 100644
--- a/src/plugins/platforms/drm/drm_output.cpp
+++ b/src/plugins/platforms/drm/drm_output.cpp
@@ -193,52 +193,13 @@ void DrmOutput::moveCursor()
     }
 }
 
-namespace {
-quint64 refreshRateForMode(_drmModeModeInfo *m)
-{
-    // Calculate higher precision (mHz) refresh rate
-    // logic based on Weston, see compositor-drm.c
-    quint64 refreshRate = (m->clock * 1000000LL / m->htotal + m->vtotal / 2) / m->vtotal;
-    if (m->flags & DRM_MODE_FLAG_INTERLACE) {
-        refreshRate *= 2;
-    }
-    if (m->flags & DRM_MODE_FLAG_DBLSCAN) {
-        refreshRate /= 2;
-    }
-    if (m->vscan > 1) {
-        refreshRate /= m->vscan;
-    }
-    return refreshRate;
-}
-}
-
-static AbstractWaylandOutput::SubPixel drmSubPixelToKWinSubPixel(drmModeSubPixel subpixel)
-{
-    switch (subpixel) {
-    case DRM_MODE_SUBPIXEL_UNKNOWN:
-        return AbstractWaylandOutput::SubPixel::Unknown;
-    case DRM_MODE_SUBPIXEL_NONE:
-        return AbstractWaylandOutput::SubPixel::None;
-    case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
-        return AbstractWaylandOutput::SubPixel::Horizontal_RGB;
-    case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
-        return AbstractWaylandOutput::SubPixel::Horizontal_BGR;
-    case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
-        return AbstractWaylandOutput::SubPixel::Vertical_RGB;
-    case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
-        return AbstractWaylandOutput::SubPixel::Vertical_BGR;
-    default:
-        Q_UNREACHABLE();
-    }
-}
-
-bool DrmOutput::init(drmModeConnector *connector)
+bool DrmOutput::init()
 {
     if (m_gpu->atomicModeSetting() && !m_primaryPlane) {
         return false;
     }
 
-    setSubPixelInternal(drmSubPixelToKWinSubPixel(connector->subpixel));
+    setSubPixelInternal(m_conn->subpixel());
     setInternal(m_conn->isInternal());
     setCapabilityInternal(DrmOutput::Capability::Dpms);
     if (m_conn->hasOverscan()) {
@@ -249,7 +210,7 @@ bool DrmOutput::init(drmModeConnector *connector)
         setCapabilityInternal(Capability::Vrr);
         setVrrPolicy(RenderLoop::VrrPolicy::Automatic);
     }
-    initOutputDevice(connector);
+    initOutputDevice();
 
     if (!m_gpu->atomicModeSetting() && !m_crtc->blank(this)) {
         // We use legacy mode and the initial output blank failed.
@@ -260,27 +221,25 @@ bool DrmOutput::init(drmModeConnector *connector)
     return true;
 }
 
-void DrmOutput::initOutputDevice(drmModeConnector *connector)
+void DrmOutput::initOutputDevice()
 {
-    // read in mode information
-    QVector<Mode> modes;
-    modes.reserve(connector->count_modes);
-    for (int i = 0; i < connector->count_modes; ++i) {
-        // TODO: in AMS here we could read and store for later every mode's blob_id
-        // would simplify isCurrentMode(..) and presentAtomically(..) in case of mode set
-        auto *m = &connector->modes[i];
+    m_conn->findCurrentMode(m_crtc->queryCurrentMode());
+    auto modelist = m_conn->modes();
 
+    QVector<Mode> modes;
+    modes.reserve(modelist.count());
+    for (int i = 0; i < modelist.count(); ++i) {
         Mode mode;
-        if (isCurrentMode(m)) {
+        if (i == m_conn->currentModeIndex()) {
             mode.flags |= ModeFlag::Current;
         }
-        if (m->type & DRM_MODE_TYPE_PREFERRED) {
+        if (modelist[i].mode.type & DRM_MODE_TYPE_PREFERRED) {
             mode.flags |= ModeFlag::Preferred;
         }
 
         mode.id = i;
-        mode.size = QSize(m->hdisplay, m->vdisplay);
-        mode.refreshRate = refreshRateForMode(m);
+        mode.size = modelist[i].size;
+        mode.refreshRate = modelist[i].refreshRate;
         modes << mode;
     }
 
@@ -290,25 +249,6 @@ void DrmOutput::initOutputDevice(drmModeConnector *connector)
                m_conn->physicalSize(), modes, m_conn->edid()->raw());
 }
 
-bool DrmOutput::isCurrentMode(const drmModeModeInfo *mode) const
-{
-    return mode->clock       == m_mode.clock
-        && mode->hdisplay    == m_mode.hdisplay
-        && mode->hsync_start == m_mode.hsync_start
-        && mode->hsync_end   == m_mode.hsync_end
-        && mode->htotal      == m_mode.htotal
-        && mode->hskew       == m_mode.hskew
-        && mode->vdisplay    == m_mode.vdisplay
-        && mode->vsync_start == m_mode.vsync_start
-        && mode->vsync_end   == m_mode.vsync_end
-        && mode->vtotal      == m_mode.vtotal
-        && mode->vscan       == m_mode.vscan
-        && mode->vrefresh    == m_mode.vrefresh
-        && mode->flags       == m_mode.flags
-        && mode->type        == m_mode.type
-        && qstrcmp(mode->name, m_mode.name) == 0;
-}
-
 bool DrmOutput::initCursor(const QSize &cursorSize)
 {
     auto createCursor = [this, cursorSize] (int index) {
@@ -548,14 +488,12 @@ void DrmOutput::updateTransform(Transform transform)
 
 void DrmOutput::updateMode(uint32_t width, uint32_t height, uint32_t refreshRate)
 {
-    if (m_mode.hdisplay == width && m_mode.vdisplay == height && refreshRateForMode(&m_mode) == refreshRate) {
+    if (m_conn->currentMode().size == QSize(width, height) && m_conn->currentMode().refreshRate == refreshRate) {
         return;
     }
-    // try to find a fitting mode
-    DrmScopedPointer<drmModeConnector> connector(drmModeGetConnectorCurrent(m_gpu->fd(), m_conn->id()));
-    for (int i = 0; i < connector->count_modes; i++) {
-        auto mode = connector->modes[i];
-        if (mode.hdisplay == width && mode.vdisplay == height && refreshRateForMode(&mode) == refreshRate) {
+    auto modelist = m_conn->modes();
+    for (int i = 0; i < modelist.size(); i++) {
+        if (modelist[i].size == QSize(width, height) && modelist[i].refreshRate == refreshRate) {
             updateMode(i);
             return;
         }
@@ -566,17 +504,10 @@ void DrmOutput::updateMode(uint32_t width, uint32_t height, uint32_t refreshRate
 
 void DrmOutput::updateMode(int modeIndex)
 {
-    // get all modes on the connector
-    DrmScopedPointer<drmModeConnector> connector(drmModeGetConnector(m_gpu->fd(), m_conn->id()));
-    if (connector->count_modes <= modeIndex) {
-        // TODO: error?
+    if (m_conn->currentModeIndex() == modeIndex) {
         return;
     }
-    if (isCurrentMode(&connector->modes[modeIndex])) {
-        // nothing to do
-        return;
-    }
-    m_mode = connector->modes[modeIndex];
+    m_conn->setModeIndex(modeIndex);
     m_modesetRequested = true;
     // aspect ratio might need to be adjusted
     m_conn->setOverscan(m_conn->overscan(), modeSize());
@@ -585,8 +516,8 @@ void DrmOutput::updateMode(int modeIndex)
 
 void DrmOutput::setCurrentModeInternal()
 {
-    AbstractWaylandOutput::setCurrentModeInternal(QSize(m_mode.hdisplay, m_mode.vdisplay),
-                                          refreshRateForMode(&m_mode));
+    auto mode = m_conn->currentMode();
+    AbstractWaylandOutput::setCurrentModeInternal(mode.size, mode.refreshRate);
 }
 
 void DrmOutput::pageFlipped()
@@ -686,7 +617,7 @@ bool DrmOutput::presentAtomically(const QSharedPointer<DrmBuffer> &buffer)
         qCDebug(KWIN_DRM) << "Atomic test commit failed. Aborting present.";
         // go back to previous state
         if (m_lastWorkingState.valid) {
-            m_mode = m_lastWorkingState.mode;
+            m_conn->setModeIndex(m_lastWorkingState.modeIndex);
             setTransformInternal(m_lastWorkingState.transform);
             setGlobalPos(m_lastWorkingState.globalPos);
             if (m_primaryPlane) {
@@ -713,14 +644,14 @@ bool DrmOutput::presentAtomically(const QSharedPointer<DrmBuffer> &buffer)
     }
     if (wasModeset) {
         // store current mode set as new good state
-        m_lastWorkingState.mode = m_mode;
+        m_lastWorkingState.modeIndex = m_conn->currentModeIndex();
         m_lastWorkingState.transform = transform();
         m_lastWorkingState.globalPos = globalPos();
         if (m_primaryPlane) {
             m_lastWorkingState.planeTransformations = m_primaryPlane->transformation();
         }
         m_lastWorkingState.valid = true;
-        m_renderLoop->setRefreshRate(refreshRateForMode(&m_mode));
+        m_renderLoop->setRefreshRate(m_conn->currentMode().refreshRate);
     }
     m_pageFlipPending = true;
     return true;
@@ -755,7 +686,8 @@ bool DrmOutput::presentLegacy(const QSharedPointer<DrmBuffer> &buffer)
 bool DrmOutput::setModeLegacy(DrmBuffer *buffer)
 {
     uint32_t connId = m_conn->id();
-    if (drmModeSetCrtc(m_gpu->fd(), m_crtc->id(), buffer->bufferId(), 0, 0, &connId, 1, &m_mode) == 0) {
+    auto mode = m_conn->currentMode().mode;
+    if (drmModeSetCrtc(m_gpu->fd(), m_crtc->id(), buffer->bufferId(), 0, 0, &connId, 1, &mode) == 0) {
         return true;
     } else {
         qCWarning(KWIN_DRM) << "Mode setting failed";
@@ -801,7 +733,8 @@ bool DrmOutput::doAtomicCommit(AtomicCommitMode mode)
     // Do we need to set a new mode?
     if (m_modesetRequested) {
         if (m_dpmsModePending == DpmsMode::On) {
-            if (drmModeCreatePropertyBlob(m_gpu->fd(), &m_mode, sizeof(m_mode), &m_blobId) != 0) {
+            auto mode = m_conn->currentMode();
+            if (drmModeCreatePropertyBlob(m_gpu->fd(), &mode, sizeof(mode), &m_blobId) != 0) {
                 qCWarning(KWIN_DRM) << "Failed to create property blob";
                 errorHandler();
                 return false;
@@ -943,7 +876,7 @@ void DrmOutput::setVrr(bool enable)
 
 bool DrmOutput::isCursorVisible()
 {
-    return m_cursor[m_cursorIndex] && QRect(m_cursorPos, m_cursor[m_cursorIndex]->size()).intersects(QRect(0, 0, m_mode.vdisplay, m_mode.hdisplay));
+    return m_cursor[m_cursorIndex] && QRect(m_cursorPos, m_cursor[m_cursorIndex]->size()).intersects(QRect(0, 0, modeSize().width(), modeSize().height()));
 }
 
 DrmBuffer *DrmOutput::currentBuffer() const
diff --git a/src/plugins/platforms/drm/drm_output.h b/src/plugins/platforms/drm/drm_output.h
index 2fd6eed3ca..24380519c1 100644
--- a/src/plugins/platforms/drm/drm_output.h
+++ b/src/plugins/platforms/drm/drm_output.h
@@ -49,7 +49,7 @@ public:
     bool hideCursor();
     bool updateCursor();
     void moveCursor();
-    bool init(drmModeConnector *connector);
+    bool init();
     bool present(const QSharedPointer<DrmBuffer> &buffer, QRegion damagedRegion);
     void pageFlipped();
 
@@ -104,7 +104,7 @@ private:
 
     bool presentLegacy(const QSharedPointer<DrmBuffer> &buffer);
     bool setModeLegacy(DrmBuffer *buffer);
-    void initOutputDevice(drmModeConnector *connector);
+    void initOutputDevice();
 
     bool isCurrentMode(const drmModeModeInfo *mode) const;
 
@@ -139,7 +139,6 @@ private:
     DrmConnector *m_conn = nullptr;
     DrmCrtc *m_crtc = nullptr;
     bool m_lastGbm = false;
-    drmModeModeInfo m_mode;
     DpmsMode m_dpmsModePending = DpmsMode::On;
     RenderLoop *m_renderLoop;
 
@@ -154,7 +153,7 @@ private:
 
     struct {
         Transform transform;
-        drmModeModeInfo mode;
+        int modeIndex = 0;
         DrmPlane::Transformations planeTransformations;
         QPoint globalPos;
         bool valid = false;