/* KWin - the KDE window manager This file is part of the KDE project. SPDX-FileCopyrightText: 2015 Martin Gräßlin SPDX-FileCopyrightText: 2022 Xaver Hugl SPDX-License-Identifier: GPL-2.0-or-later */ #include "drm_buffer.h" #include "core/graphicsbuffer.h" #include "drm_gpu.h" // system #include #if defined(Q_OS_LINUX) #include #include #endif // drm #include #include #include #include #include #ifdef Q_OS_LINUX #include #endif namespace KWin { static bool s_envIsSet = false; static bool s_disableBufferWait = qEnvironmentVariableIntValue("KWIN_DRM_DISABLE_BUFFER_READABILITY_CHECKS", &s_envIsSet) && s_envIsSet; DrmFramebuffer::DrmFramebuffer(DrmGpu *gpu, uint32_t fbId, GraphicsBuffer *buffer, FileDescriptor &&readFence) : m_framebufferId(fbId) , m_gpu(gpu) , m_bufferRef(buffer) { if (s_disableBufferWait || ((m_gpu->isVmwgfx()) && !s_envIsSet)) { // buffer readability checks cause frames to be wrongly delayed on Virtual Machines running vmwgfx m_readable = true; } m_syncFd = std::move(readFence); #ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE if (!m_syncFd.isValid()) { dma_buf_export_sync_file req{ .flags = DMA_BUF_SYNC_READ, .fd = -1, }; if (drmIoctl(buffer->dmabufAttributes()->fd[0].get(), DMA_BUF_IOCTL_EXPORT_SYNC_FILE, &req) == 0) { m_syncFd = FileDescriptor{req.fd}; } } #endif } DrmFramebuffer::~DrmFramebuffer() { uint32_t nonConstFb = m_framebufferId; #ifdef DRM_IOCTL_MODE_CLOSEFB struct drm_mode_closefb closeArgs{ .fb_id = m_framebufferId, .pad = 0, }; if (drmIoctl(m_gpu->fd(), DRM_IOCTL_MODE_CLOSEFB, &closeArgs) != 0) { drmIoctl(m_gpu->fd(), DRM_IOCTL_MODE_RMFB, &nonConstFb); } #else drmIoctl(m_gpu->fd(), DRM_IOCTL_MODE_RMFB, &nonConstFb); #endif } uint32_t DrmFramebuffer::framebufferId() const { return m_framebufferId; } GraphicsBuffer *DrmFramebuffer::buffer() const { return *m_bufferRef; } void DrmFramebuffer::releaseBuffer() { m_bufferRef = nullptr; } const FileDescriptor &DrmFramebuffer::syncFd() const { return m_syncFd; } bool DrmFramebuffer::isReadable() { if (m_readable) { return true; } else if (m_syncFd.isValid()) { return m_readable = m_syncFd.isReadable(); } else { const auto &fds = m_bufferRef->dmabufAttributes()->fd; m_readable = std::ranges::all_of(fds, [](const auto &fd) { return !fd.isValid() || fd.isReadable(); }); return m_readable; } } void DrmFramebuffer::setDeadline(std::chrono::steady_clock::time_point deadline) { #ifdef SYNC_IOC_SET_DEADLINE if (!m_syncFd.isValid()) { return; } sync_set_deadline args{ .deadline_ns = uint64_t(deadline.time_since_epoch().count()), .pad = 0, }; drmIoctl(m_syncFd.get(), SYNC_IOC_SET_DEADLINE, &args); #endif } }