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:
parent
4470e82baa
commit
219f110093
41 changed files with 239 additions and 299 deletions
|
@ -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());
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 ®ion);
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue