File indexing completed on 2024-11-10 04:56:33
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 #include "input.h" 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 <KWayland/Client/keyboard.h> 0019 #include <KWayland/Client/pointer.h> 0020 #include <KWayland/Client/pointergestures.h> 0021 #include <KWayland/Client/relativepointer.h> 0022 #include <KWayland/Client/seat.h> 0023 #include <KWayland/Client/surface.h> 0024 #include <KWayland/Client/touch.h> 0025 0026 #include <QAbstractEventDispatcher> 0027 0028 #include <drm_fourcc.h> 0029 #include <fcntl.h> 0030 #include <gbm.h> 0031 #include <linux/input.h> 0032 #include <unistd.h> 0033 #include <wayland-client-core.h> 0034 0035 #include "wayland-linux-dmabuf-unstable-v1-client-protocol.h" 0036 0037 namespace KWin 0038 { 0039 namespace Wayland 0040 { 0041 0042 using namespace KWayland::Client; 0043 0044 inline static QPointF sizeToPoint(const QSizeF &size) 0045 { 0046 return QPointF(size.width(), size.height()); 0047 } 0048 0049 WaylandInputDevice::WaylandInputDevice(KWayland::Client::Keyboard *keyboard, WaylandSeat *seat) 0050 : m_seat(seat) 0051 , m_keyboard(keyboard) 0052 { 0053 connect(keyboard, &Keyboard::left, this, [this](quint32 time) { 0054 for (quint32 key : std::as_const(m_pressedKeys)) { 0055 Q_EMIT keyChanged(key, InputRedirection::KeyboardKeyReleased, std::chrono::milliseconds(time), this); 0056 } 0057 m_pressedKeys.clear(); 0058 }); 0059 connect(keyboard, &Keyboard::keyChanged, this, [this](quint32 key, Keyboard::KeyState nativeState, quint32 time) { 0060 InputRedirection::KeyboardKeyState state; 0061 switch (nativeState) { 0062 case Keyboard::KeyState::Pressed: 0063 if (key == KEY_RIGHTCTRL) { 0064 m_seat->backend()->togglePointerLock(); 0065 } 0066 state = InputRedirection::KeyboardKeyPressed; 0067 m_pressedKeys.insert(key); 0068 break; 0069 case Keyboard::KeyState::Released: 0070 m_pressedKeys.remove(key); 0071 state = InputRedirection::KeyboardKeyReleased; 0072 break; 0073 default: 0074 Q_UNREACHABLE(); 0075 } 0076 Q_EMIT keyChanged(key, state, std::chrono::milliseconds(time), this); 0077 }); 0078 } 0079 0080 WaylandInputDevice::WaylandInputDevice(KWayland::Client::Pointer *pointer, WaylandSeat *seat) 0081 : m_seat(seat) 0082 , m_pointer(pointer) 0083 { 0084 connect(pointer, &Pointer::entered, this, [this](quint32 serial, const QPointF &relativeToSurface) { 0085 WaylandOutput *output = m_seat->backend()->findOutput(m_pointer->enteredSurface()); 0086 Q_ASSERT(output); 0087 output->cursor()->setPointer(m_pointer.get()); 0088 }); 0089 connect(pointer, &Pointer::left, this, [this]() { 0090 // wl_pointer.leave carries the wl_surface, but KWayland::Client::Pointer::left does not. 0091 const auto outputs = m_seat->backend()->outputs(); 0092 for (Output *output : outputs) { 0093 WaylandOutput *waylandOutput = static_cast<WaylandOutput *>(output); 0094 if (waylandOutput->cursor()->pointer()) { 0095 waylandOutput->cursor()->setPointer(nullptr); 0096 } 0097 } 0098 }); 0099 connect(pointer, &Pointer::motion, this, [this](const QPointF &relativeToSurface, quint32 time) { 0100 WaylandOutput *output = m_seat->backend()->findOutput(m_pointer->enteredSurface()); 0101 Q_ASSERT(output); 0102 const QPointF absolutePos = output->geometry().topLeft() + relativeToSurface; 0103 Q_EMIT pointerMotionAbsolute(absolutePos, std::chrono::milliseconds(time), this); 0104 }); 0105 connect(pointer, &Pointer::buttonStateChanged, this, [this](quint32 serial, quint32 time, quint32 button, Pointer::ButtonState nativeState) { 0106 InputRedirection::PointerButtonState state; 0107 switch (nativeState) { 0108 case Pointer::ButtonState::Pressed: 0109 state = InputRedirection::PointerButtonPressed; 0110 break; 0111 case Pointer::ButtonState::Released: 0112 state = InputRedirection::PointerButtonReleased; 0113 break; 0114 default: 0115 Q_UNREACHABLE(); 0116 } 0117 Q_EMIT pointerButtonChanged(button, state, std::chrono::milliseconds(time), this); 0118 }); 0119 // TODO: Send discreteDelta and source as well. 0120 connect(pointer, &Pointer::axisChanged, this, [this](quint32 time, Pointer::Axis nativeAxis, qreal delta) { 0121 InputRedirection::PointerAxis axis; 0122 switch (nativeAxis) { 0123 case Pointer::Axis::Horizontal: 0124 axis = InputRedirection::PointerAxisHorizontal; 0125 break; 0126 case Pointer::Axis::Vertical: 0127 axis = InputRedirection::PointerAxisVertical; 0128 break; 0129 default: 0130 Q_UNREACHABLE(); 0131 } 0132 Q_EMIT pointerAxisChanged(axis, delta, 0, InputRedirection::PointerAxisSourceUnknown, std::chrono::milliseconds(time), this); 0133 }); 0134 0135 connect(pointer, &Pointer::frame, this, [this]() { 0136 Q_EMIT pointerFrame(this); 0137 }); 0138 0139 KWayland::Client::PointerGestures *pointerGestures = m_seat->backend()->display()->pointerGestures(); 0140 if (pointerGestures) { 0141 m_pinchGesture.reset(pointerGestures->createPinchGesture(m_pointer.get(), this)); 0142 connect(m_pinchGesture.get(), &PointerPinchGesture::started, this, [this](quint32 serial, quint32 time) { 0143 Q_EMIT pinchGestureBegin(m_pinchGesture->fingerCount(), std::chrono::milliseconds(time), this); 0144 }); 0145 connect(m_pinchGesture.get(), &PointerPinchGesture::updated, this, [this](const QSizeF &delta, qreal scale, qreal rotation, quint32 time) { 0146 Q_EMIT pinchGestureUpdate(scale, rotation, sizeToPoint(delta), std::chrono::milliseconds(time), this); 0147 }); 0148 connect(m_pinchGesture.get(), &PointerPinchGesture::ended, this, [this](quint32 serial, quint32 time) { 0149 Q_EMIT pinchGestureEnd(std::chrono::milliseconds(time), this); 0150 }); 0151 connect(m_pinchGesture.get(), &PointerPinchGesture::cancelled, this, [this](quint32 serial, quint32 time) { 0152 Q_EMIT pinchGestureCancelled(std::chrono::milliseconds(time), this); 0153 }); 0154 0155 m_swipeGesture.reset(pointerGestures->createSwipeGesture(m_pointer.get(), this)); 0156 connect(m_swipeGesture.get(), &PointerSwipeGesture::started, this, [this](quint32 serial, quint32 time) { 0157 Q_EMIT swipeGestureBegin(m_swipeGesture->fingerCount(), std::chrono::milliseconds(time), this); 0158 }); 0159 connect(m_swipeGesture.get(), &PointerSwipeGesture::updated, this, [this](const QSizeF &delta, quint32 time) { 0160 Q_EMIT swipeGestureUpdate(sizeToPoint(delta), std::chrono::milliseconds(time), this); 0161 }); 0162 connect(m_swipeGesture.get(), &PointerSwipeGesture::ended, this, [this](quint32 serial, quint32 time) { 0163 Q_EMIT swipeGestureEnd(std::chrono::milliseconds(time), this); 0164 }); 0165 connect(m_swipeGesture.get(), &PointerSwipeGesture::cancelled, this, [this](quint32 serial, quint32 time) { 0166 Q_EMIT swipeGestureCancelled(std::chrono::milliseconds(time), this); 0167 }); 0168 } 0169 } 0170 0171 WaylandInputDevice::WaylandInputDevice(KWayland::Client::RelativePointer *relativePointer, WaylandSeat *seat) 0172 : m_seat(seat) 0173 , m_relativePointer(relativePointer) 0174 { 0175 connect(relativePointer, &RelativePointer::relativeMotion, this, [this](const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 timestamp) { 0176 Q_EMIT pointerMotion(sizeToPoint(delta), sizeToPoint(deltaNonAccelerated), std::chrono::microseconds(timestamp), this); 0177 }); 0178 } 0179 0180 WaylandInputDevice::WaylandInputDevice(KWayland::Client::Touch *touch, WaylandSeat *seat) 0181 : m_seat(seat) 0182 , m_touch(touch) 0183 { 0184 connect(touch, &Touch::sequenceCanceled, this, [this]() { 0185 Q_EMIT touchCanceled(this); 0186 }); 0187 connect(touch, &Touch::frameEnded, this, [this]() { 0188 Q_EMIT touchFrame(this); 0189 }); 0190 connect(touch, &Touch::sequenceStarted, this, [this](TouchPoint *tp) { 0191 Q_EMIT touchDown(tp->id(), tp->position(), std::chrono::milliseconds(tp->time()), this); 0192 }); 0193 connect(touch, &Touch::pointAdded, this, [this](TouchPoint *tp) { 0194 Q_EMIT touchDown(tp->id(), tp->position(), std::chrono::milliseconds(tp->time()), this); 0195 }); 0196 connect(touch, &Touch::pointRemoved, this, [this](TouchPoint *tp) { 0197 Q_EMIT touchUp(tp->id(), std::chrono::milliseconds(tp->time()), this); 0198 }); 0199 connect(touch, &Touch::pointMoved, this, [this](TouchPoint *tp) { 0200 Q_EMIT touchMotion(tp->id(), tp->position(), std::chrono::milliseconds(tp->time()), this); 0201 }); 0202 } 0203 0204 WaylandInputDevice::~WaylandInputDevice() 0205 { 0206 } 0207 0208 QString WaylandInputDevice::sysName() const 0209 { 0210 return QString(); 0211 } 0212 0213 QString WaylandInputDevice::name() const 0214 { 0215 return QString(); 0216 } 0217 0218 bool WaylandInputDevice::isEnabled() const 0219 { 0220 return true; 0221 } 0222 0223 void WaylandInputDevice::setEnabled(bool enabled) 0224 { 0225 } 0226 0227 LEDs WaylandInputDevice::leds() const 0228 { 0229 return LEDs(); 0230 } 0231 0232 void WaylandInputDevice::setLeds(LEDs leds) 0233 { 0234 } 0235 0236 bool WaylandInputDevice::isKeyboard() const 0237 { 0238 return m_keyboard != nullptr; 0239 } 0240 0241 bool WaylandInputDevice::isAlphaNumericKeyboard() const 0242 { 0243 return m_keyboard != nullptr; 0244 } 0245 0246 bool WaylandInputDevice::isPointer() const 0247 { 0248 return m_pointer || m_relativePointer; 0249 } 0250 0251 bool WaylandInputDevice::isTouchpad() const 0252 { 0253 return false; 0254 } 0255 0256 bool WaylandInputDevice::isTouch() const 0257 { 0258 return m_touch != nullptr; 0259 } 0260 0261 bool WaylandInputDevice::isTabletTool() const 0262 { 0263 return false; 0264 } 0265 0266 bool WaylandInputDevice::isTabletPad() const 0267 { 0268 return false; 0269 } 0270 0271 bool WaylandInputDevice::isTabletModeSwitch() const 0272 { 0273 return false; 0274 } 0275 0276 bool WaylandInputDevice::isLidSwitch() const 0277 { 0278 return false; 0279 } 0280 0281 KWayland::Client::Pointer *WaylandInputDevice::nativePointer() const 0282 { 0283 return m_pointer.get(); 0284 } 0285 0286 WaylandInputBackend::WaylandInputBackend(WaylandBackend *backend, QObject *parent) 0287 : InputBackend(parent) 0288 , m_backend(backend) 0289 { 0290 } 0291 0292 void WaylandInputBackend::initialize() 0293 { 0294 WaylandSeat *seat = m_backend->seat(); 0295 if (seat->relativePointerDevice()) { 0296 Q_EMIT deviceAdded(seat->relativePointerDevice()); 0297 } 0298 if (seat->pointerDevice()) { 0299 Q_EMIT deviceAdded(seat->pointerDevice()); 0300 } 0301 if (seat->keyboardDevice()) { 0302 Q_EMIT deviceAdded(seat->keyboardDevice()); 0303 } 0304 if (seat->touchDevice()) { 0305 Q_EMIT deviceAdded(seat->touchDevice()); 0306 } 0307 0308 connect(seat, &WaylandSeat::deviceAdded, this, &InputBackend::deviceAdded); 0309 connect(seat, &WaylandSeat::deviceRemoved, this, &InputBackend::deviceRemoved); 0310 } 0311 0312 WaylandSeat::WaylandSeat(KWayland::Client::Seat *nativeSeat, WaylandBackend *backend) 0313 : QObject(nullptr) 0314 , m_seat(nativeSeat) 0315 , m_backend(backend) 0316 { 0317 auto updateKeyboardDevice = [this](){ 0318 if (m_seat->hasKeyboard()) { 0319 createKeyboardDevice(); 0320 } else { 0321 destroyKeyboardDevice(); 0322 } 0323 }; 0324 0325 updateKeyboardDevice(); 0326 connect(m_seat, &Seat::hasKeyboardChanged, this, updateKeyboardDevice); 0327 0328 auto updatePointerDevice = [this]() { 0329 if (m_seat->hasPointer()) { 0330 createPointerDevice(); 0331 } else { 0332 destroyPointerDevice(); 0333 } 0334 }; 0335 0336 updatePointerDevice(); 0337 connect(m_seat, &Seat::hasPointerChanged, this, updatePointerDevice); 0338 0339 auto updateTouchDevice = [this]() { 0340 if (m_seat->hasTouch()) { 0341 createTouchDevice(); 0342 } else { 0343 destroyTouchDevice(); 0344 } 0345 }; 0346 0347 updateTouchDevice(); 0348 connect(m_seat, &Seat::hasTouchChanged, this, updateTouchDevice); 0349 } 0350 0351 WaylandSeat::~WaylandSeat() 0352 { 0353 destroyPointerDevice(); 0354 destroyKeyboardDevice(); 0355 destroyTouchDevice(); 0356 } 0357 0358 void WaylandSeat::createPointerDevice() 0359 { 0360 m_pointerDevice = std::make_unique<WaylandInputDevice>(m_seat->createPointer(), this); 0361 Q_EMIT deviceAdded(m_pointerDevice.get()); 0362 } 0363 0364 void WaylandSeat::destroyPointerDevice() 0365 { 0366 if (m_pointerDevice) { 0367 Q_EMIT deviceRemoved(m_pointerDevice.get()); 0368 destroyRelativePointer(); 0369 m_pointerDevice.reset(); 0370 } 0371 } 0372 0373 void WaylandSeat::createRelativePointer() 0374 { 0375 KWayland::Client::RelativePointerManager *manager = m_backend->display()->relativePointerManager(); 0376 if (manager) { 0377 m_relativePointerDevice = std::make_unique<WaylandInputDevice>(manager->createRelativePointer(m_pointerDevice->nativePointer()), this); 0378 Q_EMIT deviceAdded(m_relativePointerDevice.get()); 0379 } 0380 } 0381 0382 void WaylandSeat::destroyRelativePointer() 0383 { 0384 if (m_relativePointerDevice) { 0385 Q_EMIT deviceRemoved(m_relativePointerDevice.get()); 0386 m_relativePointerDevice.reset(); 0387 } 0388 } 0389 0390 void WaylandSeat::createKeyboardDevice() 0391 { 0392 m_keyboardDevice = std::make_unique<WaylandInputDevice>(m_seat->createKeyboard(), this); 0393 Q_EMIT deviceAdded(m_keyboardDevice.get()); 0394 } 0395 0396 void WaylandSeat::destroyKeyboardDevice() 0397 { 0398 if (m_keyboardDevice) { 0399 Q_EMIT deviceRemoved(m_keyboardDevice.get()); 0400 m_keyboardDevice.reset(); 0401 } 0402 } 0403 0404 void WaylandSeat::createTouchDevice() 0405 { 0406 m_touchDevice = std::make_unique<WaylandInputDevice>(m_seat->createTouch(), this); 0407 Q_EMIT deviceAdded(m_touchDevice.get()); 0408 } 0409 0410 void WaylandSeat::destroyTouchDevice() 0411 { 0412 if (m_touchDevice) { 0413 Q_EMIT deviceRemoved(m_touchDevice.get()); 0414 m_touchDevice.reset(); 0415 } 0416 } 0417 0418 WaylandBackend::WaylandBackend(const WaylandBackendOptions &options, QObject *parent) 0419 : OutputBackend(parent) 0420 , m_options(options) 0421 { 0422 } 0423 0424 WaylandBackend::~WaylandBackend() 0425 { 0426 m_eglDisplay.reset(); 0427 destroyOutputs(); 0428 0429 m_buffers.clear(); 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 if (WaylandLinuxDmabufV1 *dmabuf = m_display->linuxDmabuf()) { 0448 m_drmFileDescriptor = FileDescriptor(open(dmabuf->mainDevice(), O_RDWR | O_CLOEXEC)); 0449 if (m_drmFileDescriptor.isValid()) { 0450 m_gbmDevice = gbm_create_device(m_drmFileDescriptor.get()); 0451 } else { 0452 qCWarning(KWIN_WAYLAND_BACKEND) << "Failed to open drm render node" << dmabuf->mainDevice(); 0453 } 0454 } 0455 0456 createOutputs(); 0457 0458 m_seat = std::make_unique<WaylandSeat>(m_display->seat(), this); 0459 0460 QAbstractEventDispatcher *dispatcher = QAbstractEventDispatcher::instance(); 0461 QObject::connect(dispatcher, &QAbstractEventDispatcher::aboutToBlock, m_display.get(), &WaylandDisplay::flush); 0462 QObject::connect(dispatcher, &QAbstractEventDispatcher::awake, m_display.get(), &WaylandDisplay::flush); 0463 0464 connect(this, &WaylandBackend::pointerLockChanged, this, [this](bool locked) { 0465 if (locked) { 0466 m_seat->createRelativePointer(); 0467 } else { 0468 m_seat->destroyRelativePointer(); 0469 } 0470 }); 0471 0472 return true; 0473 } 0474 0475 void WaylandBackend::createOutputs() 0476 { 0477 // we need to multiply the initial window size with the scale in order to 0478 // create an output window of this size in the end 0479 const QSize pixelSize = m_options.outputSize * m_options.outputScale; 0480 for (int i = 0; i < m_options.outputCount; i++) { 0481 WaylandOutput *output = createOutput(QStringLiteral("WL-%1").arg(i), pixelSize, m_options.outputScale); 0482 m_outputs << output; 0483 Q_EMIT outputAdded(output); 0484 output->updateEnabled(true); 0485 } 0486 0487 Q_EMIT outputsQueried(); 0488 } 0489 0490 WaylandOutput *WaylandBackend::createOutput(const QString &name, const QSize &size, qreal scale) 0491 { 0492 WaylandOutput *waylandOutput = new WaylandOutput(name, this); 0493 waylandOutput->init(size, scale); 0494 0495 // Wait until the output window is configured by the host compositor. 0496 while (!waylandOutput->isReady()) { 0497 wl_display_roundtrip(m_display->nativeDisplay()); 0498 } 0499 0500 return waylandOutput; 0501 } 0502 0503 void WaylandBackend::destroyOutputs() 0504 { 0505 while (!m_outputs.isEmpty()) { 0506 WaylandOutput *output = m_outputs.takeLast(); 0507 output->updateEnabled(false); 0508 Q_EMIT outputRemoved(output); 0509 delete output; 0510 } 0511 } 0512 0513 std::unique_ptr<InputBackend> WaylandBackend::createInputBackend() 0514 { 0515 return std::make_unique<WaylandInputBackend>(this); 0516 } 0517 0518 std::unique_ptr<OpenGLBackend> WaylandBackend::createOpenGLBackend() 0519 { 0520 return std::make_unique<WaylandEglBackend>(this); 0521 } 0522 0523 std::unique_ptr<QPainterBackend> WaylandBackend::createQPainterBackend() 0524 { 0525 return std::make_unique<WaylandQPainterBackend>(this); 0526 } 0527 0528 WaylandOutput *WaylandBackend::findOutput(KWayland::Client::Surface *nativeSurface) const 0529 { 0530 for (WaylandOutput *output : m_outputs) { 0531 if (output->surface() == nativeSurface) { 0532 return output; 0533 } 0534 } 0535 return nullptr; 0536 } 0537 0538 bool WaylandBackend::supportsPointerLock() 0539 { 0540 return m_display->pointerConstraints() && m_display->relativePointerManager(); 0541 } 0542 0543 void WaylandBackend::togglePointerLock() 0544 { 0545 if (!supportsPointerLock()) { 0546 return; 0547 } 0548 if (!m_seat) { 0549 return; 0550 } 0551 auto pointer = m_seat->pointerDevice()->nativePointer(); 0552 if (!pointer) { 0553 return; 0554 } 0555 if (m_outputs.isEmpty()) { 0556 return; 0557 } 0558 0559 for (auto output : std::as_const(m_outputs)) { 0560 output->lockPointer(m_seat->pointerDevice()->nativePointer(), !m_pointerLockRequested); 0561 } 0562 m_pointerLockRequested = !m_pointerLockRequested; 0563 } 0564 0565 QList<CompositingType> WaylandBackend::supportedCompositors() const 0566 { 0567 QList<CompositingType> ret; 0568 if (m_display->linuxDmabuf() && m_gbmDevice) { 0569 ret.append(OpenGLCompositing); 0570 } 0571 ret.append(QPainterCompositing); 0572 return ret; 0573 } 0574 0575 Outputs WaylandBackend::outputs() const 0576 { 0577 return m_outputs; 0578 } 0579 0580 Output *WaylandBackend::createVirtualOutput(const QString &name, const QSize &size, double scale) 0581 { 0582 return createOutput(name, size * scale, scale); 0583 } 0584 0585 void WaylandBackend::removeVirtualOutput(Output *output) 0586 { 0587 WaylandOutput *waylandOutput = dynamic_cast<WaylandOutput *>(output); 0588 if (waylandOutput && m_outputs.removeAll(waylandOutput)) { 0589 waylandOutput->updateEnabled(false); 0590 Q_EMIT outputRemoved(waylandOutput); 0591 waylandOutput->unref(); 0592 } 0593 } 0594 0595 static wl_buffer *importDmaBufBuffer(WaylandDisplay *display, const DmaBufAttributes *attributes) 0596 { 0597 zwp_linux_buffer_params_v1 *params = zwp_linux_dmabuf_v1_create_params(display->linuxDmabuf()->handle()); 0598 for (int i = 0; i < attributes->planeCount; ++i) { 0599 zwp_linux_buffer_params_v1_add(params, 0600 attributes->fd[i].get(), 0601 i, 0602 attributes->offset[i], 0603 attributes->pitch[i], 0604 attributes->modifier >> 32, 0605 attributes->modifier & 0xffffffff); 0606 } 0607 0608 wl_buffer *buffer = zwp_linux_buffer_params_v1_create_immed(params, attributes->width, attributes->height, attributes->format, 0); 0609 zwp_linux_buffer_params_v1_destroy(params); 0610 0611 return buffer; 0612 } 0613 0614 static wl_buffer *importShmBuffer(WaylandDisplay *display, const ShmAttributes *attributes) 0615 { 0616 wl_shm_format format; 0617 switch (attributes->format) { 0618 case DRM_FORMAT_ARGB8888: 0619 format = WL_SHM_FORMAT_ARGB8888; 0620 break; 0621 case DRM_FORMAT_XRGB8888: 0622 format = WL_SHM_FORMAT_XRGB8888; 0623 break; 0624 default: 0625 format = static_cast<wl_shm_format>(attributes->format); 0626 break; 0627 } 0628 0629 wl_shm_pool *pool = wl_shm_create_pool(display->shm(), attributes->fd.get(), attributes->size.height() * attributes->stride); 0630 wl_buffer *buffer = wl_shm_pool_create_buffer(pool, 0631 attributes->offset, 0632 attributes->size.width(), 0633 attributes->size.height(), 0634 attributes->stride, 0635 format); 0636 wl_shm_pool_destroy(pool); 0637 0638 return buffer; 0639 } 0640 0641 wl_buffer *WaylandBackend::importBuffer(GraphicsBuffer *graphicsBuffer) 0642 { 0643 auto &buffer = m_buffers[graphicsBuffer]; 0644 if (!buffer) { 0645 wl_buffer *handle = nullptr; 0646 if (const DmaBufAttributes *attributes = graphicsBuffer->dmabufAttributes()) { 0647 handle = importDmaBufBuffer(m_display.get(), attributes); 0648 } else if (const ShmAttributes *attributes = graphicsBuffer->shmAttributes()) { 0649 handle = importShmBuffer(m_display.get(), attributes); 0650 } else { 0651 qCWarning(KWIN_WAYLAND_BACKEND) << graphicsBuffer << "has unknown type"; 0652 return nullptr; 0653 } 0654 0655 buffer = std::make_unique<WaylandBuffer>(handle, graphicsBuffer); 0656 connect(buffer.get(), &WaylandBuffer::defunct, this, [this, graphicsBuffer]() { 0657 m_buffers.erase(graphicsBuffer); 0658 }); 0659 0660 static const wl_buffer_listener listener = { 0661 .release = [](void *userData, wl_buffer *buffer) { 0662 WaylandBuffer *slot = static_cast<WaylandBuffer *>(userData); 0663 slot->unlock(); 0664 }, 0665 }; 0666 wl_buffer_add_listener(handle, &listener, buffer.get()); 0667 } 0668 0669 buffer->lock(); 0670 return buffer->handle(); 0671 } 0672 0673 void WaylandBackend::setEglDisplay(std::unique_ptr<EglDisplay> &&display) 0674 { 0675 m_eglDisplay = std::move(display); 0676 } 0677 0678 EglDisplay *WaylandBackend::sceneEglDisplayObject() const 0679 { 0680 return m_eglDisplay.get(); 0681 } 0682 0683 WaylandBuffer::WaylandBuffer(wl_buffer *handle, GraphicsBuffer *graphicsBuffer) 0684 : m_graphicsBuffer(graphicsBuffer) 0685 , m_handle(handle) 0686 { 0687 connect(graphicsBuffer, &GraphicsBuffer::destroyed, this, &WaylandBuffer::defunct); 0688 } 0689 0690 WaylandBuffer::~WaylandBuffer() 0691 { 0692 m_graphicsBuffer->disconnect(this); 0693 if (m_locked) { 0694 m_graphicsBuffer->unref(); 0695 } 0696 wl_buffer_destroy(m_handle); 0697 } 0698 0699 wl_buffer *WaylandBuffer::handle() const 0700 { 0701 return m_handle; 0702 } 0703 0704 void WaylandBuffer::lock() 0705 { 0706 if (!m_locked) { 0707 m_locked = true; 0708 m_graphicsBuffer->ref(); 0709 } 0710 } 0711 0712 void WaylandBuffer::unlock() 0713 { 0714 if (m_locked) { 0715 m_locked = false; 0716 m_graphicsBuffer->unref(); 0717 } 0718 } 0719 } 0720 0721 } // KWin 0722 0723 #include "moc_wayland_backend.cpp"