/* KWin - the KDE window manager This file is part of the KDE project. SPDX-FileCopyrightText: 2017 Roman Gilg SPDX-FileCopyrightText: 2015 Martin Gräßlin SPDX-License-Identifier: GPL-2.0-or-later */ #include "drm_buffer_gbm.h" #include "drm_gbm_surface.h" #include "config-kwin.h" #include "drm_backend.h" #include "drm_gpu.h" #include "drm_logging.h" #include "kwineglutils_p.h" #include "wayland/clientbuffer.h" #include "wayland/linuxdmabufv1clientbuffer.h" #include #include #include #include #include #include #include namespace KWin { static std::array getHandles(gbm_bo *bo) { std::array ret; int i = 0; for (; i < gbm_bo_get_plane_count(bo); i++) { ret[i] = gbm_bo_get_handle(bo).u32; } for (; i < 4; i++) { ret[i] = 0; } return ret; } static std::array getStrides(gbm_bo *bo) { std::array ret; int i = 0; for (; i < gbm_bo_get_plane_count(bo); i++) { ret[i] = gbm_bo_get_stride_for_plane(bo, i); } for (; i < 4; i++) { ret[i] = 0; } return ret; } static std::array getOffsets(gbm_bo *bo) { std::array ret; int i = 0; for (; i < gbm_bo_get_plane_count(bo); i++) { ret[i] = gbm_bo_get_offset(bo, i); } for (; i < 4; i++) { ret[i] = 0; } return ret; } GbmBuffer::GbmBuffer(DrmGpu *gpu, gbm_bo *bo, const std::shared_ptr &surface) : 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)) , m_bo(bo) , m_surface(surface) { } GbmBuffer::GbmBuffer(DrmGpu *gpu, gbm_bo *bo) : 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)) , m_bo(bo) { } GbmBuffer::GbmBuffer(DrmGpu *gpu, gbm_bo *bo, KWaylandServer::LinuxDmaBufV1ClientBuffer *clientBuffer) : 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)) , m_bo(bo) , m_clientBuffer(clientBuffer) { m_clientBuffer->ref(); } GbmBuffer::~GbmBuffer() { if (m_clientBuffer) { m_clientBuffer->unref(); } if (m_mapping) { gbm_bo_unmap(m_bo, m_mapping); } if (m_surface) { m_surface->releaseBuffer(this); } else { gbm_bo_destroy(m_bo); } } gbm_bo *GbmBuffer::bo() const { return m_bo; } void *GbmBuffer::mappedData() const { return m_data; } KWaylandServer::ClientBuffer *GbmBuffer::clientBuffer() const { return m_clientBuffer; } bool GbmBuffer::map(uint32_t flags) { if (m_data) { return true; } uint32_t stride = m_strides[0]; m_data = gbm_bo_map(m_bo, 0, 0, m_size.width(), m_size.height(), flags, &stride, &m_mapping); return m_data; } void GbmBuffer::createFds() { #if HAVE_GBM_BO_GET_FD_FOR_PLANE for (uint32_t i = 0; i < m_planeCount; i++) { m_fds[i] = FileDescriptor(gbm_bo_get_fd_for_plane(m_bo, i)); if (!m_fds[i].isValid()) { m_fds = {}; return; } } return; #else if (m_planeCount > 1) { return; } m_fds[0] = FileDescriptor(gbm_bo_get_fd(m_bo)); #endif } std::shared_ptr GbmBuffer::importBuffer(DrmGpu *gpu, KWaylandServer::LinuxDmaBufV1ClientBuffer *clientBuffer) { const auto &attrs = clientBuffer->attributes(); gbm_bo *bo; if (attrs.modifier != DRM_FORMAT_MOD_INVALID || attrs.offset[0] > 0 || attrs.planeCount > 1) { gbm_import_fd_modifier_data data = {}; data.format = attrs.format; data.width = static_cast(attrs.width); data.height = static_cast(attrs.height); data.num_fds = attrs.planeCount; data.modifier = attrs.modifier; for (int i = 0; i < attrs.planeCount; i++) { data.fds[i] = attrs.fd[i].get(); data.offsets[i] = attrs.offset[i]; data.strides[i] = attrs.pitch[i]; } bo = gbm_bo_import(gpu->gbmDevice(), GBM_BO_IMPORT_FD_MODIFIER, &data, GBM_BO_USE_SCANOUT); } else { gbm_import_fd_data data = {}; data.fd = attrs.fd[0].get(); data.width = static_cast(attrs.width); data.height = static_cast(attrs.height); data.stride = attrs.pitch[0]; data.format = attrs.format; bo = gbm_bo_import(gpu->gbmDevice(), GBM_BO_IMPORT_FD, &data, GBM_BO_USE_SCANOUT); } if (bo) { return std::make_shared(gpu, bo, clientBuffer); } else { return nullptr; } } std::shared_ptr GbmBuffer::importBuffer(DrmGpu *gpu, GbmBuffer *buffer, uint32_t flags) { const auto &fds = buffer->fds(); if (!fds[0].isValid()) { return nullptr; } const auto strides = buffer->strides(); const auto offsets = buffer->offsets(); gbm_import_fd_modifier_data data = { .width = (uint32_t)buffer->size().width(), .height = (uint32_t)buffer->size().height(), .format = buffer->format(), .num_fds = (uint32_t)buffer->planeCount(), .fds = {}, .strides = {}, .offsets = {}, .modifier = buffer->modifier(), }; for (uint32_t i = 0; i < data.num_fds; i++) { data.fds[i] = fds[i].get(); data.strides[i] = strides[i]; data.offsets[i] = offsets[i]; } gbm_bo *bo = gbm_bo_import(gpu->gbmDevice(), GBM_BO_IMPORT_FD_MODIFIER, &data, flags); if (bo) { return std::make_shared(gpu, bo); } else { return nullptr; } } }