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: 2017 Roman Gilg <subdiff@gmail.com> 0006 SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 #include "drm_buffer_gbm.h" 0011 #include "drm_gbm_surface.h" 0012 0013 #include "config-kwin.h" 0014 #include "drm_backend.h" 0015 #include "drm_gpu.h" 0016 #include "drm_logging.h" 0017 #include "kwineglutils_p.h" 0018 #include "wayland/clientbuffer.h" 0019 #include "wayland/linuxdmabufv1clientbuffer.h" 0020 0021 #include <cerrno> 0022 #include <drm_fourcc.h> 0023 #include <gbm.h> 0024 #include <sys/mman.h> 0025 #include <unistd.h> 0026 #include <xf86drm.h> 0027 #include <xf86drmMode.h> 0028 0029 namespace KWin 0030 { 0031 0032 static std::array<uint32_t, 4> getHandles(gbm_bo *bo) 0033 { 0034 std::array<uint32_t, 4> ret; 0035 int i = 0; 0036 for (; i < gbm_bo_get_plane_count(bo); i++) { 0037 ret[i] = gbm_bo_get_handle(bo).u32; 0038 } 0039 for (; i < 4; i++) { 0040 ret[i] = 0; 0041 } 0042 return ret; 0043 } 0044 0045 static std::array<uint32_t, 4> getStrides(gbm_bo *bo) 0046 { 0047 std::array<uint32_t, 4> ret; 0048 int i = 0; 0049 for (; i < gbm_bo_get_plane_count(bo); i++) { 0050 ret[i] = gbm_bo_get_stride_for_plane(bo, i); 0051 } 0052 for (; i < 4; i++) { 0053 ret[i] = 0; 0054 } 0055 return ret; 0056 } 0057 0058 static std::array<uint32_t, 4> getOffsets(gbm_bo *bo) 0059 { 0060 std::array<uint32_t, 4> ret; 0061 int i = 0; 0062 for (; i < gbm_bo_get_plane_count(bo); i++) { 0063 ret[i] = gbm_bo_get_offset(bo, i); 0064 } 0065 for (; i < 4; i++) { 0066 ret[i] = 0; 0067 } 0068 return ret; 0069 } 0070 0071 GbmBuffer::GbmBuffer(DrmGpu *gpu, gbm_bo *bo, const std::shared_ptr<GbmSurface> &surface) 0072 : DrmGpuBuffer(gpu, QSize(gbm_bo_get_width(bo), gbm_bo_get_height(bo)), gbm_bo_get_format(bo), gbm_bo_get_modifier(bo), getHandles(bo), getStrides(bo), getOffsets(bo), gbm_bo_get_plane_count(bo)) 0073 , m_bo(bo) 0074 , m_surface(surface) 0075 , m_flags(surface->flags()) 0076 { 0077 } 0078 0079 GbmBuffer::GbmBuffer(DrmGpu *gpu, gbm_bo *bo, uint32_t flags) 0080 : DrmGpuBuffer(gpu, QSize(gbm_bo_get_width(bo), gbm_bo_get_height(bo)), gbm_bo_get_format(bo), gbm_bo_get_modifier(bo), getHandles(bo), getStrides(bo), getOffsets(bo), gbm_bo_get_plane_count(bo)) 0081 , m_bo(bo) 0082 , m_flags(flags) 0083 { 0084 } 0085 0086 GbmBuffer::GbmBuffer(DrmGpu *gpu, gbm_bo *bo, KWaylandServer::LinuxDmaBufV1ClientBuffer *clientBuffer, uint32_t flags) 0087 : DrmGpuBuffer(gpu, QSize(gbm_bo_get_width(bo), gbm_bo_get_height(bo)), gbm_bo_get_format(bo), gbm_bo_get_modifier(bo), getHandles(bo), getStrides(bo), getOffsets(bo), gbm_bo_get_plane_count(bo)) 0088 , m_bo(bo) 0089 , m_clientBuffer(clientBuffer) 0090 , m_flags(flags) 0091 { 0092 m_clientBuffer->ref(); 0093 } 0094 0095 GbmBuffer::~GbmBuffer() 0096 { 0097 if (m_clientBuffer) { 0098 m_clientBuffer->unref(); 0099 } 0100 if (m_mapping) { 0101 gbm_bo_unmap(m_bo, m_mapping); 0102 } 0103 if (m_surface) { 0104 m_surface->releaseBuffer(this); 0105 } else { 0106 gbm_bo_destroy(m_bo); 0107 } 0108 } 0109 0110 gbm_bo *GbmBuffer::bo() const 0111 { 0112 return m_bo; 0113 } 0114 0115 void *GbmBuffer::mappedData() const 0116 { 0117 return m_data; 0118 } 0119 0120 KWaylandServer::ClientBuffer *GbmBuffer::clientBuffer() const 0121 { 0122 return m_clientBuffer; 0123 } 0124 0125 uint32_t GbmBuffer::flags() const 0126 { 0127 return m_flags; 0128 } 0129 0130 GbmBuffer::Map GbmBuffer::map(uint32_t flags) 0131 { 0132 if (!m_data) { 0133 m_data = gbm_bo_map(m_bo, 0, 0, m_size.width(), m_size.height(), flags, &m_mapStride, &m_mapping); 0134 } 0135 return Map{ 0136 .data = m_data, 0137 .stride = m_mapStride, 0138 }; 0139 } 0140 0141 void GbmBuffer::createFds() 0142 { 0143 #if HAVE_GBM_BO_GET_FD_FOR_PLANE 0144 for (uint32_t i = 0; i < m_planeCount; i++) { 0145 m_fds[i] = FileDescriptor(gbm_bo_get_fd_for_plane(m_bo, i)); 0146 if (!m_fds[i].isValid()) { 0147 m_fds = {}; 0148 return; 0149 } 0150 } 0151 return; 0152 #else 0153 if (m_planeCount > 1) { 0154 return; 0155 } 0156 m_fds[0] = FileDescriptor(gbm_bo_get_fd(m_bo)); 0157 #endif 0158 } 0159 0160 std::shared_ptr<GbmBuffer> GbmBuffer::importBuffer(DrmGpu *gpu, KWaylandServer::LinuxDmaBufV1ClientBuffer *clientBuffer) 0161 { 0162 const auto &attrs = clientBuffer->attributes(); 0163 gbm_bo *bo; 0164 if (attrs.modifier != DRM_FORMAT_MOD_INVALID || attrs.offset[0] > 0 || attrs.planeCount > 1) { 0165 gbm_import_fd_modifier_data data = {}; 0166 data.format = attrs.format; 0167 data.width = static_cast<uint32_t>(attrs.width); 0168 data.height = static_cast<uint32_t>(attrs.height); 0169 data.num_fds = attrs.planeCount; 0170 data.modifier = attrs.modifier; 0171 for (int i = 0; i < attrs.planeCount; i++) { 0172 data.fds[i] = attrs.fd[i].get(); 0173 data.offsets[i] = attrs.offset[i]; 0174 data.strides[i] = attrs.pitch[i]; 0175 } 0176 bo = gbm_bo_import(gpu->gbmDevice(), GBM_BO_IMPORT_FD_MODIFIER, &data, GBM_BO_USE_SCANOUT); 0177 } else { 0178 gbm_import_fd_data data = {}; 0179 data.fd = attrs.fd[0].get(); 0180 data.width = static_cast<uint32_t>(attrs.width); 0181 data.height = static_cast<uint32_t>(attrs.height); 0182 data.stride = attrs.pitch[0]; 0183 data.format = attrs.format; 0184 bo = gbm_bo_import(gpu->gbmDevice(), GBM_BO_IMPORT_FD, &data, GBM_BO_USE_SCANOUT); 0185 } 0186 if (bo) { 0187 return std::make_shared<GbmBuffer>(gpu, bo, clientBuffer, GBM_BO_USE_SCANOUT); 0188 } else { 0189 return nullptr; 0190 } 0191 } 0192 0193 std::shared_ptr<GbmBuffer> GbmBuffer::importBuffer(DrmGpu *gpu, GbmBuffer *buffer, uint32_t flags) 0194 { 0195 const auto &fds = buffer->fds(); 0196 if (!fds[0].isValid()) { 0197 return nullptr; 0198 } 0199 const auto strides = buffer->strides(); 0200 const auto offsets = buffer->offsets(); 0201 gbm_import_fd_modifier_data data = { 0202 .width = (uint32_t)buffer->size().width(), 0203 .height = (uint32_t)buffer->size().height(), 0204 .format = buffer->format(), 0205 .num_fds = (uint32_t)buffer->planeCount(), 0206 .fds = {}, 0207 .strides = {}, 0208 .offsets = {}, 0209 .modifier = buffer->modifier(), 0210 }; 0211 for (uint32_t i = 0; i < data.num_fds; i++) { 0212 data.fds[i] = fds[i].get(); 0213 data.strides[i] = strides[i]; 0214 data.offsets[i] = offsets[i]; 0215 } 0216 gbm_bo *bo = gbm_bo_import(gpu->gbmDevice(), GBM_BO_IMPORT_FD_MODIFIER, &data, flags); 0217 if (bo) { 0218 return std::make_shared<GbmBuffer>(gpu, bo, flags); 0219 } else { 0220 return nullptr; 0221 } 0222 } 0223 }