File indexing completed on 2024-06-16 05:05:08

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
0006     SPDX-FileCopyrightText: 2022 Xaver Hugl <xaver.hugl@gmail.com>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 #include "drm_buffer.h"
0011 
0012 #include "core/graphicsbuffer.h"
0013 #include "drm_gpu.h"
0014 
0015 // system
0016 #include <sys/mman.h>
0017 #if defined(Q_OS_LINUX)
0018 #include <linux/dma-buf.h>
0019 #include <linux/sync_file.h>
0020 #endif
0021 // drm
0022 #include <drm_fourcc.h>
0023 #include <sys/ioctl.h>
0024 #include <unistd.h>
0025 #include <xf86drm.h>
0026 #include <xf86drmMode.h>
0027 #ifdef Q_OS_LINUX
0028 #include <linux/dma-buf.h>
0029 #endif
0030 
0031 #ifndef DRM_IOCTL_MODE_CLOSEFB
0032 #define DRM_IOCTL_MODE_CLOSEFB 0xD0
0033 #endif
0034 
0035 namespace KWin
0036 {
0037 
0038 static bool s_envIsSet = false;
0039 static bool s_disableBufferWait = qEnvironmentVariableIntValue("KWIN_DRM_DISABLE_BUFFER_READABILITY_CHECKS", &s_envIsSet) && s_envIsSet;
0040 
0041 DrmFramebuffer::DrmFramebuffer(DrmGpu *gpu, uint32_t fbId, GraphicsBuffer *buffer, FileDescriptor &&readFence)
0042     : m_framebufferId(fbId)
0043     , m_gpu(gpu)
0044     , m_bufferRef(buffer)
0045 {
0046     if (s_disableBufferWait || (m_gpu->isI915() && !s_envIsSet)) {
0047         // buffer readability checks cause frames to be wrongly delayed on some Intel laptops
0048         // See https://gitlab.freedesktop.org/drm/intel/-/issues/9415
0049         m_readable = true;
0050     }
0051     m_syncFd = std::move(readFence);
0052 #ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
0053     if (!m_syncFd.isValid()) {
0054         dma_buf_export_sync_file req{
0055             .flags = DMA_BUF_SYNC_READ,
0056             .fd = -1,
0057         };
0058         if (drmIoctl(buffer->dmabufAttributes()->fd[0].get(), DMA_BUF_IOCTL_EXPORT_SYNC_FILE, &req) == 0) {
0059             m_syncFd = FileDescriptor{req.fd};
0060         }
0061     }
0062 #endif
0063 }
0064 
0065 DrmFramebuffer::~DrmFramebuffer()
0066 {
0067     uint32_t nonConstFb = m_framebufferId;
0068     if (drmIoctl(m_gpu->fd(), DRM_IOCTL_MODE_CLOSEFB, &nonConstFb) != 0) {
0069         drmIoctl(m_gpu->fd(), DRM_IOCTL_MODE_RMFB, &nonConstFb);
0070     }
0071 }
0072 
0073 uint32_t DrmFramebuffer::framebufferId() const
0074 {
0075     return m_framebufferId;
0076 }
0077 
0078 GraphicsBuffer *DrmFramebuffer::buffer() const
0079 {
0080     return *m_bufferRef;
0081 }
0082 
0083 void DrmFramebuffer::releaseBuffer()
0084 {
0085     m_bufferRef = nullptr;
0086 }
0087 
0088 const FileDescriptor &DrmFramebuffer::syncFd() const
0089 {
0090     return m_syncFd;
0091 }
0092 
0093 bool DrmFramebuffer::isReadable()
0094 {
0095     if (m_readable) {
0096         return true;
0097     } else if (m_syncFd.isValid()) {
0098         return m_readable = m_syncFd.isReadable();
0099     } else {
0100         const auto &fds = m_bufferRef->dmabufAttributes()->fd;
0101         return m_readable = std::all_of(fds.begin(), fds.end(), [](const auto &fd) {
0102                    return !fd.isValid() || fd.isReadable();
0103                });
0104     }
0105 }
0106 
0107 void DrmFramebuffer::setDeadline(std::chrono::steady_clock::time_point deadline)
0108 {
0109 #ifdef SYNC_IOC_SET_DEADLINE
0110     if (!m_syncFd.isValid()) {
0111         return;
0112     }
0113     sync_set_deadline args{
0114         .deadline_ns = uint64_t(deadline.time_since_epoch().count()),
0115         .pad = 0,
0116     };
0117     drmIoctl(m_syncFd.get(), SYNC_IOC_SET_DEADLINE, &args);
0118 #endif
0119 }
0120 }