backends: move render time queries into OutputFrame

This way, multiple OutputFrames can be pending at the same time, without
interfering in each other's render time queries
This commit is contained in:
Xaver Hugl 2024-02-29 17:29:26 +01:00
parent 4470e82baa
commit 219f110093
41 changed files with 239 additions and 299 deletions

View file

@ -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<OutputFrame>(output->renderLoop())));
const auto frame = std::make_shared<OutputFrame>(output->renderLoop());
layer->endFrame(infiniteRegion(), infiniteRegion(), frame.get());
QVERIFY(output->present(frame));
gpu.reset();
verifyCleanup(mockGpu.get());

View file

@ -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();
}

View file

@ -57,9 +57,9 @@ std::optional<OutputLayerBeginFrameInfo> 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();

View file

@ -28,13 +28,12 @@ public:
explicit EglGbmLayer(EglGbmBackend *eglBackend, DrmPipeline *pipeline, DrmPlane::TypeIndex type);
std::optional<OutputLayerBeginFrameInfo> 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<DrmFramebuffer> currentBuffer() const override;
std::shared_ptr<GLTexture> texture() const override;
ColorDescription colorDescription() const;
void releaseBuffers() override;
std::chrono::nanoseconds queryRenderTime() const override;
DrmDevice *scanoutDevice() const override;
QHash<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;
std::optional<QSize> fixedSize() const override;

View file

