From ee4b4fc9a32b8fe562f5b9932362a7619ec958cd Mon Sep 17 00:00:00 2001 From: Xaver Hugl Date: Tue, 25 May 2021 19:55:15 +0200 Subject: [PATCH] platforms/drm: refactor presentation in gbm backend --- src/plugins/platforms/drm/drm_output.cpp | 18 +++++- src/plugins/platforms/drm/drm_output.h | 3 +- src/plugins/platforms/drm/egl_gbm_backend.cpp | 60 ++++++------------- src/plugins/platforms/drm/egl_gbm_backend.h | 6 +- .../platforms/drm/egl_stream_backend.cpp | 3 +- .../drm/scene_qpainter_drm_backend.cpp | 2 +- 6 files changed, 38 insertions(+), 54 deletions(-) diff --git a/src/plugins/platforms/drm/drm_output.cpp b/src/plugins/platforms/drm/drm_output.cpp index 77a3b61e1f..53b53924a8 100644 --- a/src/plugins/platforms/drm/drm_output.cpp +++ b/src/plugins/platforms/drm/drm_output.cpp @@ -617,7 +617,7 @@ void DrmOutput::pageFlipped() } } -bool DrmOutput::present(const QSharedPointer &buffer) +bool DrmOutput::present(const QSharedPointer &buffer, QRegion damagedRegion) { if (!buffer || buffer->bufferId() == 0) { return false; @@ -627,7 +627,12 @@ bool DrmOutput::present(const QSharedPointer &buffer) } RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(m_renderLoop); setVrr(renderLoopPrivate->presentMode == RenderLoopPrivate::SyncMode::Adaptive); - return m_gpu->atomicModeSetting() ? presentAtomically(buffer) : presentLegacy(buffer); + if (m_gpu->atomicModeSetting() ? presentAtomically(buffer) : presentLegacy(buffer)) { + Q_EMIT outputChange(damagedRegion); + return true; + } else { + return false; + } } bool DrmOutput::dpmsAtomicOff() @@ -941,4 +946,13 @@ 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)); } +DrmBuffer *DrmOutput::currentBuffer() const +{ + if (m_primaryPlane) { + return m_primaryPlane->current().get(); + } else { + return m_crtc->current().get(); + } +} + } diff --git a/src/plugins/platforms/drm/drm_output.h b/src/plugins/platforms/drm/drm_output.h index 7189085890..2fd6eed3ca 100644 --- a/src/plugins/platforms/drm/drm_output.h +++ b/src/plugins/platforms/drm/drm_output.h @@ -50,7 +50,7 @@ public: bool updateCursor(); void moveCursor(); bool init(drmModeConnector *connector); - bool present(const QSharedPointer &buffer); + bool present(const QSharedPointer &buffer, QRegion damagedRegion); void pageFlipped(); bool isDpmsEnabled() const { @@ -71,6 +71,7 @@ public: const DrmPlane *primaryPlane() const { return m_primaryPlane; } + DrmBuffer *currentBuffer() const; bool initCursor(const QSize &cursorSize); diff --git a/src/plugins/platforms/drm/egl_gbm_backend.cpp b/src/plugins/platforms/drm/egl_gbm_backend.cpp index 45e880efea..3a601c5a55 100644 --- a/src/plugins/platforms/drm/egl_gbm_backend.cpp +++ b/src/plugins/platforms/drm/egl_gbm_backend.cpp @@ -289,13 +289,12 @@ QRegion EglGbmBackend::beginFrameForSecondaryGpu(DrmOutput *drmOutput) return prepareRenderingForOutput(*it); } -void EglGbmBackend::importFramebuffer(Output &output) const +QSharedPointer EglGbmBackend::importFramebuffer(Output &output) const { if (!renderingBackend()->swapBuffers(output.output)) { qCWarning(KWIN_DRM) << "swapping buffers failed on output" << output.output; - return; + return nullptr; } - output.buffer = nullptr; const auto size = output.output->modeSize(); if (output.importMode == ImportMode::Dmabuf) { uint32_t stride = 0; @@ -313,8 +312,7 @@ void EglGbmBackend::importFramebuffer(Output &output) const if (importedBuffer) { auto buffer = QSharedPointer::create(m_gpu, importedBuffer, nullptr); if (buffer->bufferId() > 0) { - output.buffer = buffer; - return; + return buffer; } } } @@ -331,12 +329,12 @@ void EglGbmBackend::importFramebuffer(Output &output) const if (output.importSwapchain) { auto buffer = output.importSwapchain->acquireBuffer(); if (renderingBackend()->exportFramebuffer(output.output, buffer->data(), size, buffer->stride())) { - output.buffer = buffer; - return; + return buffer; } } qCWarning(KWIN_DRM) << "all imports failed on output" << output.output; // TODO turn off output? + return nullptr; } void EglGbmBackend::renderFramebufferToSurface(Output &output) @@ -457,31 +455,6 @@ void EglGbmBackend::aboutToStartPainting(int screenId, const QRegion &damagedReg } } -bool EglGbmBackend::presentOnOutput(Output &output, const QRegion &damagedRegion) -{ - if (isPrimary() && !directScanoutActive(output)) { - output.buffer = output.gbmSurface->swapBuffersForDrm(); - } else if (!output.buffer) { - qCDebug(KWIN_DRM) << "imported buffer does not exist!"; - return false; - } - - Q_EMIT output.output->outputChange(damagedRegion); - if (!output.output->present(output.buffer)) { - return false; - } - - if (supportsBufferAge()) { - eglQuerySurface(eglDisplay(), output.gbmSurface->eglSurface(), EGL_BUFFER_AGE_EXT, &output.bufferAge); - } - return true; -} - -bool EglGbmBackend::directScanoutActive(const Output &output) -{ - return output.surfaceInterface != nullptr; -} - PlatformSurfaceTexture *EglGbmBackend::createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) { return new BasicEGLSurfaceTextureInternal(this, pixmap); @@ -544,14 +517,16 @@ void EglGbmBackend::endFrame(int screenId, const QRegion &renderedRegion, Output &output = m_outputs[screenId]; DrmOutput *drmOutput = output.output; + QSharedPointer buffer; if (isPrimary()) { renderFramebufferToSurface(output); + buffer = output.gbmSurface->swapBuffersForDrm(); } else { - importFramebuffer(output); + buffer = importFramebuffer(output); } const QRegion dirty = damagedRegion.intersected(output.output->geometry()); - if (!presentOnOutput(output, dirty)) { + if (!buffer || !output.output->present(buffer, dirty)) { output.damageHistory.clear(); RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(drmOutput->renderLoop()); renderLoopPrivate->notifyFrameFailed(); @@ -559,6 +534,7 @@ void EglGbmBackend::endFrame(int screenId, const QRegion &renderedRegion, } if (supportsBufferAge()) { + eglQuerySurface(eglDisplay(), output.gbmSurface->eglSurface(), EGL_BUFFER_AGE_EXT, &output.bufferAge); if (output.damageHistory.count() > 10) { output.damageHistory.removeLast(); } @@ -636,19 +612,18 @@ bool EglGbmBackend::scanout(int screenId, SurfaceItem *surfaceItem) } else { damage = output.output->geometry(); } - output.buffer = QSharedPointer::create(m_gpu, importedBuffer, buffer); - auto oldSurface = output.surfaceInterface; - output.surfaceInterface = surface; + auto bo = QSharedPointer::create(m_gpu, importedBuffer, buffer); // ensure that a context is current like with normal presentation makeCurrent(); - if (presentOnOutput(output, damage)) { - if (oldSurface != surface) { + if (output.output->present(bo, damage)) { + output.damageHistory.clear(); + if (output.surfaceInterface != surface) { auto path = surface->client()->executablePath(); qCDebug(KWIN_DRM).nospace() << "Direct scanout starting on output " << output.output->name() << " for application \"" << path << "\""; } + output.surfaceInterface = surface; return true; } else { - output.surfaceInterface = nullptr; return false; } } @@ -677,10 +652,9 @@ QSharedPointer EglGbmBackend::textureForOutput(AbstractOutput *abstra glTexture->setYInverted(true); return glTexture; } - - auto gbmBuffer = dynamic_cast(itOutput->buffer.data()); + GbmBuffer *gbmBuffer = itOutput->gbmSurface->currentBuffer().get(); if (!gbmBuffer) { - qCWarning(KWIN_DRM) << "Failed to record frame: Dumb buffer used for presentation!"; + qCWarning(KWIN_DRM) << "Failed to record frame: No gbm buffer!"; return {}; } EGLImageKHR image = eglCreateImageKHR(eglDisplay(), nullptr, EGL_NATIVE_PIXMAP_KHR, gbmBuffer->getBo(), nullptr); diff --git a/src/plugins/platforms/drm/egl_gbm_backend.h b/src/plugins/platforms/drm/egl_gbm_backend.h index bff57674c2..a090370542 100644 --- a/src/plugins/platforms/drm/egl_gbm_backend.h +++ b/src/plugins/platforms/drm/egl_gbm_backend.h @@ -82,7 +82,6 @@ private: }; struct Output { DrmOutput *output = nullptr; - QSharedPointer buffer; QSharedPointer gbmSurface; int bufferAge = 0; /** @@ -105,10 +104,7 @@ private: void prepareRenderFramebuffer(const Output &output) const; void renderFramebufferToSurface(Output &output); QRegion prepareRenderingForOutput(Output &output) const; - void importFramebuffer(Output &output) const; - - bool presentOnOutput(Output &output, const QRegion &damagedRegion); - bool directScanoutActive(const Output &output); + QSharedPointer importFramebuffer(Output &output) const; QVector m_outputs; QVector m_secondaryGpuOutputs; diff --git a/src/plugins/platforms/drm/egl_stream_backend.cpp b/src/plugins/platforms/drm/egl_stream_backend.cpp index a900a8039a..d5ef8d4b11 100644 --- a/src/plugins/platforms/drm/egl_stream_backend.cpp +++ b/src/plugins/platforms/drm/egl_stream_backend.cpp @@ -506,7 +506,6 @@ QRegion EglStreamBackend::beginFrame(int screenId) void EglStreamBackend::endFrame(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion) { Q_UNUSED(renderedRegion); - Q_UNUSED(damagedRegion); Output &renderOutput = m_outputs[screenId]; DrmOutput *drmOutput = renderOutput.output; @@ -534,7 +533,7 @@ void EglStreamBackend::endFrame(int screenId, const QRegion &renderedRegion, con frameFailed = true; } } - if (!frameFailed && !renderOutput.output->present(buffer)) { + if (!frameFailed && !renderOutput.output->present(buffer, damagedRegion)) { frameFailed = true; } diff --git a/src/plugins/platforms/drm/scene_qpainter_drm_backend.cpp b/src/plugins/platforms/drm/scene_qpainter_drm_backend.cpp index ee8a9eab70..0e55de2802 100644 --- a/src/plugins/platforms/drm/scene_qpainter_drm_backend.cpp +++ b/src/plugins/platforms/drm/scene_qpainter_drm_backend.cpp @@ -86,7 +86,7 @@ void DrmQPainterBackend::endFrame(int screenId, int mask, const QRegion &damage) const Output &rendererOutput = m_outputs[screenId]; DrmOutput *drmOutput = rendererOutput.output; - if (!drmOutput->present(rendererOutput.swapchain->currentBuffer())) { + if (!drmOutput->present(rendererOutput.swapchain->currentBuffer(), drmOutput->geometry())) { RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(drmOutput->renderLoop()); renderLoopPrivate->notifyFrameFailed(); }