File indexing completed on 2024-11-10 04:56:26
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 }