diff --git a/autotests/drm/drmTest.cpp b/autotests/drm/drmTest.cpp index a8cdfe8847..c25adc8b9c 100644 --- a/autotests/drm/drmTest.cpp +++ b/autotests/drm/drmTest.cpp @@ -384,8 +384,9 @@ void DrmTest::testModeset() layer->beginFrame(); output->renderLoop()->prepareNewFrame(); output->renderLoop()->beginPaint(); - layer->endFrame(infiniteRegion(), infiniteRegion()); - QVERIFY(output->present(std::make_shared(output->renderLoop()))); + const auto frame = std::make_shared(output->renderLoop()); + layer->endFrame(infiniteRegion(), infiniteRegion(), frame.get()); + QVERIFY(output->present(frame)); gpu.reset(); verifyCleanup(mockGpu.get()); diff --git a/src/backends/drm/drm_abstract_output.cpp b/src/backends/drm/drm_abstract_output.cpp index 9f11a1ab1c..88255a4367 100644 --- a/src/backends/drm/drm_abstract_output.cpp +++ b/src/backends/drm/drm_abstract_output.cpp @@ -34,8 +34,7 @@ void DrmAbstractOutput::frameFailed() const void DrmAbstractOutput::pageFlipped(std::chrono::nanoseconds timestamp, PresentationMode mode) { - const auto gpuTime = primaryLayer() ? primaryLayer()->queryRenderTime() : std::chrono::nanoseconds::zero(); - m_frame->presented(std::chrono::nanoseconds(1'000'000'000'000 / refreshRate()), timestamp, gpuTime, mode); + m_frame->presented(std::chrono::nanoseconds(1'000'000'000'000 / refreshRate()), timestamp, mode); m_frame.reset(); } diff --git a/src/backends/drm/drm_egl_layer.cpp b/src/backends/drm/drm_egl_layer.cpp index 6326098ebe..689e5c897f 100644 --- a/src/backends/drm/drm_egl_layer.cpp +++ b/src/backends/drm/drm_egl_layer.cpp @@ -57,9 +57,9 @@ std::optional EglGbmLayer::doBeginFrame() return m_surface.startRendering(targetRect().size(), m_pipeline->output()->transform().combine(OutputTransform::FlipY), m_pipeline->formats(m_type), m_pipeline->colorDescription(), m_pipeline->output()->channelFactors(), m_pipeline->iccProfile(), m_pipeline->output()->needsColormanagement()); } -bool EglGbmLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool EglGbmLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) { - return m_surface.endRendering(damagedRegion); + return m_surface.endRendering(damagedRegion, frame); } bool EglGbmLayer::checkTestBuffer() @@ -129,11 +129,6 @@ void EglGbmLayer::releaseBuffers() m_surface.destroyResources(); } -std::chrono::nanoseconds EglGbmLayer::queryRenderTime() const -{ - return m_surface.queryRenderTime(); -} - DrmDevice *EglGbmLayer::scanoutDevice() const { return m_pipeline->gpu()->drmDevice(); diff --git a/src/backends/drm/drm_egl_layer.h b/src/backends/drm/drm_egl_layer.h index 229d747f8b..fb33e7a095 100644 --- a/src/backends/drm/drm_egl_layer.h +++ b/src/backends/drm/drm_egl_layer.h @@ -28,13 +28,12 @@ public: explicit EglGbmLayer(EglGbmBackend *eglBackend, DrmPipeline *pipeline, DrmPlane::TypeIndex type); std::optional doBeginFrame() override; - bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) override; bool checkTestBuffer() override; std::shared_ptr currentBuffer() const override; std::shared_ptr texture() const override; ColorDescription colorDescription() const; void releaseBuffers() override; - std::chrono::nanoseconds queryRenderTime() const override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; std::optional fixedSize() const override; diff --git a/src/backends/drm/drm_egl_layer_surface.cpp b/src/backends/drm/drm_egl_layer_surface.cpp index 6f231325a7..88a4eb7b4e 100644 --- a/src/backends/drm/drm_egl_layer_surface.cpp +++ b/src/backends/drm/drm_egl_layer_surface.cpp @@ -120,6 +120,8 @@ std::optional EglGbmLayerSurface::startRendering(cons } const QRegion repaint = bufferAgeEnabled ? m_surface->damageJournal.accumulate(slot->age(), infiniteRegion()) : infiniteRegion(); + m_surface->compositingTimeQuery = std::make_unique(m_surface->context); + m_surface->compositingTimeQuery->begin(); if (enableColormanagement) { if (!m_surface->shadowSwapchain || m_surface->shadowSwapchain->size() != m_surface->gbmSwapchain->size()) { const auto formats = m_eglBackend->eglDisplayObject()->nonExternalOnlySupportedDrmFormats(); @@ -160,8 +162,6 @@ std::optional EglGbmLayerSurface::startRendering(cons return std::nullopt; } m_surface->currentShadowSlot->texture()->setContentTransform(m_surface->currentSlot->framebuffer()->colorAttachment()->contentTransform()); - m_surface->renderStart = std::chrono::steady_clock::now(); - m_surface->timeQuery->begin(); return OutputLayerBeginFrameInfo{ .renderTarget = RenderTarget(m_surface->currentShadowSlot->framebuffer(), m_surface->intermediaryColorDescription), .repaint = infiniteRegion(), @@ -169,8 +169,6 @@ std::optional EglGbmLayerSurface::startRendering(cons } else { m_surface->shadowSwapchain.reset(); m_surface->currentShadowSlot.reset(); - m_surface->renderStart = std::chrono::steady_clock::now(); - m_surface->timeQuery->begin(); return OutputLayerBeginFrameInfo{ .renderTarget = RenderTarget(m_surface->currentSlot->framebuffer()), .repaint = repaint, @@ -178,7 +176,7 @@ std::optional EglGbmLayerSurface::startRendering(cons } } -bool EglGbmLayerSurface::endRendering(const QRegion &damagedRegion) +bool EglGbmLayerSurface::endRendering(const QRegion &damagedRegion, OutputFrame *frame) { if (m_surface->colormanagementEnabled) { GLFramebuffer *fbo = m_surface->currentSlot->framebuffer(); @@ -210,7 +208,10 @@ bool EglGbmLayerSurface::endRendering(const QRegion &damagedRegion) GLFramebuffer::popFramebuffer(); } m_surface->damageJournal.add(damagedRegion); - m_surface->timeQuery->end(); + m_surface->compositingTimeQuery->end(); + if (frame) { + frame->addRenderTimeQuery(std::move(m_surface->compositingTimeQuery)); + } glFlush(); EGLNativeFence sourceFence(m_eglBackend->eglDisplayObject()); if (!sourceFence.isValid()) { @@ -219,8 +220,7 @@ bool EglGbmLayerSurface::endRendering(const QRegion &damagedRegion) glFinish(); } m_surface->gbmSwapchain->release(m_surface->currentSlot, sourceFence.fileDescriptor().duplicate()); - const auto buffer = importBuffer(m_surface.get(), m_surface->currentSlot.get(), sourceFence.takeFileDescriptor()); - m_surface->renderEnd = std::chrono::steady_clock::now(); + const auto buffer = importBuffer(m_surface.get(), m_surface->currentSlot.get(), sourceFence.takeFileDescriptor(), frame); if (buffer) { m_surface->currentFramebuffer = buffer; return true; @@ -229,24 +229,6 @@ bool EglGbmLayerSurface::endRendering(const QRegion &damagedRegion) } } -std::chrono::nanoseconds EglGbmLayerSurface::queryRenderTime() const -{ - if (!m_surface) { - return std::chrono::nanoseconds::zero(); - } - const auto cpuTime = m_surface->renderEnd - m_surface->renderStart; - if (m_surface->timeQuery) { - m_eglBackend->makeCurrent(); - auto gpuTime = m_surface->timeQuery->result(); - if (m_surface->importTimeQuery && m_eglBackend->contextForGpu(m_gpu)->makeCurrent()) { - gpuTime += m_surface->importTimeQuery->result(); - } - return std::max(gpuTime, cpuTime); - } else { - return cpuTime; - } -} - EglGbmBackend *EglGbmLayerSurface::eglBackend() const { return m_eglBackend; @@ -486,9 +468,7 @@ std::unique_ptr EglGbmLayerSurface::createSurface(c if (!ret->importGbmSwapchain) { return nullptr; } - ret->importTimeQuery = std::make_unique(); } - ret->timeQuery = std::make_unique(); if (!doRenderTestBuffer(ret.get())) { return nullptr; } @@ -532,7 +512,7 @@ std::shared_ptr EglGbmLayerSurface::doRenderTestBuffer(Surface * if (!slot) { return nullptr; } - if (const auto ret = importBuffer(surface, slot.get(), FileDescriptor{})) { + if (const auto ret = importBuffer(surface, slot.get(), FileDescriptor{}, nullptr)) { surface->currentSlot = slot; surface->currentFramebuffer = ret; return ret; @@ -541,12 +521,12 @@ std::shared_ptr EglGbmLayerSurface::doRenderTestBuffer(Surface * } } -std::shared_ptr EglGbmLayerSurface::importBuffer(Surface *surface, EglSwapchainSlot *slot, FileDescriptor &&readFence) const +std::shared_ptr EglGbmLayerSurface::importBuffer(Surface *surface, EglSwapchainSlot *slot, FileDescriptor &&readFence, OutputFrame *frame) const { if (surface->bufferTarget == BufferTarget::Dumb || surface->importMode == MultiGpuImportMode::DumbBuffer) { - return importWithCpu(surface, slot); + return importWithCpu(surface, slot, frame); } else if (surface->importMode == MultiGpuImportMode::Egl) { - return importWithEgl(surface, slot->buffer(), std::move(readFence)); + return importWithEgl(surface, slot->buffer(), std::move(readFence), frame); } else { const auto ret = m_gpu->importBuffer(slot->buffer(), std::move(readFence)); if (!ret) { @@ -556,7 +536,7 @@ std::shared_ptr EglGbmLayerSurface::importBuffer(Surface *surfac } } -std::shared_ptr EglGbmLayerSurface::importWithEgl(Surface *surface, GraphicsBuffer *sourceBuffer, FileDescriptor &&readFence) const +std::shared_ptr EglGbmLayerSurface::importWithEgl(Surface *surface, GraphicsBuffer *sourceBuffer, FileDescriptor &&readFence, OutputFrame *frame) const { Q_ASSERT(surface->importGbmSwapchain); @@ -569,7 +549,11 @@ std::shared_ptr EglGbmLayerSurface::importWithEgl(Surface *surfa if (!surface->importContext->makeCurrent()) { return nullptr; } - surface->importTimeQuery->begin(); + std::unique_ptr renderTime; + if (frame) { + renderTime = std::make_unique(surface->importContext); + renderTime->begin(); + } if (readFence.isValid()) { const auto destinationFence = EGLNativeFence::importFence(surface->importContext->displayObject(), std::move(readFence)); @@ -613,15 +597,22 @@ std::shared_ptr EglGbmLayerSurface::importWithEgl(Surface *surfa glFinish(); } surface->importGbmSwapchain->release(slot, endFence.fileDescriptor().duplicate()); - surface->importTimeQuery->end(); + if (frame) { + renderTime->end(); + frame->addRenderTimeQuery(std::move(renderTime)); + } // restore the old context m_eglBackend->makeCurrent(); return m_gpu->importBuffer(slot->buffer(), endFence.takeFileDescriptor()); } -std::shared_ptr EglGbmLayerSurface::importWithCpu(Surface *surface, EglSwapchainSlot *source) const +std::shared_ptr EglGbmLayerSurface::importWithCpu(Surface *surface, EglSwapchainSlot *source, OutputFrame *frame) const { + std::unique_ptr copyTime; + if (frame) { + copyTime = std::make_unique(); + } Q_ASSERT(surface->importDumbSwapchain); const auto slot = surface->importDumbSwapchain->acquire(); if (!slot) { @@ -651,6 +642,10 @@ std::shared_ptr EglGbmLayerSurface::importWithCpu(Surface *surfa qCWarning(KWIN_DRM, "Failed to create a framebuffer: %s", strerror(errno)); } surface->importDumbSwapchain->release(slot); + if (frame) { + copyTime->end(); + frame->addRenderTimeQuery(std::move(copyTime)); + } return ret; } } diff --git a/src/backends/drm/drm_egl_layer_surface.h b/src/backends/drm/drm_egl_layer_surface.h index fbb5a7f493..8683d4b627 100644 --- a/src/backends/drm/drm_egl_layer_surface.h +++ b/src/backends/drm/drm_egl_layer_surface.h @@ -57,8 +57,7 @@ public: ~EglGbmLayerSurface(); std::optional startRendering(const QSize &bufferSize, OutputTransform transformation, const QHash> &formats, const ColorDescription &colorDescription, const QVector3D &channelFactors, const std::shared_ptr &iccProfile, bool enableColormanagement); - bool endRendering(const QRegion &damagedRegion); - std::chrono::nanoseconds queryRenderTime() const; + bool endRendering(const QRegion &damagedRegion, OutputFrame *frame); bool doesSurfaceFit(const QSize &size, const QHash> &formats) const; std::shared_ptr texture() const; @@ -105,11 +104,7 @@ private: std::unique_ptr iccShader; std::shared_ptr iccProfile; - // for render timing - std::unique_ptr timeQuery; - std::unique_ptr importTimeQuery; - std::chrono::steady_clock::time_point renderStart; - std::chrono::steady_clock::time_point renderEnd; + std::unique_ptr compositingTimeQuery; }; bool checkSurface(const QSize &size, const QHash> &formats); bool doesSurfaceFit(Surface *surface, const QSize &size, const QHash> &formats) const; @@ -118,9 +113,9 @@ private: std::shared_ptr createGbmSwapchain(DrmGpu *gpu, EglContext *context, const QSize &size, uint32_t format, const QList &modifiers, MultiGpuImportMode importMode, BufferTarget bufferTarget) const; std::shared_ptr doRenderTestBuffer(Surface *surface) const; - std::shared_ptr importBuffer(Surface *surface, EglSwapchainSlot *source, FileDescriptor &&readFence) const; - std::shared_ptr importWithEgl(Surface *surface, GraphicsBuffer *sourceBuffer, FileDescriptor &&readFence) const; - std::shared_ptr importWithCpu(Surface *surface, EglSwapchainSlot *source) const; + std::shared_ptr importBuffer(Surface *surface, EglSwapchainSlot *source, FileDescriptor &&readFence, OutputFrame *frame) const; + std::shared_ptr importWithEgl(Surface *surface, GraphicsBuffer *sourceBuffer, FileDescriptor &&readFence, OutputFrame *frame) const; + std::shared_ptr importWithCpu(Surface *surface, EglSwapchainSlot *source, OutputFrame *frame) const; std::unique_ptr m_surface; std::unique_ptr m_oldSurface; diff --git a/src/backends/drm/drm_qpainter_layer.cpp b/src/backends/drm/drm_qpainter_layer.cpp index ccbdb610d6..91b36f9480 100644 --- a/src/backends/drm/drm_qpainter_layer.cpp +++ b/src/backends/drm/drm_qpainter_layer.cpp @@ -38,7 +38,7 @@ std::optional DrmQPainterLayer::doBeginFrame() return std::nullopt; } - m_renderStart = std::chrono::steady_clock::now(); + m_renderTime = std::make_unique(); const QRegion repaint = m_damageJournal.accumulate(m_currentBuffer->age(), infiniteRegion()); return OutputLayerBeginFrameInfo{ .renderTarget = RenderTarget(m_currentBuffer->view()->image()), @@ -46,9 +46,12 @@ std::optional DrmQPainterLayer::doBeginFrame() }; } -bool DrmQPainterLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool DrmQPainterLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) { - m_renderTime = std::chrono::steady_clock::now() - m_renderStart; + m_renderTime->end(); + if (frame) { + frame->addRenderTimeQuery(std::move(m_renderTime)); + } m_currentFramebuffer = m_pipeline->gpu()->importBuffer(m_currentBuffer->buffer(), FileDescriptor{}); m_damageJournal.add(damagedRegion); m_swapchain->release(m_currentBuffer); @@ -91,11 +94,6 @@ void DrmQPainterLayer::releaseBuffers() m_swapchain.reset(); } -std::chrono::nanoseconds DrmQPainterLayer::queryRenderTime() const -{ - return m_renderTime; -} - DrmDevice *DrmQPainterLayer::scanoutDevice() const { return m_pipeline->gpu()->drmDevice(); @@ -116,16 +114,17 @@ std::optional DrmVirtualQPainterLayer::doBeginFrame() if (m_image.isNull() || m_image.size() != m_output->modeSize()) { m_image = QImage(m_output->modeSize(), QImage::Format_RGB32); } - m_renderStart = std::chrono::steady_clock::now(); + m_renderTime = std::make_unique(); return OutputLayerBeginFrameInfo{ .renderTarget = RenderTarget(&m_image), .repaint = QRegion(), }; } -bool DrmVirtualQPainterLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool DrmVirtualQPainterLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) { - m_renderTime = std::chrono::steady_clock::now() - m_renderStart; + m_renderTime->end(); + frame->addRenderTimeQuery(std::move(m_renderTime)); return true; } @@ -133,11 +132,6 @@ void DrmVirtualQPainterLayer::releaseBuffers() { } -std::chrono::nanoseconds DrmVirtualQPainterLayer::queryRenderTime() const -{ - return m_renderTime; -} - DrmDevice *DrmVirtualQPainterLayer::scanoutDevice() const { // TODO make this use GraphicsBuffers too? diff --git a/src/backends/drm/drm_qpainter_layer.h b/src/backends/drm/drm_qpainter_layer.h index 8b23917580..c7b656489c 100644 --- a/src/backends/drm/drm_qpainter_layer.h +++ b/src/backends/drm/drm_qpainter_layer.h @@ -7,6 +7,7 @@ SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once +#include "core/renderbackend.h" #include "drm_layer.h" #include "utils/damagejournal.h" @@ -28,11 +29,10 @@ public: explicit DrmQPainterLayer(DrmPipeline *pipeline, DrmPlane::TypeIndex type); std::optional doBeginFrame() override; - bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) override; bool checkTestBuffer() override; std::shared_ptr currentBuffer() const override; void releaseBuffers() override; - std::chrono::nanoseconds queryRenderTime() const override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; @@ -43,8 +43,7 @@ private: std::shared_ptr m_currentBuffer; std::shared_ptr m_currentFramebuffer; DamageJournal m_damageJournal; - std::chrono::steady_clock::time_point m_renderStart; - std::chrono::nanoseconds m_renderTime; + std::unique_ptr m_renderTime; }; class DrmVirtualQPainterLayer : public DrmOutputLayer @@ -53,16 +52,14 @@ public: explicit DrmVirtualQPainterLayer(DrmVirtualOutput *output); std::optional doBeginFrame() override; - bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) override; void releaseBuffers() override; - std::chrono::nanoseconds queryRenderTime() const override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; private: QImage m_image; - std::chrono::steady_clock::time_point m_renderStart; - std::chrono::nanoseconds m_renderTime; + std::unique_ptr m_renderTime; }; } diff --git a/src/backends/drm/drm_virtual_egl_layer.cpp b/src/backends/drm/drm_virtual_egl_layer.cpp index a2b165c1d8..5de0b7145f 100644 --- a/src/backends/drm/drm_virtual_egl_layer.cpp +++ b/src/backends/drm/drm_virtual_egl_layer.cpp @@ -67,9 +67,7 @@ std::optional VirtualEglGbmLayer::doBeginFrame() m_currentSlot = slot; - if (!m_query) { - m_query = std::make_unique(); - } + m_query = std::make_unique(m_eglBackend->openglContextRef()); m_query->begin(); const QRegion repair = m_damageJournal.accumulate(slot->age(), infiniteRegion()); @@ -79,9 +77,10 @@ std::optional VirtualEglGbmLayer::doBeginFrame() }; } -bool VirtualEglGbmLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool VirtualEglGbmLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) { m_query->end(); + frame->addRenderTimeQuery(std::move(m_query)); glFlush(); m_damageJournal.add(damagedRegion); @@ -162,12 +161,6 @@ void VirtualEglGbmLayer::releaseBuffers() } } -std::chrono::nanoseconds VirtualEglGbmLayer::queryRenderTime() const -{ - m_eglBackend->makeCurrent(); - return m_query->result(); -} - DrmDevice *VirtualEglGbmLayer::scanoutDevice() const { return m_eglBackend->drmDevice(); diff --git a/src/backends/drm/drm_virtual_egl_layer.h b/src/backends/drm/drm_virtual_egl_layer.h index 36b774d42a..ef74dd5902 100644 --- a/src/backends/drm/drm_virtual_egl_layer.h +++ b/src/backends/drm/drm_virtual_egl_layer.h @@ -35,11 +35,10 @@ public: ~VirtualEglGbmLayer() override; std::optional doBeginFrame() override; - bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) override; std::shared_ptr texture() const override; void releaseBuffers() override; - std::chrono::nanoseconds queryRenderTime() const override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; const ColorDescription &colorDescription() const; diff --git a/src/backends/virtual/virtual_egl_backend.cpp b/src/backends/virtual/virtual_egl_backend.cpp index b2ebc3e54e..4cf6b31bc5 100644 --- a/src/backends/virtual/virtual_egl_backend.cpp +++ b/src/backends/virtual/virtual_egl_backend.cpp @@ -51,9 +51,7 @@ std::optional VirtualEglLayer::doBeginFrame() return std::nullopt; } - if (!m_query) { - m_query = std::make_unique(); - } + m_query = std::make_unique(m_backend->openglContextRef()); m_query->begin(); return OutputLayerBeginFrameInfo{ @@ -62,23 +60,14 @@ std::optional VirtualEglLayer::doBeginFrame() }; } -bool VirtualEglLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool VirtualEglLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) { m_query->end(); + frame->addRenderTimeQuery(std::move(m_query)); glFlush(); // flush pending rendering commands. return true; } -std::chrono::nanoseconds VirtualEglLayer::queryRenderTime() const -{ - if (m_query) { - m_backend->makeCurrent(); - return m_query->result(); - } else { - return std::chrono::nanoseconds::zero(); - } -} - DrmDevice *VirtualEglLayer::scanoutDevice() const { return m_backend->drmDevice(); diff --git a/src/backends/virtual/virtual_egl_backend.h b/src/backends/virtual/virtual_egl_backend.h index dd2d6f97b7..ec71500a1b 100644 --- a/src/backends/virtual/virtual_egl_backend.h +++ b/src/backends/virtual/virtual_egl_backend.h @@ -31,10 +31,9 @@ public: VirtualEglLayer(Output *output, VirtualEglBackend *backend); std::optional doBeginFrame() override; - bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) override; std::shared_ptr texture() const; - std::chrono::nanoseconds queryRenderTime() const override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; diff --git a/src/backends/virtual/virtual_output.cpp b/src/backends/virtual/virtual_output.cpp index 95a250ab7a..209087da4b 100644 --- a/src/backends/virtual/virtual_output.cpp +++ b/src/backends/virtual/virtual_output.cpp @@ -75,11 +75,9 @@ void VirtualOutput::updateEnabled(bool enabled) void VirtualOutput::vblank(std::chrono::nanoseconds timestamp) { - const auto primaryLayer = Compositor::self()->backend()->primaryLayer(this); - m_frame->presented(std::chrono::nanoseconds(1'000'000'000'000 / refreshRate()), timestamp, primaryLayer->queryRenderTime(), PresentationMode::VSync); + m_frame->presented(std::chrono::nanoseconds(1'000'000'000'000 / refreshRate()), timestamp, PresentationMode::VSync); m_frame.reset(); } - } #include "moc_virtual_output.cpp" diff --git a/src/backends/virtual/virtual_qpainter_backend.cpp b/src/backends/virtual/virtual_qpainter_backend.cpp index 3ccb7a3f5e..940a555e7c 100644 --- a/src/backends/virtual/virtual_qpainter_backend.cpp +++ b/src/backends/virtual/virtual_qpainter_backend.cpp @@ -42,16 +42,17 @@ std::optional VirtualQPainterLayer::doBeginFrame() return std::nullopt; } - m_renderStart = std::chrono::steady_clock::now(); + m_renderTime = std::make_unique(); return OutputLayerBeginFrameInfo{ .renderTarget = RenderTarget(m_current->view()->image()), .repaint = m_output->rect(), }; } -bool VirtualQPainterLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool VirtualQPainterLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) { - m_renderTime = std::chrono::steady_clock::now() - m_renderStart; + m_renderTime->end(); + frame->addRenderTimeQuery(std::move(m_renderTime)); return true; } @@ -60,11 +61,6 @@ QImage *VirtualQPainterLayer::image() return m_current->view()->image(); } -std::chrono::nanoseconds VirtualQPainterLayer::queryRenderTime() const -{ - return m_renderTime; -} - DrmDevice *VirtualQPainterLayer::scanoutDevice() const { return m_backend->drmDevice(); diff --git a/src/backends/virtual/virtual_qpainter_backend.h b/src/backends/virtual/virtual_qpainter_backend.h index 0230e7aa26..22a0be7c37 100644 --- a/src/backends/virtual/virtual_qpainter_backend.h +++ b/src/backends/virtual/virtual_qpainter_backend.h @@ -9,6 +9,7 @@ #pragma once #include "core/outputlayer.h" +#include "core/renderbackend.h" #include "platformsupport/scenes/qpainter/qpainterbackend.h" #include @@ -33,9 +34,8 @@ public: ~VirtualQPainterLayer() override; std::optional doBeginFrame() override; - bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) override; QImage *image(); - std::chrono::nanoseconds queryRenderTime() const override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; @@ -43,8 +43,7 @@ private: VirtualQPainterBackend *const m_backend; std::unique_ptr m_swapchain; std::shared_ptr m_current; - std::chrono::steady_clock::time_point m_renderStart; - std::chrono::nanoseconds m_renderTime = std::chrono::nanoseconds::zero(); + std::unique_ptr m_renderTime; }; class VirtualQPainterBackend : public QPainterBackend diff --git a/src/backends/wayland/wayland_egl_backend.cpp b/src/backends/wayland/wayland_egl_backend.cpp index b8ce7dcc5e..735cd801b4 100644 --- a/src/backends/wayland/wayland_egl_backend.cpp +++ b/src/backends/wayland/wayland_egl_backend.cpp @@ -92,9 +92,7 @@ std::optional WaylandEglPrimaryLayer::doBeginFrame() } const QRegion repair = bufferAgeEnabled ? m_damageJournal.accumulate(m_buffer->age(), infiniteRegion()) : infiniteRegion(); - if (!m_query) { - m_query = std::make_unique(); - } + m_query = std::make_unique(m_backend->openglContextRef()); m_query->begin(); return OutputLayerBeginFrameInfo{ .renderTarget = RenderTarget(m_buffer->framebuffer()), @@ -102,9 +100,10 @@ std::optional WaylandEglPrimaryLayer::doBeginFrame() }; } -bool WaylandEglPrimaryLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool WaylandEglPrimaryLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) { m_query->end(); + frame->addRenderTimeQuery(std::move(m_query)); // Flush rendering commands to the dmabuf. glFlush(); EGLNativeFence releaseFence{m_backend->eglDisplayObject()}; @@ -141,12 +140,6 @@ void WaylandEglPrimaryLayer::present() m_presentationBuffer = nullptr; } -std::chrono::nanoseconds WaylandEglPrimaryLayer::queryRenderTime() const -{ - m_backend->makeCurrent(); - return m_query->result(); -} - DrmDevice *WaylandEglPrimaryLayer::scanoutDevice() const { return m_backend->drmDevice(); @@ -204,9 +197,7 @@ std::optional WaylandEglCursorLayer::doBeginFrame() return std::nullopt; } - if (!m_query) { - m_query = std::make_unique(); - } + m_query = std::make_unique(m_backend->openglContextRef()); m_query->begin(); return OutputLayerBeginFrameInfo{ .renderTarget = RenderTarget(m_buffer->framebuffer()), @@ -214,9 +205,12 @@ std::optional WaylandEglCursorLayer::doBeginFrame() }; } -bool WaylandEglCursorLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool WaylandEglCursorLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) { m_query->end(); + if (frame) { + frame->addRenderTimeQuery(std::move(m_query)); + } // Flush rendering commands to the dmabuf. glFlush(); @@ -230,12 +224,6 @@ bool WaylandEglCursorLayer::doEndFrame(const QRegion &renderedRegion, const QReg return true; } -std::chrono::nanoseconds WaylandEglCursorLayer::queryRenderTime() const -{ - m_backend->makeCurrent(); - return m_query->result(); -} - DrmDevice *WaylandEglCursorLayer::scanoutDevice() const { return m_backend->drmDevice(); @@ -302,7 +290,7 @@ bool WaylandEglBackend::initializeEgl() m_backend->setEglDisplay(EglDisplay::create(eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_KHR, m_backend->drmDevice()->gbmDevice(), nullptr))); } - auto display = m_backend->sceneEglDisplayObject(); + const auto display = m_backend->sceneEglDisplayObject(); if (!display) { return false; } diff --git a/src/backends/wayland/wayland_egl_backend.h b/src/backends/wayland/wayland_egl_backend.h index 61874b6b85..40bb12914c 100644 --- a/src/backends/wayland/wayland_egl_backend.h +++ b/src/backends/wayland/wayland_egl_backend.h @@ -43,8 +43,7 @@ public: void present(); std::optional doBeginFrame() override; - bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; - std::chrono::nanoseconds queryRenderTime() const override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) override; bool doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color) override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; @@ -69,8 +68,7 @@ public: ~WaylandEglCursorLayer() override; std::optional doBeginFrame() override; - bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; - std::chrono::nanoseconds queryRenderTime() const override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; diff --git a/src/backends/wayland/wayland_output.cpp b/src/backends/wayland/wayland_output.cpp index b449fbcf6e..edb00c676e 100644 --- a/src/backends/wayland/wayland_output.cpp +++ b/src/backends/wayland/wayland_output.cpp @@ -126,7 +126,7 @@ WaylandOutput::WaylandOutput(const QString &name, WaylandBackend *backend) connect(m_surface.get(), &KWayland::Client::Surface::frameRendered, this, [this]() { Q_ASSERT(m_frame); const auto primary = Compositor::self()->backend()->primaryLayer(this); - m_frame->presented(std::chrono::nanoseconds(1'000'000'000'000 / refreshRate()), std::chrono::steady_clock::now().time_since_epoch(), primary ? primary->queryRenderTime() : std::chrono::nanoseconds::zero(), PresentationMode::VSync); + m_frame->presented(std::chrono::nanoseconds(1'000'000'000'000 / refreshRate()), std::chrono::steady_clock::now().time_since_epoch(), PresentationMode::VSync); m_frame.reset(); }); diff --git a/src/backends/wayland/wayland_qpainter_backend.cpp b/src/backends/wayland/wayland_qpainter_backend.cpp index 165dfe21d4..ae544e9503 100644 --- a/src/backends/wayland/wayland_qpainter_backend.cpp +++ b/src/backends/wayland/wayland_qpainter_backend.cpp @@ -67,25 +67,21 @@ std::optional WaylandQPainterPrimaryLayer::doBeginFra return std::nullopt; } - m_renderStart = std::chrono::steady_clock::now(); + m_renderTime = std::make_unique(); return OutputLayerBeginFrameInfo{ .renderTarget = RenderTarget(m_back->view()->image()), .repaint = accumulateDamage(m_back->age()), }; } -bool WaylandQPainterPrimaryLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool WaylandQPainterPrimaryLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) { - m_renderTime = std::chrono::steady_clock::now() - m_renderStart; + m_renderTime->end(); + frame->addRenderTimeQuery(std::move(m_renderTime)); m_damageJournal.add(damagedRegion); return true; } -std::chrono::nanoseconds WaylandQPainterPrimaryLayer::queryRenderTime() const -{ - return m_renderTime; -} - DrmDevice *WaylandQPainterPrimaryLayer::scanoutDevice() const { return m_backend->drmDevice(); @@ -119,16 +115,18 @@ std::optional WaylandQPainterCursorLayer::doBeginFram return std::nullopt; } - m_renderStart = std::chrono::steady_clock::now(); + m_renderTime = std::make_unique(); return OutputLayerBeginFrameInfo{ .renderTarget = RenderTarget(m_back->view()->image()), .repaint = infiniteRegion(), }; } -bool WaylandQPainterCursorLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool WaylandQPainterCursorLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) { - m_renderTime = std::chrono::steady_clock::now() - m_renderStart; + if (frame) { + frame->addRenderTimeQuery(std::move(m_renderTime)); + } wl_buffer *buffer = static_cast(m_output)->backend()->importBuffer(m_back->buffer()); Q_ASSERT(buffer); @@ -137,11 +135,6 @@ bool WaylandQPainterCursorLayer::doEndFrame(const QRegion &renderedRegion, const return true; } -std::chrono::nanoseconds WaylandQPainterCursorLayer::queryRenderTime() const -{ - return m_renderTime; -} - DrmDevice *WaylandQPainterCursorLayer::scanoutDevice() const { return m_backend->drmDevice(); diff --git a/src/backends/wayland/wayland_qpainter_backend.h b/src/backends/wayland/wayland_qpainter_backend.h index 325606c2b4..88c45fa1ff 100644 --- a/src/backends/wayland/wayland_qpainter_backend.h +++ b/src/backends/wayland/wayland_qpainter_backend.h @@ -38,8 +38,7 @@ public: ~WaylandQPainterPrimaryLayer() override; std::optional doBeginFrame() override; - bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; - std::chrono::nanoseconds queryRenderTime() const override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; @@ -54,8 +53,7 @@ private: std::unique_ptr m_swapchain; std::shared_ptr m_back; - std::chrono::steady_clock::time_point m_renderStart; - std::chrono::nanoseconds m_renderTime; + std::unique_ptr m_renderTime; friend class WaylandQPainterBackend; }; @@ -69,8 +67,7 @@ public: ~WaylandQPainterCursorLayer() override; std::optional doBeginFrame() override; - bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; - std::chrono::nanoseconds queryRenderTime() const override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; @@ -78,8 +75,7 @@ private: WaylandQPainterBackend *m_backend; std::unique_ptr m_swapchain; std::shared_ptr m_back; - std::chrono::steady_clock::time_point m_renderStart; - std::chrono::nanoseconds m_renderTime; + std::unique_ptr m_renderTime; }; class WaylandQPainterBackend : public QPainterBackend diff --git a/src/backends/x11/standalone/x11_standalone_egl_backend.cpp b/src/backends/x11/standalone/x11_standalone_egl_backend.cpp index 5112bb201d..f4d8411ca1 100644 --- a/src/backends/x11/standalone/x11_standalone_egl_backend.cpp +++ b/src/backends/x11/standalone/x11_standalone_egl_backend.cpp @@ -41,17 +41,12 @@ std::optional EglLayer::doBeginFrame() return m_backend->beginFrame(); } -bool EglLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool EglLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) { - m_backend->endFrame(renderedRegion, damagedRegion); + m_backend->endFrame(renderedRegion, damagedRegion, frame); return true; } -std::chrono::nanoseconds EglLayer::queryRenderTime() const -{ - return m_backend->queryRenderTime(); -} - DrmDevice *EglLayer::scanoutDevice() const { return nullptr; @@ -221,7 +216,7 @@ bool EglBackend::hasClientExtension(const QByteArray &name) bool EglBackend::initRenderingContext() { initClientExtensions(); - auto display = kwinApp()->outputBackend()->sceneEglDisplayObject(); + auto display = m_backend->sceneEglDisplayObject(); // Use eglGetPlatformDisplayEXT() to get the display pointer // if the implementation supports it. @@ -372,9 +367,7 @@ OutputLayerBeginFrameInfo EglBackend::beginFrame() } eglWaitNative(EGL_CORE_NATIVE_ENGINE); - if (!m_query) { - m_query = std::make_unique(); - } + m_query = std::make_unique(m_context); m_query->begin(); return OutputLayerBeginFrameInfo{ .renderTarget = RenderTarget(m_fbo.get()), @@ -382,9 +375,10 @@ OutputLayerBeginFrameInfo EglBackend::beginFrame() }; } -void EglBackend::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +void EglBackend::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) { m_query->end(); + frame->addRenderTimeQuery(std::move(m_query)); // Save the damaged region to history if (supportsBufferAge()) { m_damageJournal.add(damagedRegion); @@ -445,15 +439,9 @@ OutputLayer *EglBackend::primaryLayer(Output *output) return m_layer.get(); } -std::chrono::nanoseconds EglBackend::queryRenderTime() -{ - makeCurrent(); - return m_query->result(); -} - void EglBackend::vblank(std::chrono::nanoseconds timestamp) { - m_frame->presented(std::chrono::nanoseconds::zero(), timestamp, queryRenderTime(), PresentationMode::VSync); + m_frame->presented(std::chrono::nanoseconds::zero(), timestamp, PresentationMode::VSync); m_frame.reset(); } diff --git a/src/backends/x11/standalone/x11_standalone_egl_backend.h b/src/backends/x11/standalone/x11_standalone_egl_backend.h index b67cf89c54..bd32548607 100644 --- a/src/backends/x11/standalone/x11_standalone_egl_backend.h +++ b/src/backends/x11/standalone/x11_standalone_egl_backend.h @@ -36,8 +36,7 @@ public: EglLayer(EglBackend *backend); std::optional doBeginFrame() override; - bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; - std::chrono::nanoseconds queryRenderTime() const override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; @@ -56,12 +55,11 @@ public: std::unique_ptr createSurfaceTextureX11(SurfacePixmapX11 *texture) override; OutputLayerBeginFrameInfo beginFrame(); - void endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion); + void endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame); void present(Output *output, const std::shared_ptr &frame) override; OverlayWindow *overlayWindow() const override; OutputLayer *primaryLayer(Output *output) override; - std::chrono::nanoseconds queryRenderTime(); - EglDisplay *eglDisplayObject() const; + EglDisplay *eglDisplayObject() const override; OpenGlContext *openglContext() const override; bool makeCurrent() override; void doneCurrent() override; @@ -91,7 +89,7 @@ private: std::shared_ptr m_frame; QList m_clientExtensions; - std::unique_ptr m_context; + std::shared_ptr m_context; ::EGLSurface m_surface = EGL_NO_SURFACE; }; diff --git a/src/backends/x11/standalone/x11_standalone_glx_backend.cpp b/src/backends/x11/standalone/x11_standalone_glx_backend.cpp index a673cbb30e..a518d0cd43 100644 --- a/src/backends/x11/standalone/x11_standalone_glx_backend.cpp +++ b/src/backends/x11/standalone/x11_standalone_glx_backend.cpp @@ -109,17 +109,12 @@ std::optional GlxLayer::doBeginFrame() return m_backend->doBeginFrame(); } -bool GlxLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool GlxLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) { - m_backend->endFrame(renderedRegion, damagedRegion); + m_backend->endFrame(renderedRegion, damagedRegion, frame); return true; } -std::chrono::nanoseconds GlxLayer::queryRenderTime() const -{ - return m_backend->queryRenderTime(); -} - DrmDevice *GlxLayer::scanoutDevice() const { return nullptr; @@ -665,9 +660,6 @@ OutputLayerBeginFrameInfo GlxBackend::doBeginFrame() { QRegion repaint; makeCurrent(); - if (!m_query) { - m_query = std::make_unique(); - } if (supportsBufferAge()) { repaint = m_damageJournal.accumulate(m_bufferAge, infiniteRegion()); @@ -675,9 +667,7 @@ OutputLayerBeginFrameInfo GlxBackend::doBeginFrame() glXWaitX(); - if (!m_query) { - m_query = std::make_unique(); - } + m_query = std::make_unique(m_context); m_query->begin(); return OutputLayerBeginFrameInfo{ .renderTarget = RenderTarget(m_fbo.get()), @@ -685,9 +675,10 @@ OutputLayerBeginFrameInfo GlxBackend::doBeginFrame() }; } -void GlxBackend::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +void GlxBackend::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) { m_query->end(); + frame->addRenderTimeQuery(std::move(m_query)); // Save the damaged region to history if (supportsBufferAge()) { m_damageJournal.add(damagedRegion); @@ -695,12 +686,6 @@ void GlxBackend::endFrame(const QRegion &renderedRegion, const QRegion &damagedR m_lastRenderedRegion = renderedRegion; } -std::chrono::nanoseconds GlxBackend::queryRenderTime() -{ - makeCurrent(); - return m_query->result(); -} - void GlxBackend::present(Output *output, const std::shared_ptr &frame) { m_frame = frame; @@ -729,7 +714,7 @@ void GlxBackend::present(Output *output, const std::shared_ptr &fra void GlxBackend::vblank(std::chrono::nanoseconds timestamp) { - m_frame->presented(std::chrono::nanoseconds::zero(), timestamp, queryRenderTime(), PresentationMode::VSync); + m_frame->presented(std::chrono::nanoseconds::zero(), timestamp, PresentationMode::VSync); m_frame.reset(); } diff --git a/src/backends/x11/standalone/x11_standalone_glx_backend.h b/src/backends/x11/standalone/x11_standalone_glx_backend.h index 31ef5ca4f1..3b45ba19b8 100644 --- a/src/backends/x11/standalone/x11_standalone_glx_backend.h +++ b/src/backends/x11/standalone/x11_standalone_glx_backend.h @@ -64,8 +64,7 @@ public: GlxLayer(GlxBackend *backend); std::optional doBeginFrame() override; - bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; - std::chrono::nanoseconds queryRenderTime() const override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; @@ -85,8 +84,7 @@ public: ~GlxBackend() override; std::unique_ptr createSurfaceTextureX11(SurfacePixmapX11 *pixmap) override; OutputLayerBeginFrameInfo doBeginFrame(); - void endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion); - std::chrono::nanoseconds queryRenderTime(); + void endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame); void present(Output *output, const std::shared_ptr &frame) override; bool makeCurrent() override; void doneCurrent() override; @@ -122,7 +120,7 @@ private: ::Window window; GLXFBConfig fbconfig; GLXWindow glxWindow; - std::unique_ptr m_context; + std::shared_ptr m_context; QHash m_fbconfigHash; QHash m_visualDepthHash; std::unique_ptr m_swapEventFilter; diff --git a/src/backends/x11/windowed/x11_windowed_egl_backend.cpp b/src/backends/x11/windowed/x11_windowed_egl_backend.cpp index c84b01278c..de5528189c 100644 --- a/src/backends/x11/windowed/x11_windowed_egl_backend.cpp +++ b/src/backends/x11/windowed/x11_windowed_egl_backend.cpp @@ -59,9 +59,7 @@ std::optional X11WindowedEglPrimaryLayer::doBeginFram QRegion repaint = m_output->exposedArea() + m_output->rect(); m_output->clearExposedArea(); - if (!m_query) { - m_query = std::make_unique(); - } + m_query = std::make_unique(m_backend->openglContextRef()); m_query->begin(); return OutputLayerBeginFrameInfo{ .renderTarget = RenderTarget(m_buffer->framebuffer()), @@ -69,9 +67,10 @@ std::optional X11WindowedEglPrimaryLayer::doBeginFram }; } -bool X11WindowedEglPrimaryLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool X11WindowedEglPrimaryLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) { m_query->end(); + frame->addRenderTimeQuery(std::move(m_query)); return true; } @@ -113,12 +112,6 @@ std::shared_ptr X11WindowedEglPrimaryLayer::texture() const return m_buffer->texture(); } -std::chrono::nanoseconds X11WindowedEglPrimaryLayer::queryRenderTime() const -{ - m_backend->makeCurrent(); - return m_query->result(); -} - DrmDevice *X11WindowedEglPrimaryLayer::scanoutDevice() const { return m_backend->drmDevice(); @@ -158,7 +151,7 @@ std::optional X11WindowedEglCursorLayer::doBeginFrame m_framebuffer = std::make_unique(m_texture.get()); } if (!m_query) { - m_query = std::make_unique(); + m_query = std::make_unique(m_backend->openglContextRef()); } m_query->begin(); return OutputLayerBeginFrameInfo{ @@ -167,7 +160,7 @@ std::optional X11WindowedEglCursorLayer::doBeginFrame }; } -bool X11WindowedEglCursorLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool X11WindowedEglCursorLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) { QImage buffer(m_framebuffer->size(), QImage::Format_RGBA8888_Premultiplied); @@ -177,16 +170,13 @@ bool X11WindowedEglCursorLayer::doEndFrame(const QRegion &renderedRegion, const static_cast(m_output)->cursor()->update(buffer.mirrored(false, true), hotspot()); m_query->end(); + if (frame) { + frame->addRenderTimeQuery(std::move(m_query)); + } return true; } -std::chrono::nanoseconds X11WindowedEglCursorLayer::queryRenderTime() const -{ - m_backend->makeCurrent(); - return m_query->result(); -} - DrmDevice *X11WindowedEglCursorLayer::scanoutDevice() const { return m_backend->drmDevice(); @@ -233,7 +223,7 @@ bool X11WindowedEglBackend::initializeEgl() m_backend->setEglDisplay(EglDisplay::create(eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_KHR, m_backend->drmDevice()->gbmDevice(), nullptr))); } - auto display = m_backend->sceneEglDisplayObject(); + const auto display = m_backend->sceneEglDisplayObject(); if (!display) { return false; } diff --git a/src/backends/x11/windowed/x11_windowed_egl_backend.h b/src/backends/x11/windowed/x11_windowed_egl_backend.h index 684a7efd8a..2eed97295e 100644 --- a/src/backends/x11/windowed/x11_windowed_egl_backend.h +++ b/src/backends/x11/windowed/x11_windowed_egl_backend.h @@ -29,8 +29,7 @@ public: ~X11WindowedEglPrimaryLayer() override; std::optional doBeginFrame() override; - bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; - std::chrono::nanoseconds queryRenderTime() const override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; @@ -54,8 +53,7 @@ public: ~X11WindowedEglCursorLayer() override; std::optional doBeginFrame() override; - bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; - std::chrono::nanoseconds queryRenderTime() const override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; diff --git a/src/backends/x11/windowed/x11_windowed_output.cpp b/src/backends/x11/windowed/x11_windowed_output.cpp index 754bfb23ee..81825d9d0b 100644 --- a/src/backends/x11/windowed/x11_windowed_output.cpp +++ b/src/backends/x11/windowed/x11_windowed_output.cpp @@ -308,7 +308,7 @@ void X11WindowedOutput::resize(const QSize &pixelSize) void X11WindowedOutput::handlePresentCompleteNotify(xcb_present_complete_notify_event_t *event) { std::chrono::microseconds timestamp(event->ust); - m_frame->presented(std::chrono::nanoseconds(1'000'000'000'000 / refreshRate()), timestamp, Compositor::self()->backend()->primaryLayer(this)->queryRenderTime(), PresentationMode::VSync); + m_frame->presented(std::chrono::nanoseconds(1'000'000'000'000 / refreshRate()), timestamp, PresentationMode::VSync); m_frame.reset(); } diff --git a/src/backends/x11/windowed/x11_windowed_qpainter_backend.cpp b/src/backends/x11/windowed/x11_windowed_qpainter_backend.cpp index f2b712893d..32b4a0ff49 100644 --- a/src/backends/x11/windowed/x11_windowed_qpainter_backend.cpp +++ b/src/backends/x11/windowed/x11_windowed_qpainter_backend.cpp @@ -48,16 +48,17 @@ std::optional X11WindowedQPainterPrimaryLayer::doBegi QRegion repaint = m_output->exposedArea() + m_output->rect(); m_output->clearExposedArea(); - m_renderStart = std::chrono::steady_clock::now(); + m_renderTime = std::make_unique(); return OutputLayerBeginFrameInfo{ .renderTarget = RenderTarget(m_current->view()->image()), .repaint = repaint, }; } -bool X11WindowedQPainterPrimaryLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool X11WindowedQPainterPrimaryLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) { - m_renderTime = std::chrono::steady_clock::now() - m_renderStart; + m_renderTime->end(); + frame->addRenderTimeQuery(std::move(m_renderTime)); return true; } @@ -91,11 +92,6 @@ void X11WindowedQPainterPrimaryLayer::present() nullptr); } -std::chrono::nanoseconds X11WindowedQPainterPrimaryLayer::queryRenderTime() const -{ - return m_renderTime; -} - DrmDevice *X11WindowedQPainterPrimaryLayer::scanoutDevice() const { return m_backend->drmDevice(); @@ -120,21 +116,19 @@ std::optional X11WindowedQPainterCursorLayer::doBegin m_buffer = QImage(bufferSize, QImage::Format_ARGB32_Premultiplied); } - m_renderStart = std::chrono::steady_clock::now(); + m_renderTime = std::make_unique(); return OutputLayerBeginFrameInfo{ .renderTarget = RenderTarget(&m_buffer), .repaint = infiniteRegion(), }; } -std::chrono::nanoseconds X11WindowedQPainterCursorLayer::queryRenderTime() const +bool X11WindowedQPainterCursorLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) { - return m_renderTime; -} - -bool X11WindowedQPainterCursorLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) -{ - m_renderTime = std::chrono::steady_clock::now() - m_renderStart; + m_renderTime->end(); + if (frame) { + frame->addRenderTimeQuery(std::move(m_renderTime)); + } m_output->cursor()->update(m_buffer, hotspot()); return true; } diff --git a/src/backends/x11/windowed/x11_windowed_qpainter_backend.h b/src/backends/x11/windowed/x11_windowed_qpainter_backend.h index 04e20367ab..c235b6f6ad 100644 --- a/src/backends/x11/windowed/x11_windowed_qpainter_backend.h +++ b/src/backends/x11/windowed/x11_windowed_qpainter_backend.h @@ -35,8 +35,7 @@ public: ~X11WindowedQPainterPrimaryLayer() override; std::optional doBeginFrame() override; - bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; - std::chrono::nanoseconds queryRenderTime() const override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; @@ -47,8 +46,7 @@ private: X11WindowedQPainterBackend *const m_backend; std::unique_ptr m_swapchain; std::shared_ptr m_current; - std::chrono::steady_clock::time_point m_renderStart; - std::chrono::nanoseconds m_renderTime; + std::unique_ptr m_renderTime; }; class X11WindowedQPainterCursorLayer : public OutputLayer @@ -59,16 +57,14 @@ public: explicit X11WindowedQPainterCursorLayer(X11WindowedOutput *output); std::optional doBeginFrame() override; - bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; - std::chrono::nanoseconds queryRenderTime() const override; + bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) override; DrmDevice *scanoutDevice() const override; QHash> supportedDrmFormats() const override; private: QImage m_buffer; X11WindowedOutput *m_output; - std::chrono::steady_clock::time_point m_renderStart; - std::chrono::nanoseconds m_renderTime; + std::unique_ptr m_renderTime; }; class X11WindowedQPainterBackend : public QPainterBackend diff --git a/src/compositor_wayland.cpp b/src/compositor_wayland.cpp index 5b7b8bbe29..9e06aeeaa2 100644 --- a/src/compositor_wayland.cpp +++ b/src/compositor_wayland.cpp @@ -335,7 +335,7 @@ void WaylandCompositor::composite(RenderLoop *renderLoop) const QRegion bufferDamage = surfaceDamage.united(repaint).intersected(superLayer->rect().toAlignedRect()); paintPass(superLayer, renderTarget, bufferDamage); - primaryLayer->endFrame(bufferDamage, surfaceDamage); + primaryLayer->endFrame(bufferDamage, surfaceDamage, frame.get()); } } @@ -422,7 +422,7 @@ void WaylandCompositor::addOutput(Output *output) renderLayer.delegate()->paint(renderTarget, infiniteRegion()); renderLayer.delegate()->postPaint(); - if (!outputLayer->endFrame(infiniteRegion(), infiniteRegion())) { + if (!outputLayer->endFrame(infiniteRegion(), infiniteRegion(), nullptr)) { return false; } } else { diff --git a/src/compositor_x11.cpp b/src/compositor_x11.cpp index ee9d8528ca..7db12838e5 100644 --- a/src/compositor_x11.cpp +++ b/src/compositor_x11.cpp @@ -472,7 +472,7 @@ void X11Compositor::composite(RenderLoop *renderLoop) const QRegion bufferDamage = surfaceDamage.united(repaint).intersected(superLayer->rect().toAlignedRect()); paintPass(superLayer, renderTarget, bufferDamage); - primaryLayer->endFrame(bufferDamage, surfaceDamage); + primaryLayer->endFrame(bufferDamage, surfaceDamage, frame.get()); } postPaintPass(superLayer); diff --git a/src/core/outputlayer.cpp b/src/core/outputlayer.cpp index 8e27c9bafc..b29d8de353 100644 --- a/src/core/outputlayer.cpp +++ b/src/core/outputlayer.cpp @@ -108,9 +108,9 @@ std::optional OutputLayer::beginFrame() return doBeginFrame(); } -bool OutputLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool OutputLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) { - return doEndFrame(renderedRegion, damagedRegion); + return doEndFrame(renderedRegion, damagedRegion, frame); } void OutputLayer::notifyNoScanoutCandidate() diff --git a/src/core/outputlayer.h b/src/core/outputlayer.h index 3f0b5d0056..02ac1cf596 100644 --- a/src/core/outputlayer.h +++ b/src/core/outputlayer.h @@ -21,6 +21,7 @@ namespace KWin class SurfaceItem; class DrmDevice; class GraphicsBuffer; +class OutputFrame; struct OutputLayerBeginFrameInfo { @@ -58,7 +59,7 @@ public: bool isEnabled() const; std::optional beginFrame(); - bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion); + bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame); /** * Tries to import the newest buffer of the surface for direct scanout @@ -71,11 +72,6 @@ public: */ void notifyNoScanoutCandidate(); - /** - * queries the render time of the last frame. If rendering isn't complete yet, this may block until it is - */ - virtual std::chrono::nanoseconds queryRenderTime() const = 0; - virtual DrmDevice *scanoutDevice() const = 0; virtual QHash> supportedDrmFormats() const = 0; @@ -101,7 +97,7 @@ public: protected: virtual bool doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color); virtual std::optional doBeginFrame() = 0; - virtual bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) = 0; + virtual bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) = 0; QRegion m_repaints; QPointF m_hotspot; diff --git a/src/core/renderbackend.cpp b/src/core/renderbackend.cpp index 1021d28e4a..a34f9be11c 100644 --- a/src/core/renderbackend.cpp +++ b/src/core/renderbackend.cpp @@ -10,10 +10,27 @@ #include "syncobjtimeline.h" #include +#include namespace KWin { +CpuRenderTimeQuery::CpuRenderTimeQuery() + : m_start(std::chrono::steady_clock::now()) +{ +} + +void CpuRenderTimeQuery::end() +{ + m_end = std::chrono::steady_clock::now(); +} + +std::chrono::nanoseconds CpuRenderTimeQuery::query() +{ + Q_ASSERT(m_end); + return *m_end - m_start; +} + OutputFrame::OutputFrame(RenderLoop *loop) : m_loop(loop) { @@ -26,8 +43,12 @@ void OutputFrame::addFeedback(std::unique_ptr &&feedback) m_feedbacks.push_back(std::move(feedback)); } -void OutputFrame::presented(std::chrono::nanoseconds refreshDuration, std::chrono::nanoseconds timestamp, std::chrono::nanoseconds renderTime, PresentationMode mode) +void OutputFrame::presented(std::chrono::nanoseconds refreshDuration, std::chrono::nanoseconds timestamp, PresentationMode mode) { + const auto view = m_renderTimeQueries | std::views::transform([](const auto &query) { + return query->query(); + }); + const auto renderTime = std::accumulate(view.begin(), view.end(), std::chrono::nanoseconds::zero()); RenderLoopPrivate::get(m_loop)->notifyFrameCompleted(timestamp, renderTime, mode); for (const auto &feedback : m_feedbacks) { feedback->presented(refreshDuration, timestamp, mode); @@ -69,6 +90,11 @@ QRegion OutputFrame::damage() const return m_damage; } +void OutputFrame::addRenderTimeQuery(std::unique_ptr &&query) +{ + m_renderTimeQueries.push_back(std::move(query)); +} + RenderBackend::RenderBackend(QObject *parent) : QObject(parent) { diff --git a/src/core/renderbackend.h b/src/core/renderbackend.h index 6115df397a..700f516fb8 100644 --- a/src/core/renderbackend.h +++ b/src/core/renderbackend.h @@ -40,13 +40,37 @@ public: virtual void presented(std::chrono::nanoseconds refreshCycleDuration, std::chrono::nanoseconds timestamp, PresentationMode mode) = 0; }; +class KWIN_EXPORT RenderTimeQuery +{ +public: + virtual ~RenderTimeQuery() = default; + virtual std::chrono::nanoseconds query() = 0; +}; + +class KWIN_EXPORT CpuRenderTimeQuery : public RenderTimeQuery +{ +public: + /** + * marks the start of the query + */ + explicit CpuRenderTimeQuery(); + + void end(); + + std::chrono::nanoseconds query() override; + +private: + const std::chrono::steady_clock::time_point m_start; + std::optional m_end; +}; + class KWIN_EXPORT OutputFrame { public: explicit OutputFrame(RenderLoop *loop); ~OutputFrame(); - void presented(std::chrono::nanoseconds refreshDuration, std::chrono::nanoseconds timestamp, std::chrono::nanoseconds renderTime, PresentationMode mode); + void presented(std::chrono::nanoseconds refreshDuration, std::chrono::nanoseconds timestamp, PresentationMode mode); void failed(); void addFeedback(std::unique_ptr &&feedback); @@ -59,6 +83,7 @@ public: void setDamage(const QRegion ®ion); QRegion damage() const; + void addRenderTimeQuery(std::unique_ptr &&query); private: RenderLoop *const m_loop; @@ -66,6 +91,7 @@ private: std::optional m_contentType; PresentationMode m_presentationMode = PresentationMode::VSync; QRegion m_damage; + std::vector> m_renderTimeQueries; }; /** diff --git a/src/opengl/glrendertimequery.cpp b/src/opengl/glrendertimequery.cpp index 6b0a7879c0..8bd59e7b1d 100644 --- a/src/opengl/glrendertimequery.cpp +++ b/src/opengl/glrendertimequery.cpp @@ -12,18 +12,25 @@ namespace KWin { -GLRenderTimeQuery::GLRenderTimeQuery() +GLRenderTimeQuery::GLRenderTimeQuery(const std::shared_ptr &context) + : m_context(context) { - if (OpenGlContext::currentContext()->supportsTimerQueries()) { + if (context->supportsTimerQueries()) { glGenQueries(1, &m_gpuProbe.query); } } GLRenderTimeQuery::~GLRenderTimeQuery() { - if (m_gpuProbe.query) { - glDeleteQueries(1, &m_gpuProbe.query); + if (!m_gpuProbe.query) { + return; } + const auto context = m_context.lock(); + if (!context) { + return; + } + context->makeCurrent(); + glDeleteQueries(1, &m_gpuProbe.query); } void GLRenderTimeQuery::begin() @@ -44,7 +51,7 @@ void GLRenderTimeQuery::end() m_cpuProbe.end = std::chrono::steady_clock::now().time_since_epoch(); } -std::chrono::nanoseconds GLRenderTimeQuery::result() +std::chrono::nanoseconds GLRenderTimeQuery::query() { if (!m_hasResult) { return std::chrono::nanoseconds::zero(); @@ -52,6 +59,11 @@ std::chrono::nanoseconds GLRenderTimeQuery::result() m_hasResult = false; if (m_gpuProbe.query) { + const auto context = m_context.lock(); + if (!context) { + return std::chrono::nanoseconds::zero(); + } + context->makeCurrent(); glGetQueryObjecti64v(m_gpuProbe.query, GL_QUERY_RESULT, &m_gpuProbe.end); } diff --git a/src/opengl/glrendertimequery.h b/src/opengl/glrendertimequery.h index 0778fd5c7b..ba83b0d077 100644 --- a/src/opengl/glrendertimequery.h +++ b/src/opengl/glrendertimequery.h @@ -11,15 +11,18 @@ #include #include +#include "core/renderbackend.h" #include "kwin_export.h" namespace KWin { -class KWIN_EXPORT GLRenderTimeQuery +class OpenGlContext; + +class KWIN_EXPORT GLRenderTimeQuery : public RenderTimeQuery { public: - explicit GLRenderTimeQuery(); + explicit GLRenderTimeQuery(const std::shared_ptr &context); ~GLRenderTimeQuery(); void begin(); @@ -28,9 +31,10 @@ public: /** * fetches the result of the query. If rendering is not done yet, this will block! */ - std::chrono::nanoseconds result(); + std::chrono::nanoseconds query() override; private: + const std::weak_ptr m_context; bool m_hasResult = false; struct diff --git a/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp b/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp index a60ba104d0..560a680eab 100644 --- a/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp +++ b/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp @@ -335,6 +335,11 @@ EglContext *AbstractEglBackend::openglContext() const { return m_context.get(); } + +std::shared_ptr AbstractEglBackend::openglContextRef() const +{ + return m_context; +} } #include "moc_abstract_egl_backend.cpp" diff --git a/src/platformsupport/scenes/opengl/abstract_egl_backend.h b/src/platformsupport/scenes/opengl/abstract_egl_backend.h index 0d2760022b..0d8a4ed6db 100644 --- a/src/platformsupport/scenes/opengl/abstract_egl_backend.h +++ b/src/platformsupport/scenes/opengl/abstract_egl_backend.h @@ -35,6 +35,7 @@ public: EGLConfig config() const; EglDisplay *eglDisplayObject() const override; EglContext *openglContext() const override; + std::shared_ptr openglContextRef() const; bool testImportBuffer(GraphicsBuffer *buffer) override; QHash> supportedFormats() const override; diff --git a/src/plugins/qpa/eglplatformcontext.h b/src/plugins/qpa/eglplatformcontext.h index f9ffe6531c..a3ac1701b7 100644 --- a/src/plugins/qpa/eglplatformcontext.h +++ b/src/plugins/qpa/eglplatformcontext.h @@ -62,7 +62,7 @@ private: void create(const QSurfaceFormat &format, ::EGLContext shareContext); void updateFormatFromContext(); - EglDisplay *m_eglDisplay = nullptr; + EglDisplay *const m_eglDisplay; QSurfaceFormat m_format; EGLConfig m_config = EGL_NO_CONFIG_KHR; std::shared_ptr m_eglContext; diff --git a/src/plugins/qpa/integration.cpp b/src/plugins/qpa/integration.cpp index 238a2e6062..51e21dbc4b 100644 --- a/src/plugins/qpa/integration.cpp +++ b/src/plugins/qpa/integration.cpp @@ -152,7 +152,7 @@ QPlatformOpenGLContext *Integration::createPlatformOpenGLContext(QOpenGLContext qCWarning(KWIN_QPA) << "Attempting to create a QOpenGLContext before the scene is initialized"; return nullptr; } - EglDisplay *const eglDisplay = kwinApp()->outputBackend()->sceneEglDisplayObject(); + const auto eglDisplay = kwinApp()->outputBackend()->sceneEglDisplayObject(); if (eglDisplay) { EGLPlatformContext *platformContext = new EGLPlatformContext(context, eglDisplay); return platformContext;