File indexing completed on 2024-11-10 04:56:53

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2017 Martin Flöser <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 "opengl/eglswapchain.h"
0011 #include "core/graphicsbuffer.h"
0012 #include "core/graphicsbufferallocator.h"
0013 #include "opengl/eglcontext.h"
0014 #include "opengl/glutils.h"
0015 #include "utils/common.h"
0016 
0017 #include <drm_fourcc.h>
0018 #include <errno.h>
0019 
0020 namespace KWin
0021 {
0022 
0023 EglSwapchainSlot::EglSwapchainSlot(GraphicsBuffer *buffer, std::unique_ptr<GLFramebuffer> &&framebuffer, const std::shared_ptr<GLTexture> &texture)
0024     : m_buffer(buffer)
0025     , m_framebuffer(std::move(framebuffer))
0026     , m_texture(texture)
0027 {
0028 }
0029 
0030 EglSwapchainSlot::~EglSwapchainSlot()
0031 {
0032     m_framebuffer.reset();
0033     m_texture.reset();
0034     m_buffer->drop();
0035 }
0036 
0037 GraphicsBuffer *EglSwapchainSlot::buffer() const
0038 {
0039     return m_buffer;
0040 }
0041 
0042 std::shared_ptr<GLTexture> EglSwapchainSlot::texture() const
0043 {
0044     return m_texture;
0045 }
0046 
0047 GLFramebuffer *EglSwapchainSlot::framebuffer() const
0048 {
0049     return m_framebuffer.get();
0050 }
0051 
0052 int EglSwapchainSlot::age() const
0053 {
0054     return m_age;
0055 }
0056 
0057 std::shared_ptr<EglSwapchainSlot> EglSwapchainSlot::create(EglContext *context, GraphicsBuffer *buffer)
0058 {
0059     auto texture = context->importDmaBufAsTexture(*buffer->dmabufAttributes());
0060     if (!texture) {
0061         buffer->drop();
0062         return nullptr;
0063     }
0064     auto framebuffer = std::make_unique<GLFramebuffer>(texture.get());
0065     if (!framebuffer->valid()) {
0066         buffer->drop();
0067         return nullptr;
0068     }
0069     return std::make_shared<EglSwapchainSlot>(buffer, std::move(framebuffer), texture);
0070 }
0071 
0072 EglSwapchain::EglSwapchain(GraphicsBufferAllocator *allocator, EglContext *context, const QSize &size, uint32_t format, uint64_t modifier, const std::shared_ptr<EglSwapchainSlot> &seed)
0073     : m_allocator(allocator)
0074     , m_context(context)
0075     , m_size(size)
0076     , m_format(format)
0077     , m_modifier(modifier)
0078     , m_slots({seed})
0079 {
0080 }
0081 
0082 EglSwapchain::~EglSwapchain()
0083 {
0084 }
0085 
0086 QSize EglSwapchain::size() const
0087 {
0088     return m_size;
0089 }
0090 
0091 uint32_t EglSwapchain::format() const
0092 {
0093     return m_format;
0094 }
0095 
0096 uint64_t EglSwapchain::modifier() const
0097 {
0098     return m_modifier;
0099 }
0100 
0101 std::shared_ptr<EglSwapchainSlot> EglSwapchain::acquire()
0102 {
0103     for (const auto &slot : std::as_const(m_slots)) {
0104         if (!slot->buffer()->isReferenced()) {
0105             return slot;
0106         }
0107     }
0108 
0109     GraphicsBuffer *buffer = m_allocator->allocate(GraphicsBufferOptions{
0110         .size = m_size,
0111         .format = m_format,
0112         .modifiers = {m_modifier},
0113     });
0114     if (!buffer) {
0115         qCWarning(KWIN_OPENGL) << "Failed to allocate an egl gbm swapchain graphics buffer";
0116         return nullptr;
0117     }
0118 
0119     auto slot = EglSwapchainSlot::create(m_context, buffer);
0120     if (!slot) {
0121         return nullptr;
0122     }
0123     m_slots.append(slot);
0124     return slot;
0125 }
0126 
0127 void EglSwapchain::release(std::shared_ptr<EglSwapchainSlot> slot)
0128 {
0129     for (qsizetype i = 0; i < m_slots.count(); ++i) {
0130         if (m_slots[i] == slot) {
0131             m_slots[i]->m_age = 1;
0132         } else if (m_slots[i]->m_age > 0) {
0133             m_slots[i]->m_age++;
0134         }
0135     }
0136 }
0137 
0138 std::shared_ptr<EglSwapchain> EglSwapchain::create(GraphicsBufferAllocator *allocator, EglContext *context, const QSize &size, uint32_t format, const QList<uint64_t> &modifiers)
0139 {
0140     if (!context->makeCurrent()) {
0141         return nullptr;
0142     }
0143 
0144     // The seed graphics buffer is used to fixate modifiers.
0145     GraphicsBuffer *seed = allocator->allocate(GraphicsBufferOptions{
0146         .size = size,
0147         .format = format,
0148         .modifiers = modifiers,
0149     });
0150     if (!seed) {
0151         return nullptr;
0152     }
0153     const auto first = EglSwapchainSlot::create(context, seed);
0154     if (!first) {
0155         return nullptr;
0156     }
0157     return std::make_shared<EglSwapchain>(std::move(allocator),
0158                                           context,
0159                                           size,
0160                                           format,
0161                                           seed->dmabufAttributes()->modifier,
0162                                           first);
0163 }
0164 
0165 } // namespace KWin