backends: record GPU render time

This should make it much less likely for KWin to miss frames
master
Xaver Hugl 1 year ago
parent 02b996cf9c
commit 44937136cd

@ -405,7 +405,6 @@ void DrmTest::testModeset()
const auto layer = renderBackend->primaryLayer(output);
layer->beginFrame();
output->renderLoop()->beginFrame();
output->renderLoop()->endFrame();
layer->endFrame(infiniteRegion(), infiniteRegion());
QVERIFY(gpu->drmOutputs().front()->present());

@ -10,6 +10,7 @@
#include "core/renderloop_p.h"
#include "drm_backend.h"
#include "drm_gpu.h"
#include "drm_layer.h"
namespace KWin
{
@ -33,7 +34,8 @@ void DrmAbstractOutput::frameFailed() const
void DrmAbstractOutput::pageFlipped(std::chrono::nanoseconds timestamp) const
{
RenderLoopPrivate::get(m_renderLoop.get())->notifyFrameCompleted(timestamp);
const auto gpuTime = primaryLayer() ? primaryLayer()->queryRenderTime() : std::chrono::nanoseconds::zero();
RenderLoopPrivate::get(m_renderLoop.get())->notifyFrameCompleted(timestamp, gpuTime);
}
DrmGpu *DrmAbstractOutput::gpu() const

@ -78,4 +78,9 @@ quint32 EglGbmCursorLayer::format() const
{
return m_surface.currentBuffer()->buffer()->dmabufAttributes()->format;
}
std::chrono::nanoseconds EglGbmCursorLayer::queryRenderTime() const
{
return m_surface.queryRenderTime();
}
}

@ -35,6 +35,7 @@ public:
bool checkTestBuffer() override;
void releaseBuffers() override;
quint32 format() const override;
std::chrono::nanoseconds queryRenderTime() const override;
private:
EglGbmLayerSurface m_surface;

@ -167,4 +167,9 @@ void EglGbmLayer::releaseBuffers()
m_scanoutBuffer.reset();
m_surface.destroyResources();
}
std::chrono::nanoseconds EglGbmLayer::queryRenderTime() const
{
return m_surface.queryRenderTime();
}
}

@ -38,6 +38,7 @@ public:
std::shared_ptr<GLTexture> texture() const override;
ColorDescription colorDescription() const;
void releaseBuffers() override;
std::chrono::nanoseconds queryRenderTime() const override;
private:
std::shared_ptr<DrmFramebuffer> m_scanoutBuffer;

@ -15,6 +15,7 @@
#include "drm_logging.h"
#include "platformsupport/scenes/opengl/eglnativefence.h"
#include "platformsupport/scenes/opengl/eglswapchain.h"
#include "platformsupport/scenes/opengl/glrendertimequery.h"
#include "platformsupport/scenes/qpainter/qpainterswapchain.h"
#include "utils/drm_format_helper.h"
@ -98,6 +99,8 @@ std::optional<OutputLayerBeginFrameInfo> EglGbmLayerSurface::startRendering(cons
}
m_surface.shadowBuffer = std::make_shared<GLFramebuffer>(m_surface.shadowTexture.get());
}
m_surface.renderStart = std::chrono::steady_clock::now();
m_surface.timeQuery->begin();
return OutputLayerBeginFrameInfo{
.renderTarget = RenderTarget(m_surface.shadowBuffer.get(), m_surface.intermediaryColorDescription),
.repaint = repaint,
@ -105,6 +108,8 @@ std::optional<OutputLayerBeginFrameInfo> EglGbmLayerSurface::startRendering(cons
} else {
m_surface.shadowTexture.reset();
m_surface.shadowBuffer.reset();
m_surface.renderStart = std::chrono::steady_clock::now();
m_surface.timeQuery->begin();
return OutputLayerBeginFrameInfo{
.renderTarget = RenderTarget(m_surface.currentSlot->framebuffer()),
.repaint = repaint,
@ -134,8 +139,10 @@ bool EglGbmLayerSurface::endRendering(const QRegion &damagedRegion)
}
m_surface.damageJournal.add(damagedRegion);
m_surface.gbmSwapchain->release(m_surface.currentSlot);
m_surface.timeQuery->end();
glFlush();
const auto buffer = importBuffer(m_surface, m_surface.currentSlot.get());
m_surface.renderEnd = std::chrono::steady_clock::now();
if (buffer) {
m_surface.currentFramebuffer = buffer;
return true;
@ -144,6 +151,21 @@ bool EglGbmLayerSurface::endRendering(const QRegion &damagedRegion)
}
}
std::chrono::nanoseconds EglGbmLayerSurface::queryRenderTime() const
{
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;
@ -320,7 +342,9 @@ std::optional<EglGbmLayerSurface::Surface> EglGbmLayerSurface::createSurface(con
if (!ret.importGbmSwapchain) {
return std::nullopt;
}
ret.importTimeQuery = std::make_shared<GLRenderTimeQuery>();
}
ret.timeQuery = std::make_shared<GLRenderTimeQuery>();
if (!doRenderTestBuffer(ret)) {
return std::nullopt;
}
@ -402,6 +426,7 @@ std::shared_ptr<DrmFramebuffer> EglGbmLayerSurface::importWithEgl(Surface &surfa
if (!context || context->isSoftwareRenderer() || !context->makeCurrent()) {
return nullptr;
}
surface.importTimeQuery->begin();
if (sourceFence.isValid()) {
const auto destinationFence = EGLNativeFence::importFence(context->displayObject(), sourceFence.fileDescriptor().duplicate());
@ -441,9 +466,9 @@ std::shared_ptr<DrmFramebuffer> EglGbmLayerSurface::importWithEgl(Surface &surfa
context->shaderManager()->popShader();
glFlush();
surface.importGbmSwapchain->release(slot);
surface.importTimeQuery->end();
// restore the old context
context->doneCurrent();
m_eglBackend->makeCurrent();
return m_gpu->importBuffer(slot->buffer());
}

@ -12,6 +12,7 @@
#include <QMap>
#include <QPointer>
#include <QRegion>
#include <chrono>
#include <optional>
#include "core/outputlayer.h"
@ -34,6 +35,7 @@ class EglGbmBackend;
class GraphicsBuffer;
class SurfaceItem;
class GLTexture;
class GLRenderTimeQuery;
class EglGbmLayerSurface : public QObject
{
@ -53,6 +55,7 @@ public:
std::optional<OutputLayerBeginFrameInfo> startRendering(const QSize &bufferSize, TextureTransforms transformation, const QMap<uint32_t, QVector<uint64_t>> &formats, const ColorDescription &colorDescription, const QVector3D &channelFactors, bool enableColormanagement);
bool endRendering(const QRegion &damagedRegion);
std::chrono::nanoseconds queryRenderTime() const;
bool doesSurfaceFit(const QSize &size, const QMap<uint32_t, QVector<uint64_t>> &formats) const;
std::shared_ptr<GLTexture> texture() const;
@ -89,6 +92,12 @@ private:
MultiGpuImportMode importMode;
std::shared_ptr<DrmFramebuffer> currentFramebuffer;
bool forceLinear = false;
// for render timing
std::shared_ptr<GLRenderTimeQuery> timeQuery;
std::shared_ptr<GLRenderTimeQuery> importTimeQuery;
std::chrono::steady_clock::time_point renderStart;
std::chrono::steady_clock::time_point renderEnd;
};
bool checkSurface(const QSize &size, const QMap<uint32_t, QVector<uint64_t>> &formats);
bool doesSurfaceFit(const Surface &surface, const QSize &size, const QMap<uint32_t, QVector<uint64_t>> &formats) const;

@ -38,6 +38,7 @@ std::optional<OutputLayerBeginFrameInfo> DrmQPainterLayer::beginFrame()
return std::nullopt;
}
m_renderStart = std::chrono::steady_clock::now();
const QRegion repaint = m_damageJournal.accumulate(m_currentBuffer->age(), infiniteRegion());
return OutputLayerBeginFrameInfo{
.renderTarget = RenderTarget(m_currentBuffer->view()->image()),
@ -47,6 +48,7 @@ std::optional<OutputLayerBeginFrameInfo> DrmQPainterLayer::beginFrame()
bool DrmQPainterLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_renderTime = std::chrono::steady_clock::now() - m_renderStart;
m_currentFramebuffer = m_pipeline->gpu()->importBuffer(m_currentBuffer->buffer());
m_damageJournal.add(damagedRegion);
m_swapchain->release(m_currentBuffer);
@ -99,6 +101,11 @@ quint32 DrmQPainterLayer::format() const
return DRM_FORMAT_XRGB8888;
}
std::chrono::nanoseconds DrmQPainterLayer::queryRenderTime() const
{
return m_renderTime;
}
DrmCursorQPainterLayer::DrmCursorQPainterLayer(DrmPipeline *pipeline)
: DrmOverlayLayer(pipeline)
{
@ -113,6 +120,7 @@ std::optional<OutputLayerBeginFrameInfo> DrmCursorQPainterLayer::beginFrame()
if (!m_currentBuffer) {
return std::nullopt;
}
m_renderStart = std::chrono::steady_clock::now();
return OutputLayerBeginFrameInfo{
.renderTarget = RenderTarget(m_currentBuffer->view()->image()),
.repaint = infiniteRegion(),
@ -121,6 +129,7 @@ std::optional<OutputLayerBeginFrameInfo> DrmCursorQPainterLayer::beginFrame()
bool DrmCursorQPainterLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_renderTime = std::chrono::steady_clock::now() - m_renderStart;
m_currentFramebuffer = m_pipeline->gpu()->importBuffer(m_currentBuffer->buffer());
m_swapchain->release(m_currentBuffer);
if (!m_currentFramebuffer) {
@ -149,6 +158,11 @@ void DrmCursorQPainterLayer::releaseBuffers()
m_swapchain.reset();
}
std::chrono::nanoseconds DrmCursorQPainterLayer::queryRenderTime() const
{
return m_renderTime;
}
DrmVirtualQPainterLayer::DrmVirtualQPainterLayer(DrmVirtualOutput *output)
: m_output(output)
{
@ -159,6 +173,7 @@ std::optional<OutputLayerBeginFrameInfo> DrmVirtualQPainterLayer::beginFrame()
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();
return OutputLayerBeginFrameInfo{
.renderTarget = RenderTarget(&m_image),
.repaint = QRegion(),
@ -167,6 +182,7 @@ std::optional<OutputLayerBeginFrameInfo> DrmVirtualQPainterLayer::beginFrame()
bool DrmVirtualQPainterLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_renderTime = std::chrono::steady_clock::now() - m_renderStart;
m_currentDamage = damagedRegion;
return true;
}
@ -179,4 +195,9 @@ QRegion DrmVirtualQPainterLayer::currentDamage() const
void DrmVirtualQPainterLayer::releaseBuffers()
{
}
std::chrono::nanoseconds DrmVirtualQPainterLayer::queryRenderTime() const
{
return m_renderTime;
}
}

@ -34,6 +34,7 @@ public:
QRegion currentDamage() const override;
void releaseBuffers() override;
quint32 format() const override;
std::chrono::nanoseconds queryRenderTime() const override;
private:
bool doesSwapchainFit() const;
@ -42,6 +43,8 @@ private:
std::shared_ptr<QPainterSwapchainSlot> m_currentBuffer;
std::shared_ptr<DrmFramebuffer> m_currentFramebuffer;
DamageJournal m_damageJournal;
std::chrono::steady_clock::time_point m_renderStart;
std::chrono::nanoseconds m_renderTime;
};
class DrmCursorQPainterLayer : public DrmOverlayLayer
@ -56,11 +59,14 @@ public:
std::shared_ptr<DrmFramebuffer> currentBuffer() const override;
QRegion currentDamage() const override;
void releaseBuffers() override;
std::chrono::nanoseconds queryRenderTime() const override;
private:
std::shared_ptr<QPainterSwapchain> m_swapchain;
std::shared_ptr<QPainterSwapchainSlot> m_currentBuffer;
std::shared_ptr<DrmFramebuffer> m_currentFramebuffer;
std::chrono::steady_clock::time_point m_renderStart;
std::chrono::nanoseconds m_renderTime;
};
class DrmVirtualQPainterLayer : public DrmOutputLayer
@ -73,10 +79,13 @@ public:
QRegion currentDamage() const override;
void releaseBuffers() override;
std::chrono::nanoseconds queryRenderTime() const override;
private:
QImage m_image;
QRegion m_currentDamage;
DrmVirtualOutput *const m_output;
std::chrono::steady_clock::time_point m_renderStart;
std::chrono::nanoseconds m_renderTime;
};
}

@ -12,6 +12,7 @@
#include "drm_logging.h"
#include "drm_virtual_output.h"
#include "platformsupport/scenes/opengl/eglswapchain.h"
#include "platformsupport/scenes/opengl/glrendertimequery.h"
#include "scene/surfaceitem_wayland.h"
#include "wayland/surface_interface.h"
@ -30,6 +31,8 @@ VirtualEglGbmLayer::VirtualEglGbmLayer(EglGbmBackend *eglBackend, DrmVirtualOutp
{
}
VirtualEglGbmLayer::~VirtualEglGbmLayer() = default;
std::optional<OutputLayerBeginFrameInfo> VirtualEglGbmLayer::beginFrame()
{
// gbm surface
@ -68,6 +71,11 @@ std::optional<OutputLayerBeginFrameInfo> VirtualEglGbmLayer::beginFrame()
m_scanoutBuffer = nullptr;
}
if (!m_query) {
m_query = std::make_unique<GLRenderTimeQuery>();
}
m_query->begin();
const QRegion repair = m_damageJournal.accumulate(slot->age(), infiniteRegion());
return OutputLayerBeginFrameInfo{
.renderTarget = RenderTarget(slot->framebuffer()),
@ -77,6 +85,7 @@ std::optional<OutputLayerBeginFrameInfo> VirtualEglGbmLayer::beginFrame()
bool VirtualEglGbmLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_query->end();
glFlush();
m_currentDamage = damagedRegion;
m_damageJournal.add(damagedRegion);
@ -181,4 +190,10 @@ quint32 VirtualEglGbmLayer::format() const
}
return m_gbmSwapchain->format();
}
std::chrono::nanoseconds VirtualEglGbmLayer::queryRenderTime() const
{
m_eglBackend->makeCurrent();
return m_query->result();
}
}

