File indexing completed on 2026-06-14 15:32:07
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2019 Roman Gilg <subdiff@gmail.com> 0006 SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 #include "wayland_backend.h" 0011 0012 #include "wayland_display.h" 0013 #include "wayland_egl_backend.h" 0014 #include "wayland_logging.h" 0015 #include "wayland_output.h" 0016 #include "wayland_qpainter_backend.h" 0017 0018 #include "dpmsinputeventfilter.h" 0019 #include "input.h" 0020 0021 #include <KWayland/Client/keyboard.h> 0022 #include <KWayland/Client/pointer.h> 0023 #include <KWayland/Client/pointergestures.h> 0024 #include <KWayland/Client/relativepointer.h> 0025 #include <KWayland/Client/seat.h> 0026 #include <KWayland/Client/surface.h> 0027 #include <KWayland/Client/touch.h> 0028 0029 #include <QAbstractEventDispatcher> 0030 0031 #include <drm_fourcc.h> 0032 #include <fcntl.h> 0033 #include <gbm.h> 0034 #include <linux/input.h> 0035 #include <unistd.h> 0036 #include <wayland-client-core.h> 0037 0038 #include "../drm/gbm_dmabuf.h" 0039 0040 namespace KWin 0041 { 0042 namespace Wayland 0043 { 0044 0045 using namespace KWayland::Client; 0046 0047 inline static QPointF sizeToPoint(const QSizeF &size) 0048 { 0049 return QPointF(size.width(), size.height()); 0050 } 0051 0052 WaylandInputDevice::WaylandInputDevice(KWayland::Client::Keyboard *keyboard, WaylandSeat *seat) 0053 : m_seat(seat) 0054 , m_keyboard(keyboard) 0055 { 0056 connect(keyboard, &Keyboard::keyChanged, this, [this](quint32 key, Keyboard::KeyState nativeState, quint32 time) { 0057 InputRedirection::KeyboardKeyState state; 0058 switch (nativeState) { 0059 case Keyboard::KeyState::Pressed: 0060 if (key == KEY_RIGHTCTRL) { 0061 m_seat->backend()->togglePointerLock(); 0062 } 0063 state = InputRedirection::KeyboardKeyPressed; 0064 break; 0065 case Keyboard::KeyState::Released: 0066 state = InputRedirection::KeyboardKeyReleased; 0067 break; 0068 default: 0069 Q_UNREACHABLE(); 0070 } 0071 Q_EMIT keyChanged(key, state, std::chrono::milliseconds(time), this); 0072 }); 0073 } 0074 0075 WaylandInputDevice::WaylandInputDevice(KWayland::Client::Pointer *pointer, WaylandSeat *seat) 0076 : m_seat(seat) 0077 , m_pointer(pointer) 0078 { 0079 connect(pointer, &Pointer::entered, this, [this](quint32 serial, const QPointF &relativeToSurface) { 0080 WaylandOutput *output = m_seat->backend()->findOutput(m_pointer->enteredSurface()); 0081 Q_ASSERT(output); 0082 output->cursor()->setPointer(m_pointer.get()); 0083 }); 0084 connect(pointer, &Pointer::left, this, [this]() { 0085 // wl_pointer.leave carries the wl_surface, but KWayland::Client::Pointer::left does not. 0086 const auto outputs = m_seat->backend()->outputs(); 0087 for (Output *output : outputs) { 0088 WaylandOutput *waylandOutput = static_cast<WaylandOutput *>(output); 0089 if (waylandOutput->cursor()->pointer()) { 0090 waylandOutput->cursor()->setPointer(nullptr); 0091 } 0092 } 0093 }); 0094 connect(pointer, &Pointer::motion, this, [this](const QPointF &relativeToSurface, quint32 time) { 0095 WaylandOutput *output = m_seat->backend()->findOutput(m_pointer->enteredSurface()); 0096 Q_ASSERT(output); 0097 const QPointF absolutePos = output->geometry().topLeft() + relativeToSurface; 0098 Q_EMIT pointerMotionAbsolute(absolutePos, std::chrono::milliseconds(time), this); 0099 }); 0100 connect(pointer, &Pointer::buttonStateChanged, this, [this](quint32 serial, quint32 time, quint32 button, Pointer::ButtonState nativeState) { 0101 InputRedirection::PointerButtonState state; 0102 switch (nativeState) { 0103 case Pointer::ButtonState::Pressed: 0104 state = InputRedirection::PointerButtonPressed; 0105 break; 0106 case Pointer::ButtonState::Released: 0107 state = InputRedirection::PointerButtonReleased; 0108 break; 0109 default: 0110 Q_UNREACHABLE(); 0111 } 0112 Q_EMIT pointerButtonChanged(button, state, std::chrono::milliseconds(time), this); 0113 }); 0114 // TODO: Send discreteDelta and source as well. 0115 connect(pointer, &Pointer::axisChanged, this, [this](quint32 time, Pointer::Axis nativeAxis, qreal delta) { 0116 InputRedirection::PointerAxis axis; 0117 switch (nativeAxis) { 0118 case Pointer::Axis::Horizontal: 0119 axis = InputRedirection::PointerAxisHorizontal; 0120 break; 0121 case Pointer::Axis::Vertical: 0122 axis = InputRedirection::PointerAxisVertical; 0123 break; 0124 default: 0125 Q_UNREACHABLE(); 0126 } 0127 Q_EMIT pointerAxisChanged(axis, delta, 0, InputRedirection::PointerAxisSourceUnknown, std::chrono::milliseconds(time), this); 0128 }); 0129 0130 KWayland::Client::PointerGestures *pointerGestures = m_seat->backend()->display()->pointerGestures(); 0131 if (pointerGestures) { 0132 m_pinchGesture.reset(pointerGestures->createPinchGesture(m_pointer.get(), this)); 0133 connect(m_pinchGesture.get(), &PointerPinchGesture::started, this, [this](quint32 serial, quint32 time) { 0134 Q_EMIT pinchGestureBegin(m_pinchGesture->fingerCount(), std::chrono::milliseconds(time), this); 0135 }); 0136 connect(m_pinchGesture.get(), &PointerPinchGesture::updated, this, [this](const QSizeF &delta, qreal scale, qreal rotation, quint32 time) { 0137 Q_EMIT pinchGestureUpdate(scale, rotation, sizeToPoint(delta), std::chrono::milliseconds(time), this); 0138 }); 0139 connect(m_pinchGesture.get(), &PointerPinchGesture::ended, this, [this](quint32 serial, quint32 time) { 0140 Q_EMIT pinchGestureEnd(std::chrono::milliseconds(time), this); 0141 }); 0142 connect(m_pinchGesture.get(), &PointerPinchGesture::cancelled, this, [this](quint32 serial, quint32 time) { 0143 Q_EMIT pinchGestureCancelled(std::chrono::milliseconds(time), this); 0144 }); 0145 0146 m_swipeGesture.reset(pointerGestures->createSwipeGesture(m_pointer.get(), this)); 0147 connect(m_swipeGesture.get(), &PointerSwipeGesture::started, this, [this](quint32 serial, quint32 time) { 0148 Q_EMIT swipeGestureBegin(m_swipeGesture->fingerCount(), std::chrono::milliseconds(time), this); 0149 }); 0150 connect(m_swipeGesture.get(), &PointerSwipeGesture::updated, this, [this](const QSizeF &delta, quint32 time) { 0151 Q_EMIT swipeGestureUpdate(sizeToPoint(delta), std::chrono::milliseconds(time), this); 0152 }); 0153 connect(m_swipeGesture.get(), &PointerSwipeGesture::ended, this, [this](quint32 serial, quint32 time) { 0154 Q_EMIT swipeGestureEnd(std::chrono::milliseconds(time), this); 0155 }); 0156 connect(m_swipeGesture.get(), &PointerSwipeGesture::cancelled, this, [this](quint32 serial, quint32 time) { 0157 Q_EMIT swipeGestureCancelled(std::chrono::milliseconds(time), this); 0158 }); 0159 } 0160 } 0161 0162 WaylandInputDevice::WaylandInputDevice(KWayland::Client::RelativePointer *relativePointer, WaylandSeat *seat) 0163 : m_seat(seat) 0164 , m_relativePointer(relativePointer) 0165 { 0166 connect(relativePointer, &RelativePointer::relativeMotion, this, [this](const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 timestamp) { 0167 Q_EMIT pointerMotion(sizeToPoint(delta), sizeToPoint(deltaNonAccelerated), std::chrono::microseconds(timestamp), this); 0168 }); 0169 } 0170 0171 WaylandInputDevice::WaylandInputDevice(KWayland::Client::Touch *touch, WaylandSeat *seat) 0172 : m_seat(seat) 0173 , m_touch(touch) 0174 { 0175 connect(touch, &Touch::sequenceCanceled, this, [this]() { 0176 Q_EMIT touchCanceled(this); 0177 }); 0178 connect(touch, &Touch::frameEnded, this, [this]() { 0179 Q_EMIT touchFrame(this); 0180 }); 0181 connect(touch, &Touch::sequenceStarted, this, [this](TouchPoint *tp) { 0182 Q_EMIT touchDown(tp->id(), tp->position(), std::chrono::milliseconds(tp->time()), this); 0183 }); 0184 connect(touch, &Touch::pointAdded, this, [this](TouchPoint *tp) { 0185 Q_EMIT touchDown(tp->id(), tp->position(), std::chrono::milliseconds(tp->time()), this); 0186 }); 0187 connect(touch, &Touch::pointRemoved, this, [this](TouchPoint *tp) { 0188 Q_EMIT touchUp(tp->id(), std::chrono::milliseconds(tp->time()), this); 0189 }); 0190 connect(touch, &Touch::pointMoved, this, [this](TouchPoint *tp) { 0191 Q_EMIT touchMotion(tp->id(), tp->position(), std::chrono::milliseconds(tp->time()), this); 0192 }); 0193 } 0194 0195 WaylandInputDevice::~WaylandInputDevice() 0196 { 0197 } 0198 0199 QString WaylandInputDevice::sysName() const 0200 { 0201 return QString(); 0202 } 0203 0204 QString WaylandInputDevice::name() const 0205 { 0206 return QString(); 0207 } 0208 0209 bool WaylandInputDevice::isEnabled() const 0210 { 0211 return true; 0212 } 0213 0214 void WaylandInputDevice::setEnabled(bool enabled) 0215 { 0216 } 0217 0218 LEDs WaylandInputDevice::leds() const 0219 { 0220 return LEDs(); 0221 } 0222 0223 void WaylandInputDevice::setLeds(LEDs leds) 0224 { 0225 } 0226 0227 bool WaylandInputDevice::isKeyboard() const 0228 { 0229 return m_keyboard != nullptr; 0230 } 0231 0232 bool WaylandInputDevice::isAlphaNumericKeyboard() const 0233 { 0234 return m_keyboard != nullptr; 0235 } 0236 0237 bool WaylandInputDevice::isPointer() const 0238 { 0239 return m_pointer || m_relativePointer; 0240 } 0241 0242 bool WaylandInputDevice::isTouchpad() const 0243 { 0244 return false; 0245 } 0246 0247 bool WaylandInputDevice::isTouch() const 0248 { 0249 return m_touch != nullptr; 0250 } 0251 0252 bool WaylandInputDevice::isTabletTool() const 0253 { 0254 return false; 0255 } 0256 0257 bool WaylandInputDevice::isTabletPad() const 0258 { 0259 return false; 0260 } 0261 0262 bool WaylandInputDevice::isTabletModeSwitch() const 0263 { 0264 return false; 0265 } 0266 0267 bool WaylandInputDevice::isLidSwitch() const 0268 { 0269 return false; 0270 } 0271 0272 KWayland::Client::Pointer *WaylandInputDevice::nativePointer() const 0273 { 0274 return m_pointer.get(); 0275 } 0276 0277 WaylandInputBackend::WaylandInputBackend(WaylandBackend *backend, QObject *parent) 0278 : InputBackend(parent) 0279 , m_backend(backend) 0280 { 0281 } 0282 0283 void WaylandInputBackend::initialize() 0284 { 0285 WaylandSeat *seat = m_backend->seat(); 0286 if (seat->relativePointerDevice()) { 0287 Q_EMIT deviceAdded(seat->relativePointerDevice()); 0288 } 0289 if (seat->pointerDevice()) { 0290 Q_EMIT deviceAdded(seat->pointerDevice()); 0291 } 0292 if (seat->keyboardDevice()) { 0293 Q_EMIT deviceAdded(seat->keyboardDevice()); 0294 } 0295 if (seat->touchDevice()) { 0296 Q_EMIT deviceAdded(seat->touchDevice()); 0297 } 0298 0299 connect(seat, &WaylandSeat::deviceAdded, this, &InputBackend::deviceAdded); 0300 connect(seat, &WaylandSeat::deviceRemoved, this, &InputBackend::deviceRemoved); 0301 } 0302 0303 WaylandSeat::WaylandSeat(KWayland::Client::Seat *nativeSeat, WaylandBackend *backend) 0304 : QObject(nullptr) 0305 , m_seat(nativeSeat) 0306 , m_backend(backend) 0307 { 0308 auto updateKeyboardDevice = [this](){ 0309 if (m_seat->hasKeyboard()) { 0310 createKeyboardDevice(); 0311 } else { 0312 destroyKeyboardDevice(); 0313 } 0314 }; 0315 0316 updateKeyboardDevice(); 0317 connect(m_seat, &Seat::hasKeyboardChanged, this, updateKeyboardDevice); 0318 0319 auto updatePointerDevice = [this]() { 0320 if (m_seat->hasPointer()) { 0321 createPointerDevice(); 0322 } else { 0323 destroyPointerDevice(); 0324 } 0325 }; 0326 0327 updatePointerDevice(); 0328 connect(m_seat, &Seat::hasPointerChanged, this, updatePointerDevice); 0329 0330 auto updateTouchDevice = [this]() { 0331 if (m_seat->hasTouch()) { 0332 createTouchDevice(); 0333 } else { 0334 destroyTouchDevice(); 0335 } 0336 }; 0337 0338 updateTouchDevice(); 0339 connect(m_seat, &Seat::hasTouchChanged, this, updateTouchDevice); 0340 } 0341 0342 WaylandSeat::~WaylandSeat() 0343 { 0344 destroyPointerDevice(); 0345 destroyKeyboardDevice(); 0346 destroyTouchDevice(); 0347 } 0348 0349 void WaylandSeat::createPointerDevice() 0350 { 0351 m_pointerDevice = std::make_unique<WaylandInputDevice>(m_seat->createPointer(), this); 0352 Q_EMIT deviceAdded(m_pointerDevice.get()); 0353 } 0354 0355 void WaylandSeat::destroyPointerDevice() 0356 { 0357 if (m_pointerDevice) { 0358 Q_EMIT deviceRemoved(m_pointerDevice.get()); 0359 destroyRelativePointer(); 0360 m_pointerDevice.reset(); 0361 } 0362 } 0363 0364 void WaylandSeat::createRelativePointer() 0365 { 0366 KWayland::Client::RelativePointerManager *manager = m_backend->display()->relativePointerManager(); 0367 if (manager) { 0368 m_relativePointerDevice = std::make_unique<WaylandInputDevice>(manager->createRelativePointer(m_pointerDevice->nativePointer()), this); 0369 Q_EMIT deviceAdded(m_relativePointerDevice.get()); 0370 } 0371 } 0372 0373 void WaylandSeat::destroyRelativePointer() 0374 { 0375 if (m_relativePointerDevice) { 0376 Q_EMIT deviceRemoved(m_relativePointerDevice.get()); 0377 m_relativePointerDevice.reset(); 0378 } 0379 } 0380 0381 void WaylandSeat::createKeyboardDevice() 0382 { 0383 m_keyboardDevice = std::make_unique<WaylandInputDevice>(m_seat->createKeyboard(), this); 0384 Q_EMIT deviceAdded(m_keyboardDevice.get()); 0385 } 0386 0387 void WaylandSeat::destroyKeyboardDevice() 0388 { 0389 if (m_keyboardDevice) { 0390 Q_EMIT deviceRemoved(m_keyboardDevice.get()); 0391 m_keyboardDevice.reset(); 0392 } 0393 } 0394 0395 void WaylandSeat::createTouchDevice() 0396 { 0397 m_touchDevice = std::make_unique<WaylandInputDevice>(m_seat->createTouch(), this); 0398 Q_EMIT deviceAdded(m_touchDevice.get()); 0399 } 0400 0401 void WaylandSeat::destroyTouchDevice() 0402 { 0403 if (m_touchDevice) { 0404 Q_EMIT deviceRemoved(m_touchDevice.get()); 0405 m_touchDevice.reset(); 0406 } 0407 } 0408 0409 WaylandBackend::WaylandBackend(const WaylandBackendOptions &options, QObject *parent) 0410 : OutputBackend(parent) 0411 , m_options(options) 0412 { 0413 char const *drm_render_node = "/dev/dri/renderD128"; 0414 m_drmFileDescriptor = FileDescriptor(open(drm_render_node, O_RDWR | O_CLOEXEC)); 0415 if (!m_drmFileDescriptor.isValid()) { 0416 qCWarning(KWIN_WAYLAND_BACKEND) << "Failed to open drm render node" << drm_render_node; 0417 m_gbmDevice = nullptr; 0418 return; 0419 } 0420 m_gbmDevice = gbm_create_device(m_drmFileDescriptor.get()); 0421 } 0422 0423 WaylandBackend::~WaylandBackend() 0424 { 0425 if (sceneEglDisplay() != EGL_NO_DISPLAY) { 0426 eglTerminate(sceneEglDisplay()); 0427 } 0428 0429 destroyOutputs(); 0430 0431 m_seat.reset(); 0432 m_display.reset(); 0433 0434 if (m_gbmDevice) { 0435 gbm_device_destroy(m_gbmDevice); 0436 } 0437 qCDebug(KWIN_WAYLAND_BACKEND) << "Destroyed Wayland display"; 0438 } 0439 0440 bool WaylandBackend::initialize() 0441 { 0442 m_display = std::make_unique<WaylandDisplay>(); 0443 if (!m_display->initialize(m_options.socketName)) { 0444 return false; 0445 } 0446 0447 createOutputs(); 0448 0449 m_seat = std::make_unique<WaylandSeat>(m_display->seat(), this); 0450 0451 QAbstractEventDispatcher *dispatcher = QAbstractEventDispatcher::instance(); 0452 QObject::connect(dispatcher, &QAbstractEventDispatcher::aboutToBlock, m_display.get(), &WaylandDisplay::flush); 0453 QObject::connect(dispatcher, &QAbstractEventDispatcher::awake, m_display.get(), &WaylandDisplay::flush); 0454 0455 connect(this, &WaylandBackend::pointerLockChanged, this, [this](bool locked) { 0456 if (locked) { 0457 m_seat->createRelativePointer(); 0458 } else { 0459 m_seat->destroyRelativePointer(); 0460 } 0461 }); 0462 0463 return true; 0464 } 0465 0466 void WaylandBackend::createOutputs() 0467 { 0468 // we need to multiply the initial window size with the scale in order to 0469 // create an output window of this size in the end 0470 const QSize pixelSize = m_options.outputSize * m_options.outputScale; 0471 for (int i = 0; i < m_options.outputCount; i++) { 0472 WaylandOutput *output = createOutput(QStringLiteral("WL-%1").arg(i), pixelSize, m_options.outputScale); 0473 m_outputs << output; 0474 Q_EMIT outputAdded(output); 0475 output->updateEnabled(true); 0476 } 0477 0478 Q_EMIT outputsQueried(); 0479 } 0480 0481 WaylandOutput *WaylandBackend::createOutput(const QString &name, const QSize &size, qreal scale) 0482 { 0483 WaylandOutput *waylandOutput = new WaylandOutput(name, this); 0484 waylandOutput->init(size, scale); 0485 0486 // Wait until the output window is configured by the host compositor. 0487 while (!waylandOutput->isReady()) { 0488 wl_display_roundtrip(m_display->nativeDisplay()); 0489 } 0490 0491 return waylandOutput; 0492 } 0493 0494 void WaylandBackend::destroyOutputs() 0495 { 0496 while (!m_outputs.isEmpty()) { 0497 WaylandOutput *output = m_outputs.takeLast(); 0498 output->updateEnabled(false); 0499 Q_EMIT outputRemoved(output); 0500 delete output; 0501 } 0502 } 0503 0504 std::unique_ptr<InputBackend> WaylandBackend::createInputBackend() 0505 { 0506 return std::make_unique<WaylandInputBackend>(this); 0507 } 0508 0509 std::unique_ptr<OpenGLBackend> WaylandBackend::createOpenGLBackend() 0510 { 0511 return std::make_unique<WaylandEglBackend>(this); 0512 } 0513 0514 std::unique_ptr<QPainterBackend> WaylandBackend::createQPainterBackend() 0515 { 0516 return std::make_unique<WaylandQPainterBackend>(this); 0517 } 0518 0519 WaylandOutput *WaylandBackend::findOutput(KWayland::Client::Surface *nativeSurface) const 0520 { 0521 for (WaylandOutput *output : m_outputs) { 0522 if (output->surface() == nativeSurface) { 0523 return output; 0524 } 0525 } 0526 return nullptr; 0527 } 0528 0529 bool WaylandBackend::supportsPointerLock() 0530 { 0531 return m_display->pointerConstraints() && m_display->relativePointerManager(); 0532 } 0533 0534 void WaylandBackend::togglePointerLock() 0535 { 0536 if (!supportsPointerLock()) { 0537 return; 0538 } 0539 if (!m_seat) { 0540 return; 0541 } 0542 auto pointer = m_seat->pointerDevice()->nativePointer(); 0543 if (!pointer) { 0544 return; 0545 } 0546 if (m_outputs.isEmpty()) { 0547 return; 0548 } 0549 0550 for (auto output : std::as_const(m_outputs)) { 0551 output->lockPointer(m_seat->pointerDevice()->nativePointer(), !m_pointerLockRequested); 0552 } 0553 m_pointerLockRequested = !m_pointerLockRequested; 0554 } 0555 0556 QVector<CompositingType> WaylandBackend::supportedCompositors() const 0557 { 0558 QVector<CompositingType> ret; 0559 if (m_display->linuxDmabuf() && m_gbmDevice) { 0560 ret.append(OpenGLCompositing); 0561 } 0562 ret.append(QPainterCompositing); 0563 return ret; 0564 } 0565 0566 Outputs WaylandBackend::outputs() const 0567 { 0568 return m_outputs; 0569 } 0570 0571 void WaylandBackend::createDpmsFilter() 0572 { 0573 if (m_dpmsFilter) { 0574 // already another output is off 0575 return; 0576 } 0577 m_dpmsFilter = std::make_unique<DpmsInputEventFilter>(); 0578 input()->prependInputEventFilter(m_dpmsFilter.get()); 0579 } 0580 0581 void WaylandBackend::clearDpmsFilter() 0582 { 0583 m_dpmsFilter.reset(); 0584 } 0585 0586 Output *WaylandBackend::createVirtualOutput(const QString &name, const QSize &size, double scale) 0587 { 0588 return createOutput(name, size * scale, scale); 0589 } 0590 0591 void WaylandBackend::removeVirtualOutput(Output *output) 0592 { 0593 WaylandOutput *waylandOutput = dynamic_cast<WaylandOutput *>(output); 0594 if (waylandOutput && m_outputs.removeAll(waylandOutput)) { 0595 waylandOutput->updateEnabled(false); 0596 Q_EMIT outputRemoved(waylandOutput); 0597 waylandOutput->unref(); 0598 } 0599 } 0600 0601 std::optional<DmaBufParams> WaylandBackend::testCreateDmaBuf(const QSize &size, quint32 format, const QVector<uint64_t> &modifiers) 0602 { 0603 gbm_bo *bo = createGbmBo(m_gbmDevice, size, format, modifiers); 0604 if (!bo) { 0605 return {}; 0606 } 0607 0608 auto ret = dmaBufParamsForBo(bo); 0609 gbm_bo_destroy(bo); 0610 return ret; 0611 } 0612 0613 std::shared_ptr<DmaBufTexture> WaylandBackend::createDmaBufTexture(const QSize &size, quint32 format, uint64_t modifier) 0614 { 0615 gbm_bo *bo = createGbmBo(m_gbmDevice, size, format, {modifier}); 0616 if (!bo) { 0617 return {}; 0618 } 0619 0620 // The bo will be kept around until the last fd is closed. 0621 DmaBufAttributes attributes = dmaBufAttributesForBo(bo); 0622 gbm_bo_destroy(bo); 0623 m_eglBackend->makeCurrent(); 0624 return std::make_shared<DmaBufTexture>(m_eglBackend->importDmaBufAsTexture(attributes), std::move(attributes)); 0625 } 0626 0627 } 0628 0629 } // KWin