/* KWin - the KDE window manager This file is part of the KDE project. SPDX-FileCopyrightText: 2022 Xaver Hugl SPDX-License-Identifier: GPL-2.0-or-later */ #include "drm_qpainter_layer.h" #include "core/graphicsbufferview.h" #include "drm_buffer.h" #include "drm_gpu.h" #include "drm_logging.h" #include "drm_pipeline.h" #include "drm_virtual_output.h" #include "platformsupport/scenes/qpainter/qpainterswapchain.h" #include #include namespace KWin { DrmQPainterLayer::DrmQPainterLayer(DrmPipeline *pipeline, DrmPlane::TypeIndex type) : DrmPipelineLayer(pipeline, type) { } std::optional DrmQPainterLayer::doBeginFrame() { if (!doesSwapchainFit()) { m_swapchain = std::make_shared(m_pipeline->gpu()->drmDevice()->allocator(), m_pipeline->mode()->size(), DRM_FORMAT_XRGB8888); m_damageJournal = DamageJournal(); } m_currentBuffer = m_swapchain->acquire(); if (!m_currentBuffer) { return std::nullopt; } m_renderTime = std::make_unique(); const QRegion repaint = m_damageJournal.accumulate(m_currentBuffer->age(), infiniteRegion()); return OutputLayerBeginFrameInfo{ .renderTarget = RenderTarget(m_currentBuffer->view()->image()), .repaint = repaint, }; } bool DrmQPainterLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) { 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); if (!m_currentFramebuffer) { qCWarning(KWIN_DRM, "Failed to create dumb framebuffer: %s", strerror(errno)); } return m_currentFramebuffer != nullptr; } bool DrmQPainterLayer::checkTestBuffer() { if (!doesSwapchainFit()) { m_swapchain = std::make_shared(m_pipeline->gpu()->drmDevice()->allocator(), m_pipeline->mode()->size(), DRM_FORMAT_XRGB8888); m_currentBuffer = m_swapchain->acquire(); if (m_currentBuffer) { m_currentFramebuffer = m_pipeline->gpu()->importBuffer(m_currentBuffer->buffer(), FileDescriptor{}); m_swapchain->release(m_currentBuffer); if (!m_currentFramebuffer) { qCWarning(KWIN_DRM, "Failed to create dumb framebuffer: %s", strerror(errno)); } } else { m_currentFramebuffer.reset(); } } return m_currentFramebuffer != nullptr; } bool DrmQPainterLayer::doesSwapchainFit() const { return m_swapchain && m_swapchain->size() == m_pipeline->mode()->size(); } std::shared_ptr DrmQPainterLayer::currentBuffer() const { return m_currentFramebuffer; } void DrmQPainterLayer::releaseBuffers() { m_swapchain.reset(); } DrmDevice *DrmQPainterLayer::scanoutDevice() const { return m_pipeline->gpu()->drmDevice(); } QHash> DrmQPainterLayer::supportedDrmFormats() const { return m_pipeline->formats(m_type); } DrmVirtualQPainterLayer::DrmVirtualQPainterLayer(DrmVirtualOutput *output) : DrmOutputLayer(output) { } std::optional DrmVirtualQPainterLayer::doBeginFrame() { if (m_image.isNull() || m_image.size() != m_output->modeSize()) { m_image = QImage(m_output->modeSize(), QImage::Format_RGB32); } m_renderTime = std::make_unique(); return OutputLayerBeginFrameInfo{ .renderTarget = RenderTarget(&m_image), .repaint = QRegion(), }; } bool DrmVirtualQPainterLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) { m_renderTime->end(); frame->addRenderTimeQuery(std::move(m_renderTime)); return true; } void DrmVirtualQPainterLayer::releaseBuffers() { } DrmDevice *DrmVirtualQPainterLayer::scanoutDevice() const { // TODO make this use GraphicsBuffers too? return nullptr; } QHash> DrmVirtualQPainterLayer::supportedDrmFormats() const { return {{DRM_FORMAT_ARGB8888, QList{DRM_FORMAT_MOD_LINEAR}}}; } }