@ -120,6 +120,8 @@ std::optional<OutputLayerBeginFrameInfo> EglGbmLayerSurface::startRendering(cons
}
const QRegion repaint = bufferAgeEnabled ? m_surface->damageJournal.accumulate(slot->age(), infiniteRegion()) : infiniteRegion();
m_surface->compositingTimeQuery = std::make_unique<GLRenderTimeQuery>(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<OutputLayerBeginFrameInfo> 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<OutputLayerBeginFrameInfo> 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<OutputLayerBeginFrameInfo> 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::Surface> EglGbmLayerSurface::createSurface(c
if (!ret->importGbmSwapchain) {
return nullptr;
}
ret->importTimeQuery = std::make_unique<GLRenderTimeQuery>();
}
ret->timeQuery = std::make_unique<GLRenderTimeQuery>();
if (!doRenderTestBuffer(ret.get())) {
return nullptr;
}
@ -532,7 +512,7 @@ std::shared_ptr<DrmFramebuffer> 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<DrmFramebuffer> EglGbmLayerSurface::doRenderTestBuffer(Surface *
}
}
std::shared_ptr<DrmFramebuffer> EglGbmLayerSurface::importBuffer(Surface *surface, EglSwapchainSlot *slot, FileDescriptor &&readFence) const
std::shared_ptr<DrmFramebuffer> 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<DrmFramebuffer> EglGbmLayerSurface::importBuffer(Surface *surfac
}
}
std::shared_ptr<DrmFramebuffer> EglGbmLayerSurface::importWithEgl(Surface *surface, GraphicsBuffer *sourceBuffer, FileDescriptor &&readFence) const
std::shared_ptr<DrmFramebuffer> EglGbmLayerSurface::importWithEgl(Surface *surface, GraphicsBuffer *sourceBuffer, FileDescriptor &&readFence, OutputFrame *frame) const
{
Q_ASSERT(surface->importGbmSwapchain);
@ -569,7 +549,11 @@ std::shared_ptr<DrmFramebuffer> EglGbmLayerSurface::importWithEgl(Surface *surfa
if (!surface->importContext->makeCurrent()) {
return nullptr;
}
surface->importTimeQuery->begin();
std::unique_ptr<GLRenderTimeQuery> renderTime;
if (frame) {
renderTime = std::make_unique<GLRenderTimeQuery>(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<DrmFramebuffer> 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<DrmFramebuffer> EglGbmLayerSurface::importWithCpu(Surface *surface, EglSwapchainSlot *source) const
std::shared_ptr<DrmFramebuffer> EglGbmLayerSurface::importWithCpu(Surface *surface, EglSwapchainSlot *source, OutputFrame *frame) const
{
std::unique_ptr<CpuRenderTimeQuery> copyTime;
if (frame) {
copyTime = std::make_unique<CpuRenderTimeQuery>();
}
Q_ASSERT(surface->importDumbSwapchain);
const auto slot = surface->importDumbSwapchain->acquire();
if (!slot) {
@ -651,6 +642,10 @@ std::shared_ptr<DrmFramebuffer> 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;
}
}

View file

@ -57,8 +57,7 @@ public:
~EglGbmLayerSurface();
std::optional<OutputLayerBeginFrameInfo> startRendering(const QSize &bufferSize, OutputTransform transformation, const QHash<uint32_t, QList<uint64_t>> &formats, const ColorDescription &colorDescription, const QVector3D &channelFactors, const std::shared_ptr<IccProfile> &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<uint32_t, QList<uint64_t>> &formats) const;
std::shared_ptr<GLTexture> texture() const;
@ -105,11 +104,7 @@ private:
std::unique_ptr<IccShader> iccShader;
std::shared_ptr<IccProfile> iccProfile;
// for render timing
std::unique_ptr<GLRenderTimeQuery> timeQuery;
std::unique_ptr<GLRenderTimeQuery> importTimeQuery;
std::chrono::steady_clock::time_point renderStart;
std::chrono::steady_clock::time_point renderEnd;
std::unique_ptr<GLRenderTimeQuery> compositingTimeQuery;
};
bool checkSurface(const QSize &size, const QHash<uint32_t, QList<uint64_t>> &formats);
bool doesSurfaceFit(Surface *surface, const QSize &size, const QHash<uint32_t, QList<uint64_t>> &formats) const;
@ -118,9 +113,9 @@ private:
std::shared_ptr<EglSwapchain> createGbmSwapchain(DrmGpu *gpu, EglContext *context, const QSize &size, uint32_t format, const QList<uint64_t> &modifiers, MultiGpuImportMode importMode, BufferTarget bufferTarget) const;
std::shared_ptr<DrmFramebuffer> doRenderTestBuffer(Surface *surface) const;
std::shared_ptr<DrmFramebuffer> importBuffer(Surface *surface, EglSwapchainSlot *source, FileDescriptor &&readFence) const;
std::shared_ptr<DrmFramebuffer> importWithEgl(Surface *surface, GraphicsBuffer *sourceBuffer, FileDescriptor &&readFence) const;
std::shared_ptr<DrmFramebuffer> importWithCpu(Surface *surface, EglSwapchainSlot *source) const;
std::shared_ptr<DrmFramebuffer> importBuffer(Surface *surface, EglSwapchainSlot *source, FileDescriptor &&readFence, OutputFrame *frame) const;
std::shared_ptr<DrmFramebuffer> importWithEgl(Surface *surface, GraphicsBuffer *sourceBuffer, FileDescriptor &&readFence, OutputFrame *frame) const;
std::shared_ptr<DrmFramebuffer> importWithCpu(Surface *surface, EglSwapchainSlot *source, OutputFrame *frame) const;
std::unique_ptr<Surface> m_surface;
std::unique_ptr<Surface> m_oldSurface;

View file

@ -38,7 +38,7 @@ std::optional<OutputLayerBeginFrameInfo> DrmQPainterLayer::doBeginFrame()
return std::nullopt;
}
m_renderStart = std::chrono::steady_clock::now();
m_renderTime = std::make_unique<CpuRenderTimeQuery>();
const QRegion repaint = m_damageJournal.accumulate(m_currentBuffer->age(), infiniteRegion());
return OutputLayerBeginFrameInfo{
.renderTarget = RenderTarget(m_currentBuffer->view()->image()),
@ -46,9 +46,12 @@ std::optional<OutputLayerBeginFrameInfo> 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<OutputLayerBeginFrameInfo> 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<CpuRenderTimeQuery>();
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?

View file

@ -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<OutputLayerBeginFrameInfo> 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<DrmFramebuffer> currentBuffer() const override;
void releaseBuffers() override;
std::chrono::nanoseconds queryRenderTime() const override;
DrmDevice *scanoutDevice() const override;
QHash<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;
@ -43,8 +43,7 @@ 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;
std::unique_ptr<CpuRenderTimeQuery> m_renderTime;
};
class DrmVirtualQPainterLayer : public DrmOutputLayer
@ -53,16 +52,14 @@ public:
explicit DrmVirtualQPainterLayer(DrmVirtualOutput *output);
std::optional<OutputLayerBeginFrameInfo> 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<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;
private:
QImage m_image;
std::chrono::steady_clock::time_point m_renderStart;
std::chrono::nanoseconds m_renderTime;
std::unique_ptr<CpuRenderTimeQuery> m_renderTime;
};
}

