From 65b55e2045c7a7fa7cfdd30eaddc49c281366919 Mon Sep 17 00:00:00 2001 From: Xaver Hugl Date: Thu, 24 Jun 2021 15:53:06 +0200 Subject: [PATCH] platforms/drm: change when to reset the output with eglstreams In order to accomodate crtc or primary plane changes on outputs we need to dynamically recreate rendering resources with EglStreams as the stream is tied to the crtc or plane currently in use. --- .../platforms/drm/egl_stream_backend.cpp | 41 ++++++++++++------- .../platforms/drm/egl_stream_backend.h | 6 +++ 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src/plugins/platforms/drm/egl_stream_backend.cpp b/src/plugins/platforms/drm/egl_stream_backend.cpp index 0b7038990d..578b902a2e 100644 --- a/src/plugins/platforms/drm/egl_stream_backend.cpp +++ b/src/plugins/platforms/drm/egl_stream_backend.cpp @@ -306,6 +306,7 @@ bool EglStreamBackend::resetOutput(Output &o) if (isPrimary()) { // dumb buffer used for modesetting o.buffer = QSharedPointer::create(m_gpu, sourceSize); + o.targetPlane = drmOutput->pipeline()->primaryPlane(); EGLAttrib streamAttribs[] = { EGL_STREAM_FIFO_LENGTH_KHR, 0, // mailbox mode @@ -319,13 +320,8 @@ bool EglStreamBackend::resetOutput(Output &o) } EGLAttrib outputAttribs[3]; - if (drmOutput->pipeline()->primaryPlane()) { - outputAttribs[0] = EGL_DRM_PLANE_EXT; - outputAttribs[1] = drmOutput->pipeline()->primaryPlane()->id(); - } else { - outputAttribs[0] = EGL_DRM_CRTC_EXT; - outputAttribs[1] = drmOutput->pipeline()->crtc()->id(); - } + outputAttribs[0] = EGL_DRM_PLANE_EXT; + outputAttribs[1] = o.targetPlane->id(); outputAttribs[2] = EGL_NONE; EGLint numLayers; EGLOutputLayerEXT outputLayer; @@ -392,12 +388,6 @@ bool EglStreamBackend::addOutput(DrmAbstractOutput *output) if (!isPrimary() && !renderingBackend()->addOutput(drmOutput)) { return false; } - - connect(drmOutput, &DrmOutput::currentModeChanged, this, - [drmOutput, this] { - resetOutput(m_outputs[drmOutput]); - } - ); m_outputs.insert(output, o); return true; } else { @@ -483,11 +473,34 @@ PlatformSurfaceTexture *EglStreamBackend::createPlatformSurfaceTextureWayland(Su return new EglStreamSurfaceTextureWayland(this, pixmap); } +bool EglStreamBackend::needsReset(const Output &o) const +{ + if (o.targetPlane != o.output->pipeline()->primaryPlane()) { + return true; + } + QSize surfaceSize = o.dumbSwapchain ? o.dumbSwapchain->size() : o.buffer->size(); + if (surfaceSize != o.output->sourceSize()) { + return true; + } + bool needsTexture = surfaceSize != o.output->pixelSize(); + if (needsTexture) { + return !o.shadowBuffer || o.shadowBuffer->textureSize() != o.output->pixelSize(); + } else { + return o.shadowBuffer != nullptr; + } +} + QRegion EglStreamBackend::beginFrame(AbstractOutput *drmOutput) { Q_ASSERT(m_outputs.contains(drmOutput)); - const Output &o = m_outputs[drmOutput]; + Output &o = m_outputs[drmOutput]; if (isPrimary()) { + if (needsReset(o)) { + if (!resetOutput(o)) { + // handle this better? + return {}; + } + } makeContextCurrent(o); if (o.shadowBuffer) { o.shadowBuffer->bind(); diff --git a/src/plugins/platforms/drm/egl_stream_backend.h b/src/plugins/platforms/drm/egl_stream_backend.h index 91c40adad9..c1f0c4447e 100644 --- a/src/plugins/platforms/drm/egl_stream_backend.h +++ b/src/plugins/platforms/drm/egl_stream_backend.h @@ -21,6 +21,8 @@ class DrmAbstractOutput; class DrmDumbBuffer; class DumbSwapchain; class ShadowBuffer; +class DrmCrtc; +class DrmPlane; /** * @brief OpenGL Backend using Egl with an EGLDevice. @@ -68,12 +70,16 @@ private: EGLStreamKHR eglStream = EGL_NO_STREAM_KHR; QSharedPointer shadowBuffer; + DrmPlane *targetPlane = nullptr; + // for operation as secondary GPU QSharedPointer dumbSwapchain; }; bool resetOutput(Output &output); + bool createEglSurface(Output &o); bool makeContextCurrent(const Output &output); void cleanupOutput(Output &output); + bool needsReset(const Output &o) const; QMap m_outputs; KWaylandServer::EglStreamControllerInterface *m_eglStreamControllerInterface;