File indexing completed on 2025-04-20 10:57:34
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2022 Xaver Hugl <xaver.hugl@gmail.com> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 #include "drm_egl_layer.h" 0010 #include "drm_abstract_output.h" 0011 #include "drm_backend.h" 0012 #include "drm_buffer_gbm.h" 0013 #include "drm_egl_backend.h" 0014 #include "drm_gpu.h" 0015 #include "drm_logging.h" 0016 #include "drm_output.h" 0017 #include "drm_pipeline.h" 0018 #include "egl_dmabuf.h" 0019 #include "scene/surfaceitem_wayland.h" 0020 #include "wayland/linuxdmabufv1clientbuffer.h" 0021 #include "wayland/surface_interface.h" 0022 0023 #include <QRegion> 0024 #include <drm_fourcc.h> 0025 #include <errno.h> 0026 #include <gbm.h> 0027 #include <unistd.h> 0028 0029 namespace KWin 0030 { 0031 0032 EglGbmLayer::EglGbmLayer(EglGbmBackend *eglBackend, DrmPipeline *pipeline) 0033 : DrmPipelineLayer(pipeline) 0034 , m_surface(pipeline->gpu(), eglBackend) 0035 , m_dmabufFeedback(pipeline->gpu(), eglBackend) 0036 { 0037 } 0038 0039 std::optional<OutputLayerBeginFrameInfo> EglGbmLayer::beginFrame() 0040 { 0041 m_scanoutBuffer.reset(); 0042 m_dmabufFeedback.renderingSurface(); 0043 0044 return m_surface.startRendering(m_pipeline->bufferSize(), m_pipeline->renderOrientation(), m_pipeline->bufferOrientation(), m_pipeline->formats()); 0045 } 0046 0047 void EglGbmLayer::aboutToStartPainting(const QRegion &damagedRegion) 0048 { 0049 m_surface.aboutToStartPainting(m_pipeline->output(), damagedRegion); 0050 } 0051 0052 bool EglGbmLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) 0053 { 0054 const bool ret = m_surface.endRendering(m_pipeline->renderOrientation(), damagedRegion); 0055 if (ret) { 0056 m_currentDamage = damagedRegion; 0057 } 0058 return ret; 0059 } 0060 0061 QRegion EglGbmLayer::currentDamage() const 0062 { 0063 return m_currentDamage; 0064 } 0065 0066 bool EglGbmLayer::checkTestBuffer() 0067 { 0068 return m_surface.renderTestBuffer(m_pipeline->bufferSize(), m_pipeline->formats()) != nullptr; 0069 } 0070 0071 std::shared_ptr<GLTexture> EglGbmLayer::texture() const 0072 { 0073 if (m_scanoutBuffer) { 0074 return m_surface.eglBackend()->importBufferObjectAsTexture(static_cast<GbmBuffer *>(m_scanoutBuffer->buffer())->bo()); 0075 } else { 0076 return m_surface.texture(); 0077 } 0078 } 0079 0080 bool EglGbmLayer::scanout(SurfaceItem *surfaceItem) 0081 { 0082 static bool valid; 0083 static const bool directScanoutDisabled = qEnvironmentVariableIntValue("KWIN_DRM_NO_DIRECT_SCANOUT", &valid) == 1 && valid; 0084 if (directScanoutDisabled) { 0085 return false; 0086 } 0087 0088 SurfaceItemWayland *item = qobject_cast<SurfaceItemWayland *>(surfaceItem); 0089 if (!item || !item->surface()) { 0090 return false; 0091 } 0092 const auto surface = item->surface(); 0093 if (m_pipeline->bufferOrientation() != DrmPlane::Transformations(DrmPlane::Transformation::Rotate0) || surface->bufferTransform() != m_pipeline->output()->transform()) { 0094 return false; 0095 } 0096 const auto buffer = qobject_cast<KWaylandServer::LinuxDmaBufV1ClientBuffer *>(surface->buffer()); 0097 if (!buffer) { 0098 return false; 0099 } 0100 0101 const auto formats = m_pipeline->formats(); 0102 if (!formats.contains(buffer->format())) { 0103 m_dmabufFeedback.scanoutFailed(surface, formats); 0104 return false; 0105 } 0106 if (buffer->attributes().modifier == DRM_FORMAT_MOD_INVALID && m_pipeline->gpu()->platform()->gpuCount() > 1) { 0107 // importing a buffer from another GPU without an explicit modifier can mess up the buffer format 0108 return false; 0109 } 0110 if (!formats[buffer->format()].contains(buffer->attributes().modifier)) { 0111 return false; 0112 } 0113 const auto gbmBuffer = GbmBuffer::importBuffer(m_pipeline->gpu(), buffer); 0114 if (!gbmBuffer) { 0115 m_dmabufFeedback.scanoutFailed(surface, formats); 0116 return false; 0117 } 0118 m_scanoutBuffer = DrmFramebuffer::createFramebuffer(gbmBuffer); 0119 if (m_scanoutBuffer && m_pipeline->testScanout()) { 0120 m_dmabufFeedback.scanoutSuccessful(surface); 0121 m_currentDamage = surfaceItem->damage(); 0122 surfaceItem->resetDamage(); 0123 // ensure the pixmap is updated when direct scanout ends 0124 surfaceItem->destroyPixmap(); 0125 return true; 0126 } else { 0127 m_dmabufFeedback.scanoutFailed(surface, formats); 0128 m_scanoutBuffer.reset(); 0129 return false; 0130 } 0131 } 0132 0133 std::shared_ptr<DrmFramebuffer> EglGbmLayer::currentBuffer() const 0134 { 0135 return m_scanoutBuffer ? m_scanoutBuffer : m_surface.currentBuffer(); 0136 } 0137 0138 bool EglGbmLayer::hasDirectScanoutBuffer() const 0139 { 0140 return m_scanoutBuffer != nullptr; 0141 } 0142 0143 void EglGbmLayer::releaseBuffers() 0144 { 0145 m_scanoutBuffer.reset(); 0146 m_surface.destroyResources(); 0147 } 0148 }