View file

@ -67,9 +67,7 @@ std::optional<OutputLayerBeginFrameInfo> VirtualEglGbmLayer::doBeginFrame()
m_currentSlot = slot;
if (!m_query) {
m_query = std::make_unique<GLRenderTimeQuery>();
}
m_query = std::make_unique<GLRenderTimeQuery>(m_eglBackend->openglContextRef());
m_query->begin();
const QRegion repair = m_damageJournal.accumulate(slot->age(), infiniteRegion());
@ -79,9 +77,10 @@ std::optional<OutputLayerBeginFrameInfo> 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();

View file

@ -35,11 +35,10 @@ public:
~VirtualEglGbmLayer() override;
std::optional<OutputLayerBeginFrameInfo> 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<GLTexture> texture() const override;
void releaseBuffers() override;
std::chrono::nanoseconds queryRenderTime() const override;
DrmDevice *scanoutDevice() const override;
QHash<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;
const ColorDescription &colorDescription() const;

View file

@ -51,9 +51,7 @@ std::optional<OutputLayerBeginFrameInfo> VirtualEglLayer::doBeginFrame()
return std::nullopt;
}
if (!m_query) {
m_query = std::make_unique<GLRenderTimeQuery>();
}
m_query = std::make_unique<GLRenderTimeQuery>(m_backend->openglContextRef());
m_query->begin();
return OutputLayerBeginFrameInfo{
@ -62,23 +60,14 @@ std::optional<OutputLayerBeginFrameInfo> 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();

View file

@ -31,10 +31,9 @@ public:
VirtualEglLayer(Output *output, VirtualEglBackend *backend);
std::optional<OutputLayerBeginFrameInfo> 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<GLTexture> texture() const;
std::chrono::nanoseconds queryRenderTime() const override;
DrmDevice *scanoutDevice() const override;
QHash<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;

View file

@ -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"

View file

@ -42,16 +42,17 @@ std::optional<OutputLayerBeginFrameInfo> VirtualQPainterLayer::doBeginFrame()
return std::nullopt;
}
m_renderStart = std::chrono::steady_clock::now();
m_renderTime = std::make_unique<CpuRenderTimeQuery>();
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();

View file

@ -9,6 +9,7 @@
#pragma once
#include "core/outputlayer.h"
#include "core/renderbackend.h"
#include "platformsupport/scenes/qpainter/qpainterbackend.h"
#include <QList>
@ -33,9 +34,8 @@ public:
~VirtualQPainterLayer() override;
std::optional<OutputLayerBeginFrameInfo> 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<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;
@ -43,8 +43,7 @@ private:
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();
std::unique_ptr<CpuRenderTimeQuery> m_renderTime;
};
class VirtualQPainterBackend : public QPainterBackend

View file

@ -92,9 +92,7 @@ std::optional<OutputLayerBeginFrameInfo> WaylandEglPrimaryLayer::doBeginFrame()
}
const QRegion repair = bufferAgeEnabled ? m_damageJournal.accumulate(m_buffer->age(), infiniteRegion()) : infiniteRegion();
if (!m_query) {
m_query = std::make_unique<GLRenderTimeQuery>();
}
m_query = std::make_unique<GLRenderTimeQuery>(m_backend->openglContextRef());
m_query->begin();
return OutputLayerBeginFrameInfo{
.renderTarget = RenderTarget(m_buffer->framebuffer()),
@ -102,9 +100,10 @@ std::optional<OutputLayerBeginFrameInfo> 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<OutputLayerBeginFrameInfo> WaylandEglCursorLayer::doBeginFrame()
return std::nullopt;
}
if (!m_query) {
m_query = std::make_unique<GLRenderTimeQuery>();
}
m_query = std::make_unique<GLRenderTimeQuery>(m_backend->openglContextRef());
m_query->begin();
return OutputLayerBeginFrameInfo{
.renderTarget = RenderTarget(m_buffer->framebuffer()),
@ -214,9 +205,12 @@ std::optional<OutputLayerBeginFrameInfo> 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;
}

View file

@ -43,8 +43,7 @@ public:
void present();
std::optional<OutputLayerBeginFrameInfo> 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<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;
@ -69,8 +68,7 @@ public:
~WaylandEglCursorLayer() override;
std::optional<OutputLayerBeginFrameInfo> 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<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;

View file

@ -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();
});

View file

