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