File indexing completed on 2025-04-20 10:57:33

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2022 Xaver Hugl <xaver.hugl@gmail.com>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #include "drm_dmabuf_feedback.h"
0010 
0011 #include "drm_egl_backend.h"
0012 #include "drm_gpu.h"
0013 #include "egl_dmabuf.h"
0014 #include "wayland/linuxdmabufv1clientbuffer.h"
0015 #include "wayland/surface_interface.h"
0016 
0017 namespace KWin
0018 {
0019 
0020 DmabufFeedback::DmabufFeedback(DrmGpu *gpu, EglGbmBackend *eglBackend)
0021     : m_gpu(gpu)
0022     , m_eglBackend(eglBackend)
0023 {
0024 }
0025 
0026 void DmabufFeedback::renderingSurface()
0027 {
0028     if (m_surface && !m_attemptedThisFrame) {
0029         if (const auto &feedback = m_surface->dmabufFeedbackV1()) {
0030             feedback->setTranches({});
0031         }
0032         m_surface = nullptr;
0033     }
0034     m_attemptedThisFrame = false;
0035 }
0036 
0037 void DmabufFeedback::scanoutSuccessful(KWaylandServer::SurfaceInterface *surface)
0038 {
0039     if (surface != m_surface) {
0040         if (m_surface && m_surface->dmabufFeedbackV1()) {
0041             m_surface->dmabufFeedbackV1()->setTranches({});
0042         }
0043         m_surface = surface;
0044         m_attemptedFormats = {};
0045     }
0046 }
0047 
0048 void DmabufFeedback::scanoutFailed(KWaylandServer::SurfaceInterface *surface, const QMap<uint32_t, QVector<uint64_t>> &formats)
0049 {
0050     m_attemptedThisFrame = true;
0051     if (surface != m_surface) {
0052         m_attemptedFormats = {};
0053         if (m_surface && m_surface->dmabufFeedbackV1()) {
0054             m_surface->dmabufFeedbackV1()->setTranches({});
0055         }
0056         m_surface = surface;
0057     }
0058     if (const auto &feedback = m_surface->dmabufFeedbackV1()) {
0059         const auto buffer = qobject_cast<KWaylandServer::LinuxDmaBufV1ClientBuffer *>(surface->buffer());
0060         Q_ASSERT(buffer);
0061         const DmaBufAttributes &dmabufAttrs = buffer->attributes();
0062         if (!m_attemptedFormats[dmabufAttrs.format].contains(dmabufAttrs.modifier)) {
0063             m_attemptedFormats[dmabufAttrs.format] << dmabufAttrs.modifier;
0064             QVector<KWaylandServer::LinuxDmaBufV1Feedback::Tranche> scanoutTranches;
0065             const auto tranches = m_eglBackend->dmabuf()->tranches();
0066             for (const auto &tranche : tranches) {
0067                 KWaylandServer::LinuxDmaBufV1Feedback::Tranche scanoutTranche;
0068                 for (auto it = tranche.formatTable.constBegin(); it != tranche.formatTable.constEnd(); it++) {
0069                     const uint32_t format = it.key();
0070                     const auto trancheModifiers = it.value();
0071                     const auto drmModifiers = formats[format];
0072                     for (const auto &mod : trancheModifiers) {
0073                         if (drmModifiers.contains(mod) && !m_attemptedFormats[format].contains(mod)) {
0074                             scanoutTranche.formatTable[format] << mod;
0075                         }
0076                     }
0077                 }
0078                 if (!scanoutTranche.formatTable.isEmpty()) {
0079                     scanoutTranche.device = m_gpu->deviceId();
0080                     scanoutTranche.flags = KWaylandServer::LinuxDmaBufV1Feedback::TrancheFlag::Scanout;
0081                     scanoutTranches << scanoutTranche;
0082                 }
0083             }
0084             feedback->setTranches(scanoutTranches);
0085         }
0086     }
0087 }
0088 
0089 }