@ -30,11 +30,13 @@ class GraphicsBuffer;
class GLTexture;
class EglGbmBackend;
class DrmVirtualOutput;
class GLRenderTimeQuery;
class VirtualEglGbmLayer : public DrmOutputLayer
{
public:
VirtualEglGbmLayer(EglGbmBackend *eglBackend, DrmVirtualOutput *output);
~VirtualEglGbmLayer() override;
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
@ -44,6 +46,7 @@ public:
std::shared_ptr<GLTexture> texture() const override;
void releaseBuffers() override;
quint32 format() const override;
std::chrono::nanoseconds queryRenderTime() const override;
private:
std::shared_ptr<EglSwapchain> createGbmSwapchain() const;
@ -57,6 +60,7 @@ private:
std::shared_ptr<EglSwapchain> m_gbmSwapchain;
std::shared_ptr<EglSwapchain> m_oldGbmSwapchain;
std::shared_ptr<EglSwapchainSlot> m_currentSlot;
std::unique_ptr<GLRenderTimeQuery> m_query;
DrmVirtualOutput *const m_output;
EglGbmBackend *const m_eglBackend;

@ -11,6 +11,7 @@
#include "libkwineffects/kwinglutils.h"
#include "platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.h"
#include "platformsupport/scenes/opengl/eglswapchain.h"
#include "platformsupport/scenes/opengl/glrendertimequery.h"
#include "utils/softwarevsyncmonitor.h"
#include "virtual_backend.h"
#include "virtual_logging.h"
@ -49,6 +50,11 @@ std::optional<OutputLayerBeginFrameInfo> VirtualEglLayer::beginFrame()
return std::nullopt;
}
if (!m_query) {
m_query = std::make_unique<GLRenderTimeQuery>();
}
m_query->begin();
return OutputLayerBeginFrameInfo{
.renderTarget = RenderTarget(m_current->framebuffer()),
.repaint = infiniteRegion(),
@ -57,6 +63,7 @@ std::optional<OutputLayerBeginFrameInfo> VirtualEglLayer::beginFrame()
bool VirtualEglLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_query->end();
glFlush(); // flush pending rendering commands.
Q_EMIT m_output->outputChange(damagedRegion);
return true;
@ -67,6 +74,16 @@ quint32 VirtualEglLayer::format() const
return DRM_FORMAT_XRGB8888;
}
std::chrono::nanoseconds VirtualEglLayer::queryRenderTime() const
{
if (m_query) {
m_backend->makeCurrent();
return m_query->result();
} else {
return std::chrono::nanoseconds::zero();
}
}
VirtualEglBackend::VirtualEglBackend(VirtualBackend *b)
: AbstractEglBackend()
, m_backend(b)