@ -67,25 +67,21 @@ std::optional<OutputLayerBeginFrameInfo> WaylandQPainterPrimaryLayer::doBeginFra
return std::nullopt;
}
m_renderStart = std::chrono::steady_clock::now();
m_renderTime = std::make_unique<CpuRenderTimeQuery>();
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<OutputLayerBeginFrameInfo> WaylandQPainterCursorLayer::doBeginFram
return std::nullopt;
}
m_renderStart = std::chrono::steady_clock::now();
m_renderTime = std::make_unique<CpuRenderTimeQuery>();
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<WaylandOutput *>(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();

View file

@ -38,8 +38,7 @@ public:
~WaylandQPainterPrimaryLayer() override;
std::optional<OutputLayerBeginFrameInfo> 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<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;
@ -54,8 +53,7 @@ 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;
std::unique_ptr<CpuRenderTimeQuery> m_renderTime;
friend class WaylandQPainterBackend;
};
@ -69,8 +67,7 @@ public:
~WaylandQPainterCursorLayer() override;
std::optional<OutputLayerBeginFrameInfo> 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<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;
@ -78,8 +75,7 @@ private:
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;
std::unique_ptr<CpuRenderTimeQuery> m_renderTime;
};
class WaylandQPainterBackend : public QPainterBackend

View file

@ -41,17 +41,12 @@ std::optional<OutputLayerBeginFrameInfo> 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<GLRenderTimeQuery>();
}
m_query = std::make_unique<GLRenderTimeQuery>(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();
}

View file

@ -36,8 +36,7 @@ public:
EglLayer(EglBackend *backend);
std::optional<OutputLayerBeginFrameInfo> 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<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;
@ -56,12 +55,11 @@ public:
std::unique_ptr<SurfaceTexture> 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<OutputFrame> &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<OutputFrame> m_frame;
QList<QByteArray> m_clientExtensions;
std::unique_ptr<EglContext> m_context;
std::shared_ptr<EglContext> m_context;
::EGLSurface m_surface = EGL_NO_SURFACE;
};

View file

@ -109,17 +109,12 @@ std::optional<OutputLayerBeginFrameInfo> 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<GLRenderTimeQuery>();
}
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<GLRenderTimeQuery>();
}
m_query = std::make_unique<GLRenderTimeQuery>(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<OutputFrame> &frame)
{
m_frame = frame;
@ -729,7 +714,7 @@ void GlxBackend::present(Output *output, const std::shared_ptr<OutputFrame> &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();
}

View file

@ -64,8 +64,7 @@ public:
GlxLayer(GlxBackend *backend);
std::optional<OutputLayerBeginFrameInfo> 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<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;
@ -85,8 +84,7 @@ public:
~GlxBackend() override;
std::unique_ptr<SurfaceTexture> 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<OutputFrame> &frame) override;
bool makeCurrent() override;
void doneCurrent() override;
@ -122,7 +120,7 @@ private:
::Window window;
GLXFBConfig fbconfig;
GLXWindow glxWindow;
std::unique_ptr<GlxContext> m_context;
std::shared_ptr<GlxContext> m_context;
QHash<xcb_visualid_t, FBConfigInfo> m_fbconfigHash;
QHash<xcb_visualid_t, int> m_visualDepthHash;
std::unique_ptr<SwapEventFilter> m_swapEventFilter;

View file

@ -59,9 +59,7 @@ std::optional<OutputLayerBeginFrameInfo> X11WindowedEglPrimaryLayer::doBeginFram
QRegion repaint = m_output->exposedArea() + m_output->rect();
m_output->clearExposedArea();
if (!m_query) {
m_query = std::make_unique<GLRenderTimeQuery>();
}
m_query = std::make_unique<GLRenderTimeQuery>(m_backend->openglContextRef());
m_query->begin();
return OutputLayerBeginFrameInfo{
.renderTarget = RenderTarget(m_buffer->framebuffer()),
@ -69,9 +67,10 @@ std::optional<OutputLayerBeginFrameInfo> 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<GLTexture> 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<OutputLayerBeginFrameInfo> X11WindowedEglCursorLayer::doBeginFrame
m_framebuffer = std::make_unique<GLFramebuffer>(m_texture.get());
}
if (!m_query) {
m_query = std::make_unique<GLRenderTimeQuery>();
m_query = std::make_unique<GLRenderTimeQuery>(m_backend->openglContextRef());
}
m_query->begin();
return OutputLayerBeginFrameInfo{
@ -167,7 +160,7 @@ std::optional<OutputLayerBeginFrameInfo> 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<X11WindowedOutput *>(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;
}

View file

@ -29,8 +29,7 @@ public:
~X11WindowedEglPrimaryLayer() override;
std::optional<OutputLayerBeginFrameInfo> 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<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;
@ -54,8 +53,7 @@ public:
~X11WindowedEglCursorLayer() override;
std::optional<OutputLayerBeginFrameInfo> 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<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;

View file

@ -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();
}

View file

@ -48,16 +48,17 @@ std::optional<OutputLayerBeginFrameInfo> 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<CpuRenderTimeQuery>();
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<OutputLayerBeginFrameInfo> X11WindowedQPainterCursorLayer::doBegin
m_buffer = QImage(bufferSize, QImage::Format_ARGB32_Premultiplied);
}
m_renderStart = std::chrono::steady_clock::now();
m_renderTime = std::make_unique<CpuRenderTimeQuery>();
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;
}

View file

@ -35,8 +35,7 @@ public:
~X11WindowedQPainterPrimaryLayer() override;
std::optional<OutputLayerBeginFrameInfo> 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<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;
@ -47,8 +46,7 @@ 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;
std::unique_ptr<CpuRenderTimeQuery> m_renderTime;
};
class X11WindowedQPainterCursorLayer : public OutputLayer
@ -59,16 +57,14 @@ public:
explicit X11WindowedQPainterCursorLayer(X11WindowedOutput *output);
std::optional<OutputLayerBeginFrameInfo> 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<uint32_t, QList<uint64_t>> 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<CpuRenderTimeQuery> m_renderTime;
};
class X11WindowedQPainterBackend : public QPainterBackend

View file

@ -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 {

View file

@ -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);

View file

@ -108,9 +108,9 @@ std::optional<OutputLayerBeginFrameInfo> 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()

View file

@ -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<OutputLayerBeginFrameInfo> 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<uint32_t, QList<uint64_t>> supportedDrmFormats() const = 0;
@ -101,7 +97,7 @@ public:
protected:
virtual bool doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color);
virtual std::optional<OutputLayerBeginFrameInfo> 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;

View file

@ -10,10 +10,27 @@
#include "syncobjtimeline.h"
#include <drm_fourcc.h>
#include <ranges>
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<PresentationFeedback> &&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<RenderTimeQuery> &&query)
{
m_renderTimeQueries.push_back(std::move(query));
}
RenderBackend::RenderBackend(QObject *parent)
: QObject(parent)
{

View file

@ -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<std::chrono::steady_clock::time_point> 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<PresentationFeedback> &&feedback);
@ -59,6 +83,7 @@ public:
void setDamage(const QRegion &region);
QRegion damage() const;
void addRenderTimeQuery(std::unique_ptr<RenderTimeQuery> &&query);
private:
RenderLoop *const m_loop;
@ -66,6 +91,7 @@ private:
std::optional<ContentType> m_contentType;
PresentationMode m_presentationMode = PresentationMode::VSync;
QRegion m_damage;
std::vector<std::unique_ptr<RenderTimeQuery>> m_renderTimeQueries;
};
/**

View file

@ -12,18 +12,25 @@
namespace KWin
{
GLRenderTimeQuery::GLRenderTimeQuery()
GLRenderTimeQuery::GLRenderTimeQuery(const std::shared_ptr<OpenGlContext> &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);
}

View file

@ -11,15 +11,18 @@
#include <chrono>
#include <epoxy/gl.h>
#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<OpenGlContext> &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<OpenGlContext> m_context;
bool m_hasResult = false;
struct

View file

@ -335,6 +335,11 @@ EglContext *AbstractEglBackend::openglContext() const
{
return m_context.get();
}
std::shared_ptr<EglContext> AbstractEglBackend::openglContextRef() const
{
return m_context;
}
}
#include "moc_abstract_egl_backend.cpp"

View file

@ -35,6 +35,7 @@ public:
EGLConfig config() const;
EglDisplay *eglDisplayObject() const override;
EglContext *openglContext() const override;
std::shared_ptr<EglContext> openglContextRef() const;
bool testImportBuffer(GraphicsBuffer *buffer) override;
QHash<uint32_t, QList<uint64_t>> supportedFormats() const override;

View file

@ -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<EglContext> m_eglContext;

View file

@ -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;