@ -10,6 +10,7 @@
#include "core/outputlayer.h"
#include "platformsupport/scenes/opengl/abstract_egl_backend.h"
#include <chrono>
#include <memory>
namespace KWin
@ -22,6 +23,7 @@ class VirtualBackend;
class GLFramebuffer;
class GLTexture;
class VirtualEglBackend;
class GLRenderTimeQuery;
class VirtualEglLayer : public OutputLayer
{
@ -33,12 +35,14 @@ public:
std::shared_ptr<GLTexture> texture() const;
quint32 format() const override;
std::chrono::nanoseconds queryRenderTime() const override;
private:
VirtualEglBackend *const m_backend;
Output *m_output;
std::shared_ptr<EglSwapchain> m_swapchain;
std::shared_ptr<EglSwapchainSlot> m_current;
std::unique_ptr<GLRenderTimeQuery> m_query;
};
/**

@ -9,6 +9,9 @@
#include "virtual_output.h"
#include "virtual_backend.h"
#include "composite.h"
#include "core/outputlayer.h"
#include "core/renderbackend.h"
#include "core/renderloop_p.h"
#include "utils/softwarevsyncmonitor.h"
@ -71,7 +74,7 @@ void VirtualOutput::updateEnabled(bool enabled)
void VirtualOutput::vblank(std::chrono::nanoseconds timestamp)
{
RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(m_renderLoop.get());
renderLoopPrivate->notifyFrameCompleted(timestamp);
renderLoopPrivate->notifyFrameCompleted(timestamp, Compositor::self()->backend()->primaryLayer(this)->queryRenderTime());
}
}

@ -41,6 +41,7 @@ std::optional<OutputLayerBeginFrameInfo> VirtualQPainterLayer::beginFrame()
return std::nullopt;
}
m_renderStart = std::chrono::steady_clock::now();
return OutputLayerBeginFrameInfo{
.renderTarget = RenderTarget(m_current->view()->image()),
.repaint = m_output->rect(),
@ -49,6 +50,7 @@ std::optional<OutputLayerBeginFrameInfo> VirtualQPainterLayer::beginFrame()
bool VirtualQPainterLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_renderTime = std::chrono::steady_clock::now() - m_renderStart;
return true;
}
@ -62,6 +64,11 @@ quint32 VirtualQPainterLayer::format() const
return DRM_FORMAT_XRGB8888;
}
std::chrono::nanoseconds VirtualQPainterLayer::queryRenderTime() const
{
return m_renderTime;
}
VirtualQPainterBackend::VirtualQPainterBackend(VirtualBackend *backend)
: m_allocator(std::make_unique<ShmGraphicsBufferAllocator>())
{

@ -14,6 +14,7 @@
#include <QMap>
#include <QObject>
#include <QVector>
#include <chrono>
#include <memory>
namespace KWin
@ -35,12 +36,15 @@ public:
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
QImage *image();
quint32 format() const override;
std::chrono::nanoseconds queryRenderTime() const override;
private:
Output *const m_output;
VirtualQPainterBackend *const m_backend;
std::unique_ptr<QPainterSwapchain> m_swapchain;
std::shared_ptr<QPainterSwapchainSlot> m_current;
std::chrono::steady_clock::time_point m_renderStart;
std::chrono::nanoseconds m_renderTime = std::chrono::nanoseconds::zero();
};
class VirtualQPainterBackend : public QPainterBackend

@ -13,6 +13,7 @@
#include "libkwineffects/kwinglutils.h"
#include "platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.h"
#include "platformsupport/scenes/opengl/eglswapchain.h"
#include "platformsupport/scenes/opengl/glrendertimequery.h"
#include "wayland_backend.h"
#include "wayland_display.h"
#include "wayland_logging.h"
@ -89,7 +90,10 @@ std::optional<OutputLayerBeginFrameInfo> WaylandEglPrimaryLayer::beginFrame()
if (m_backend->supportsBufferAge()) {
repair = m_damageJournal.accumulate(m_buffer->age(), infiniteRegion());
}
if (!m_query) {
m_query = std::make_unique<GLRenderTimeQuery>();
}
m_query->begin();
return OutputLayerBeginFrameInfo{
.renderTarget = RenderTarget(m_buffer->framebuffer()),
.repaint = repair,
@ -98,6 +102,7 @@ std::optional<OutputLayerBeginFrameInfo> WaylandEglPrimaryLayer::beginFrame()
bool WaylandEglPrimaryLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_query->end();
// Flush rendering commands to the dmabuf.
glFlush();
@ -120,6 +125,17 @@ void WaylandEglPrimaryLayer::present()
m_swapchain->release(m_buffer);
}
quint32 WaylandEglPrimaryLayer::format() const
{
return m_buffer->buffer()->dmabufAttributes()->format;
}
std::chrono::nanoseconds WaylandEglPrimaryLayer::queryRenderTime() const
{
m_backend->makeCurrent();
return m_query->result();
}
WaylandEglCursorLayer::WaylandEglCursorLayer(WaylandOutput *output, WaylandEglBackend *backend)
: m_output(output)
, m_backend(backend)
@ -160,6 +176,10 @@ std::optional<OutputLayerBeginFrameInfo> WaylandEglCursorLayer::beginFrame()
}
m_buffer = m_swapchain->acquire();
if (!m_query) {
m_query = std::make_unique<GLRenderTimeQuery>();
}
m_query->begin();
return OutputLayerBeginFrameInfo{
.renderTarget = RenderTarget(m_buffer->framebuffer()),
.repaint = infiniteRegion(),
@ -168,6 +188,7 @@ std::optional<OutputLayerBeginFrameInfo> WaylandEglCursorLayer::beginFrame()
bool WaylandEglCursorLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_query->end();
// Flush rendering commands to the dmabuf.
glFlush();
@ -185,9 +206,10 @@ quint32 WaylandEglCursorLayer::format() const
return m_buffer->buffer()->dmabufAttributes()->format;
}
quint32 WaylandEglPrimaryLayer::format() const
std::chrono::nanoseconds WaylandEglCursorLayer::queryRenderTime() const
{
return m_buffer->buffer()->dmabufAttributes()->format;
m_backend->makeCurrent();
return m_query->result();
}
WaylandEglBackend::WaylandEglBackend(WaylandBackend *b)

@ -21,6 +21,7 @@ class EglSwapchainSlot;
class EglSwapchain;
class GLFramebuffer;
class GraphicsBufferAllocator;
class GLRenderTimeQuery;
namespace Wayland
{
@ -41,12 +42,14 @@ public:
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
quint32 format() const override;
std::chrono::nanoseconds queryRenderTime() const override;
private:
WaylandOutput *m_waylandOutput;
DamageJournal m_damageJournal;
std::shared_ptr<EglSwapchain> m_swapchain;
std::shared_ptr<EglSwapchainSlot> m_buffer;
std::unique_ptr<GLRenderTimeQuery> m_query;
WaylandEglBackend *const m_backend;
friend class WaylandEglBackend;
@ -63,12 +66,14 @@ public:
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
quint32 format() const override;
std::chrono::nanoseconds queryRenderTime() const override;
private:
WaylandOutput *m_output;
WaylandEglBackend *m_backend;
std::shared_ptr<EglSwapchain> m_swapchain;
std::shared_ptr<EglSwapchainSlot> m_buffer;
std::unique_ptr<GLRenderTimeQuery> m_query;
};
/**

@ -136,7 +136,8 @@ WaylandOutput::WaylandOutput(const QString &name, WaylandBackend *backend)
connect(m_surface.get(), &KWayland::Client::Surface::frameRendered, this, [this]() {
RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(renderLoop());
renderLoopPrivate->notifyFrameCompleted(std::chrono::steady_clock::now().time_since_epoch());
const auto primary = Compositor::self()->backend()->primaryLayer(this);
renderLoopPrivate->notifyFrameCompleted(std::chrono::steady_clock::now().time_since_epoch(), primary ? primary->queryRenderTime() : std::chrono::nanoseconds::zero());
});
updateWindowTitle();

@ -66,6 +66,7 @@ std::optional<OutputLayerBeginFrameInfo> WaylandQPainterPrimaryLayer::beginFrame
return std::nullopt;
}
m_renderStart = std::chrono::steady_clock::now();
return OutputLayerBeginFrameInfo{
.renderTarget = RenderTarget(m_back->view()->image()),
.repaint = accumulateDamage(m_back->age()),
@ -74,6 +75,7 @@ std::optional<OutputLayerBeginFrameInfo> WaylandQPainterPrimaryLayer::beginFrame
bool WaylandQPainterPrimaryLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_renderTime = std::chrono::steady_clock::now() - m_renderStart;
m_damageJournal.add(damagedRegion);
return true;
}
@ -83,6 +85,11 @@ quint32 WaylandQPainterPrimaryLayer::format() const
return DRM_FORMAT_RGBA8888;
}
std::chrono::nanoseconds WaylandQPainterPrimaryLayer::queryRenderTime() const
{
return m_renderTime;
}
WaylandQPainterCursorLayer::WaylandQPainterCursorLayer(WaylandOutput *output, WaylandQPainterBackend *backend)
: m_output(output)
, m_backend(backend)
@ -106,6 +113,7 @@ std::optional<OutputLayerBeginFrameInfo> WaylandQPainterCursorLayer::beginFrame(
return std::nullopt;
}
m_renderStart = std::chrono::steady_clock::now();
return OutputLayerBeginFrameInfo{
.renderTarget = RenderTarget(m_back->view()->image()),
.repaint = infiniteRegion(),
@ -114,6 +122,7 @@ std::optional<OutputLayerBeginFrameInfo> WaylandQPainterCursorLayer::beginFrame(
bool WaylandQPainterCursorLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_renderTime = std::chrono::steady_clock::now() - m_renderStart;
wl_buffer *buffer = m_output->backend()->importBuffer(m_back->buffer());
Q_ASSERT(buffer);
@ -127,6 +136,11 @@ quint32 WaylandQPainterCursorLayer::format() const
return DRM_FORMAT_RGBA8888;
}
std::chrono::nanoseconds WaylandQPainterCursorLayer::queryRenderTime() const
{
return m_renderTime;
}
WaylandQPainterBackend::WaylandQPainterBackend(Wayland::WaylandBackend *b)
: QPainterBackend()
, m_backend(b)

@ -15,6 +15,7 @@
#include <QImage>
#include <QObject>
#include <chrono>
namespace KWin
{
@ -39,6 +40,7 @@ public:
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
quint32 format() const override;
std::chrono::nanoseconds queryRenderTime() const override;
void present();
@ -51,6 +53,8 @@ private:
std::unique_ptr<QPainterSwapchain> m_swapchain;
std::shared_ptr<QPainterSwapchainSlot> m_back;
std::chrono::steady_clock::time_point m_renderStart;
std::chrono::nanoseconds m_renderTime;
friend class WaylandQPainterBackend;
};
@ -66,12 +70,15 @@ public:
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
quint32 format() const override;
std::chrono::nanoseconds queryRenderTime() const override;
private:
WaylandOutput *m_output;
WaylandQPainterBackend *m_backend;
std::unique_ptr<QPainterSwapchain> m_swapchain;
std::shared_ptr<QPainterSwapchainSlot> m_back;
std::chrono::steady_clock::time_point m_renderStart;
std::chrono::nanoseconds m_renderTime;
};
class WaylandQPainterBackend : public QPainterBackend

@ -6,11 +6,14 @@
*/
#include "x11_standalone_egl_backend.h"
#include "composite.h"
#include "core/outputbackend.h"
#include "core/outputlayer.h"
#include "core/overlaywindow.h"
#include "core/renderloop_p.h"
#include "libkwineffects/kwinglplatform.h"
#include "options.h"
#include "platformsupport/scenes/opengl/glrendertimequery.h"
#include "scene/surfaceitem_x11.h"
#include "scene/workspacescene.h"
#include "utils/c_ptr.h"
@ -47,6 +50,11 @@ uint EglLayer::format() const
return DRM_FORMAT_RGBA8888;
}
std::chrono::nanoseconds EglLayer::queryRenderTime() const
{
return m_backend->queryRenderTime();
}
EglBackend::EglBackend(Display *display, X11StandaloneBackend *backend)
: m_backend(backend)
, m_overlayWindow(std::make_unique<OverlayWindowX11>())
@ -322,6 +330,10 @@ OutputLayerBeginFrameInfo EglBackend::beginFrame()
}
eglWaitNative(EGL_CORE_NATIVE_ENGINE);
if (!m_query) {
m_query = std::make_unique<GLRenderTimeQuery>();
}
m_query->begin();
return OutputLayerBeginFrameInfo{
.renderTarget = RenderTarget(m_fbo.get()),
.repaint = repaint,
@ -330,6 +342,7 @@ OutputLayerBeginFrameInfo EglBackend::beginFrame()
void EglBackend::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_query->end();
// Save the damaged region to history
if (supportsBufferAge()) {
m_damageJournal.add(damagedRegion);
@ -389,10 +402,16 @@ 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)
{
RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(m_backend->renderLoop());
renderLoopPrivate->notifyFrameCompleted(timestamp);
renderLoopPrivate->notifyFrameCompleted(timestamp, m_layer->queryRenderTime());
}
EglSurfaceTextureX11::EglSurfaceTextureX11(EglBackend *backend, SurfacePixmapX11 *texture)

@ -23,6 +23,7 @@ class EglPixmapTexturePrivate;
class SoftwareVsyncMonitor;
class X11StandaloneBackend;
class EglBackend;
class GLRenderTimeQuery;
class EglLayer : public OutputLayer
{
@ -32,6 +33,7 @@ public:
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
uint format() const override;
std::chrono::nanoseconds queryRenderTime() const override;
private:
EglBackend *const m_backend;
@ -53,6 +55,7 @@ public:
void present(Output *output) override;
OverlayWindow *overlayWindow() const override;
OutputLayer *primaryLayer(Output *output) override;
std::chrono::nanoseconds queryRenderTime();
protected:
EGLConfig chooseBufferConfig();
@ -72,6 +75,7 @@ private:
int m_bufferAge = 0;
QRegion m_lastRenderedRegion;
std::unique_ptr<EglLayer> m_layer;
std::unique_ptr<GLRenderTimeQuery> m_query;
int m_havePostSubBuffer = false;
bool m_havePlatformBase = false;
};

@ -28,6 +28,7 @@
#include "core/overlaywindow.h"
#include "core/renderloop_p.h"
#include "options.h"
#include "platformsupport/scenes/opengl/glrendertimequery.h"
#include "scene/surfaceitem_x11.h"
#include "scene/workspacescene.h"
#include "utils/xcbutils.h"
@ -93,7 +94,7 @@ bool SwapEventFilter::event(xcb_generic_event_t *event)
const std::chrono::microseconds timestamp((uint64_t(swapEvent->ust_hi) << 32) | swapEvent->ust_lo);
const auto platform = static_cast<X11StandaloneBackend *>(kwinApp()->outputBackend());
RenderLoopPrivate::get(platform->renderLoop())->notifyFrameCompleted(timestamp);
RenderLoopPrivate::get(platform->renderLoop())->notifyFrameCompleted(timestamp, Compositor::self()->backend()->primaryLayer(nullptr)->queryRenderTime());
return true;
}
@ -119,6 +120,11 @@ uint GlxLayer::format() const
return DRM_FORMAT_RGBA8888;
}
std::chrono::nanoseconds GlxLayer::queryRenderTime() const
{
return m_backend->queryRenderTime();
}
GlxBackend::GlxBackend(Display *display, X11StandaloneBackend *backend)
: OpenGLBackend()
, m_overlayWindow(std::make_unique<OverlayWindowX11>())
@ -770,6 +776,9 @@ OutputLayerBeginFrameInfo GlxBackend::beginFrame()
{
QRegion repaint;
makeCurrent();
if (!m_query) {
m_query = std::make_unique<GLRenderTimeQuery>();
}
if (supportsBufferAge()) {
repaint = m_damageJournal.accumulate(m_bufferAge, infiniteRegion());
@ -777,6 +786,10 @@ OutputLayerBeginFrameInfo GlxBackend::beginFrame()
glXWaitX();
if (!m_query) {
m_query = std::make_unique<GLRenderTimeQuery>();
}
m_query->begin();
return OutputLayerBeginFrameInfo{
.renderTarget = RenderTarget(m_fbo.get()),
.repaint = repaint,
@ -785,6 +798,7 @@ OutputLayerBeginFrameInfo GlxBackend::beginFrame()
void GlxBackend::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_query->end();
// Save the damaged region to history
if (supportsBufferAge()) {
m_damageJournal.add(damagedRegion);
@ -792,6 +806,12 @@ 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)
{
// If the GLX_INTEL_swap_event extension is not used for getting presentation feedback,
@ -820,7 +840,7 @@ void GlxBackend::present(Output *output)
void GlxBackend::vblank(std::chrono::nanoseconds timestamp)
{
RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(m_backend->renderLoop());
renderLoopPrivate->notifyFrameCompleted(timestamp);
renderLoopPrivate->notifyFrameCompleted(timestamp, queryRenderTime());
}
bool GlxBackend::makeCurrent()

@ -30,6 +30,7 @@ class GlxPixmapTexturePrivate;
class VsyncMonitor;
class X11StandaloneBackend;
class GlxBackend;
class GLRenderTimeQuery;
// GLX_MESA_swap_interval
using glXSwapIntervalMESA_func = int (*)(unsigned int interval);
@ -66,6 +67,7 @@ public:
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
uint format() const override;
std::chrono::nanoseconds queryRenderTime() const override;
private:
GlxBackend *const m_backend;
@ -84,6 +86,7 @@ public:
std::unique_ptr<SurfaceTexture> createSurfaceTextureX11(SurfacePixmapX11 *pixmap) override;
OutputLayerBeginFrameInfo beginFrame();
void endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion);
std::chrono::nanoseconds queryRenderTime();
void present(Output *output) override;
bool makeCurrent() override;
void doneCurrent() override;
@ -134,6 +137,7 @@ private:
X11StandaloneBackend *m_backend;
std::unique_ptr<VsyncMonitor> m_vsyncMonitor;
std::unique_ptr<GlxLayer> m_layer;
std::unique_ptr<GLRenderTimeQuery> m_query;
friend class GlxPixmapTexture;
};

@ -10,6 +10,7 @@
#include "core/gbmgraphicsbufferallocator.h"
#include "platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.h"
#include "platformsupport/scenes/opengl/eglswapchain.h"
#include "platformsupport/scenes/opengl/glrendertimequery.h"
#include "x11_windowed_backend.h"
#include "x11_windowed_logging.h"
#include "x11_windowed_output.h"
@ -56,6 +57,10 @@ std::optional<OutputLayerBeginFrameInfo> X11WindowedEglPrimaryLayer::beginFrame(
QRegion repaint = m_output->exposedArea() + m_output->rect();
m_output->clearExposedArea();
if (!m_query) {
m_query = std::make_unique<GLRenderTimeQuery>();
}
m_query->begin();
return OutputLayerBeginFrameInfo{
.renderTarget = RenderTarget(m_buffer->framebuffer()),
.repaint = repaint,
@ -64,6 +69,7 @@ std::optional<OutputLayerBeginFrameInfo> X11WindowedEglPrimaryLayer::beginFrame(
bool X11WindowedEglPrimaryLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_query->end();
return true;
}
@ -111,6 +117,12 @@ quint32 X11WindowedEglPrimaryLayer::format() const
return DRM_FORMAT_RGBA8888;
}
std::chrono::nanoseconds X11WindowedEglPrimaryLayer::queryRenderTime() const
{
m_backend->makeCurrent();
return m_query->result();
}
X11WindowedEglCursorLayer::X11WindowedEglCursorLayer(X11WindowedEglBackend *backend, X11WindowedOutput *output)
: m_output(output)
, m_backend(backend)
@ -139,7 +151,10 @@ std::optional<OutputLayerBeginFrameInfo> X11WindowedEglCursorLayer::beginFrame()
}
m_framebuffer = std::make_unique<GLFramebuffer>(m_texture.get());
}
if (!m_query) {
m_query = std::make_unique<GLRenderTimeQuery>();
}
m_query->begin();
return OutputLayerBeginFrameInfo{
.renderTarget = RenderTarget(m_framebuffer.get()),
.repaint = infiniteRegion(),
@ -155,6 +170,7 @@ bool X11WindowedEglCursorLayer::endFrame(const QRegion &renderedRegion, const QR
GLFramebuffer::popFramebuffer();
m_output->cursor()->update(buffer.mirrored(false, true), hotspot());
m_query->end();
return true;
}
@ -164,6 +180,12 @@ quint32 X11WindowedEglCursorLayer::format() const
return DRM_FORMAT_RGBA8888;
}
std::chrono::nanoseconds X11WindowedEglCursorLayer::queryRenderTime() const
{
m_backend->makeCurrent();
return m_query->result();
}
X11WindowedEglBackend::X11WindowedEglBackend(X11WindowedBackend *backend)
: m_allocator(std::make_unique<GbmGraphicsBufferAllocator>(backend->gbmDevice()))
, m_backend(backend)

@ -21,6 +21,7 @@ class GraphicsBufferAllocator;
class X11WindowedBackend;
class X11WindowedOutput;
class X11WindowedEglBackend;
class GLRenderTimeQuery;
class X11WindowedEglPrimaryLayer : public OutputLayer
{
@ -31,6 +32,7 @@ public:
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
quint32 format() const override;
std::chrono::nanoseconds queryRenderTime() const override;
std::shared_ptr<GLTexture> texture() const;
void present();
@ -38,6 +40,7 @@ public:
private:
std::shared_ptr<EglSwapchain> m_swapchain;
std::shared_ptr<EglSwapchainSlot> m_buffer;
std::unique_ptr<GLRenderTimeQuery> m_query;
X11WindowedOutput *const m_output;
X11WindowedEglBackend *const m_backend;
};
@ -53,12 +56,14 @@ public:
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
quint32 format() const override;
std::chrono::nanoseconds queryRenderTime() const override;
private:
X11WindowedOutput *const m_output;
X11WindowedEglBackend *const m_backend;
std::unique_ptr<GLFramebuffer> m_framebuffer;
std::unique_ptr<GLTexture> m_texture;
std::unique_ptr<GLRenderTimeQuery> m_query;
};
/**

@ -311,7 +311,7 @@ void X11WindowedOutput::resize(const QSize &pixelSize)
void X11WindowedOutput::handlePresentCompleteNotify(xcb_present_complete_notify_event_t *event)
{
std::chrono::microseconds timestamp(event->ust);
RenderLoopPrivate::get(m_renderLoop.get())->notifyFrameCompleted(timestamp);
RenderLoopPrivate::get(m_renderLoop.get())->notifyFrameCompleted(timestamp, Compositor::self()->backend()->primaryLayer(this)->queryRenderTime());
}
void X11WindowedOutput::handlePresentIdleNotify(xcb_present_idle_notify_event_t *event)

@ -47,6 +47,7 @@ std::optional<OutputLayerBeginFrameInfo> X11WindowedQPainterPrimaryLayer::beginF
QRegion repaint = m_output->exposedArea() + m_output->rect();
m_output->clearExposedArea();
m_renderStart = std::chrono::steady_clock::now();
return OutputLayerBeginFrameInfo{
.renderTarget = RenderTarget(m_current->view()->image()),
.repaint = repaint,
@ -55,6 +56,7 @@ std::optional<OutputLayerBeginFrameInfo> X11WindowedQPainterPrimaryLayer::beginF
bool X11WindowedQPainterPrimaryLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_renderTime = std::chrono::steady_clock::now() - m_renderStart;
return true;
}
@ -93,6 +95,11 @@ quint32 X11WindowedQPainterPrimaryLayer::format() const
return m_current->buffer()->shmAttributes()->format;
}
std::chrono::nanoseconds X11WindowedQPainterPrimaryLayer::queryRenderTime() const
{
return m_renderTime;
}
X11WindowedQPainterCursorLayer::X11WindowedQPainterCursorLayer(X11WindowedOutput *output)
: m_output(output)
{
@ -106,6 +113,7 @@ std::optional<OutputLayerBeginFrameInfo> X11WindowedQPainterCursorLayer::beginFr
m_buffer = QImage(bufferSize, QImage::Format_ARGB32_Premultiplied);
}
m_renderStart = std::chrono::steady_clock::now();
return OutputLayerBeginFrameInfo{
.renderTarget = RenderTarget(&m_buffer),
.repaint = infiniteRegion(),
@ -117,8 +125,14 @@ quint32 X11WindowedQPainterCursorLayer::format() const
return DRM_FORMAT_ARGB8888;
}
std::chrono::nanoseconds X11WindowedQPainterCursorLayer::queryRenderTime() const
{
return m_renderTime;
}
bool X11WindowedQPainterCursorLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_renderTime = std::chrono::steady_clock::now() - m_renderStart;
m_output->cursor()->update(m_buffer, hotspot());
return true;
}

@ -15,6 +15,7 @@
#include <QObject>
#include <QVector>
#include <chrono>
#include <memory>
namespace KWin
@ -36,6 +37,7 @@ public:
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
quint32 format() const override;
std::chrono::nanoseconds queryRenderTime() const override;
void present();
@ -44,6 +46,8 @@ private:
X11WindowedQPainterBackend *const m_backend;
std::unique_ptr<QPainterSwapchain> m_swapchain;
std::shared_ptr<QPainterSwapchainSlot> m_current;
std::chrono::steady_clock::time_point m_renderStart;
std::chrono::nanoseconds m_renderTime;
};
class X11WindowedQPainterCursorLayer : public OutputLayer
@ -56,10 +60,13 @@ public:
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
quint32 format() const override;
std::chrono::nanoseconds queryRenderTime() const override;
private:
QImage m_buffer;
X11WindowedOutput *m_output;
std::chrono::steady_clock::time_point m_renderStart;
std::chrono::nanoseconds m_renderTime;
};
class X11WindowedQPainterBackend : public QPainterBackend

@ -662,7 +662,6 @@ void Compositor::composite(RenderLoop *renderLoop)
}
postPaintPass(superLayer);
renderLoop->endFrame();
m_backend->present(output);

@ -11,6 +11,7 @@
#include <QObject>
#include <QRegion>
#include <chrono>
#include <optional>
namespace KWin
@ -57,6 +58,11 @@ public:
*/
virtual bool scanout(SurfaceItem *surfaceItem);
/**
* 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;
private:
QRegion m_repaints;
QPointF m_hotspot;

@ -13,18 +13,12 @@ RenderJournal::RenderJournal()
{
}
void RenderJournal::beginFrame()
void RenderJournal::add(std::chrono::nanoseconds renderTime)
{
m_timer.start();
}
void RenderJournal::endFrame()
{
std::chrono::nanoseconds duration(m_timer.nsecsElapsed());
if (m_log.count() >= m_size) {
m_log.dequeue();
}
m_log.enqueue(duration);
m_log.enqueue(renderTime);
}
std::chrono::nanoseconds RenderJournal::minimum() const

@ -23,15 +23,7 @@ class KWIN_EXPORT RenderJournal
public:
RenderJournal();
/**
* This function must be called before starting rendering a new frame.
*/
void beginFrame();
/**
* This function must be called after finishing rendering a frame.
*/
void endFrame();
void add(std::chrono::nanoseconds renderTime);
/**
* Returns the maximum estimated amount of time that it takes to render a single frame.
@ -49,7 +41,6 @@ public:
std::chrono::nanoseconds average() const;
private:
QElapsedTimer m_timer;
QQueue<std::chrono::nanoseconds> m_log;
int m_size = 15;
};

@ -127,7 +127,7 @@ void RenderLoopPrivate::notifyFrameFailed()
}
}
void RenderLoopPrivate::notifyFrameCompleted(std::chrono::nanoseconds timestamp)
void RenderLoopPrivate::notifyFrameCompleted(std::chrono::nanoseconds timestamp, std::chrono::nanoseconds renderTime)
{
Q_ASSERT(pendingFrameCount > 0);
pendingFrameCount--;
@ -142,6 +142,7 @@ void RenderLoopPrivate::notifyFrameCompleted(std::chrono::nanoseconds timestamp)
lastPresentationTimestamp = std::chrono::steady_clock::now().time_since_epoch();
}
renderJournal.add(renderTime);
if (!inhibitCount) {
maybeScheduleRepaint();
}
@ -201,12 +202,6 @@ void RenderLoop::beginFrame()
{
d->pendingRepaint = false;
d->pendingFrameCount++;
d->renderJournal.beginFrame();
}
void RenderLoop::endFrame()
{
d->renderJournal.endFrame();
}
int RenderLoop::refreshRate() const

@ -52,12 +52,6 @@ public:
*/
void beginFrame();
/**
* This function must be called after the Compositor has finished rendering the
* next frame.
*/
void endFrame();
/**
* Returns the refresh rate at which the output is being updated, in millihertz.
*/

@ -30,7 +30,7 @@ public:
void maybeScheduleRepaint();
void notifyFrameFailed();
void notifyFrameCompleted(std::chrono::nanoseconds timestamp);
void notifyFrameCompleted(std::chrono::nanoseconds timestamp, std::chrono::nanoseconds renderTime);
RenderLoop *q;
std::chrono::nanoseconds lastPresentationTimestamp = std::chrono::nanoseconds::zero();

Loading…
Cancel
Save