| 1 | // Copyright (C) 2017 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> |
| 2 | // Copyright (C) 2017 Jolla Ltd, author: <giulio.camuffo@jollamobile.com> |
| 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
| 4 | |
| 5 | #include <QtQml/QQmlEngine> |
| 6 | #include <QQuickWindow> |
| 7 | #if QT_CONFIG(opengl) |
| 8 | # include <QOpenGLTextureBlitter> |
| 9 | # include <QOpenGLTexture> |
| 10 | # include <QOpenGLFramebufferObject> |
| 11 | #endif |
| 12 | #include <QMatrix4x4> |
| 13 | #include <QRunnable> |
| 14 | |
| 15 | #include "qwaylandclient.h" |
| 16 | #include "qwaylandquickcompositor.h" |
| 17 | #include "qwaylandquicksurface.h" |
| 18 | #include "qwaylandquickoutput.h" |
| 19 | #include "qwaylandquickitem.h" |
| 20 | #include "qwaylandoutput.h" |
| 21 | #include <QtWaylandCompositor/private/qwaylandcompositor_p.h> |
| 22 | #include <QtWaylandCompositor/QWaylandViewporter> |
| 23 | #include "qwaylandsurfacegrabber.h" |
| 24 | |
| 25 | QT_BEGIN_NAMESPACE |
| 26 | |
| 27 | class QWaylandQuickCompositorPrivate : public QWaylandCompositorPrivate |
| 28 | { |
| 29 | public: |
| 30 | explicit QWaylandQuickCompositorPrivate(QWaylandCompositor *compositor) |
| 31 | : QWaylandCompositorPrivate(compositor) |
| 32 | , m_viewporter(new QWaylandViewporter(compositor)) |
| 33 | { |
| 34 | } |
| 35 | protected: |
| 36 | QWaylandSurface *createDefaultSurface() override |
| 37 | { |
| 38 | return new QWaylandQuickSurface(); |
| 39 | } |
| 40 | private: |
| 41 | QScopedPointer<QWaylandViewporter> m_viewporter; |
| 42 | }; |
| 43 | |
| 44 | QWaylandQuickCompositor::QWaylandQuickCompositor(QObject *parent) |
| 45 | : QWaylandCompositor(*new QWaylandQuickCompositorPrivate(this), parent) |
| 46 | { |
| 47 | } |
| 48 | |
| 49 | /*! |
| 50 | * \qmlproperty list QtWayland.Compositor::WaylandCompositor::extensions |
| 51 | * |
| 52 | * A list of extensions that the compositor advertises to its clients. For |
| 53 | * any Wayland extension the compositor should support, instantiate its component, |
| 54 | * and add it to the list of extensions. |
| 55 | * |
| 56 | * For instance, the following code would allow the clients to request \c wl_shell |
| 57 | * surfaces in the compositor using the \c wl_shell interface. |
| 58 | * |
| 59 | * \qml |
| 60 | * import QtWayland.Compositor |
| 61 | * |
| 62 | * WaylandCompositor { |
| 63 | * WlShell { |
| 64 | * // ... |
| 65 | * } |
| 66 | * } |
| 67 | * \endqml |
| 68 | */ |
| 69 | |
| 70 | void QWaylandQuickCompositor::create() |
| 71 | { |
| 72 | QWaylandCompositor::create(); |
| 73 | } |
| 74 | |
| 75 | |
| 76 | void QWaylandQuickCompositor::classBegin() |
| 77 | { |
| 78 | QWaylandCompositorPrivate::get(compositor: this)->preInit(); |
| 79 | } |
| 80 | |
| 81 | void QWaylandQuickCompositor::componentComplete() |
| 82 | { |
| 83 | create(); |
| 84 | } |
| 85 | |
| 86 | /*! |
| 87 | * Grab the surface content from the given \a buffer. |
| 88 | * Reimplemented from QWaylandCompositor::grabSurface. |
| 89 | */ |
| 90 | void QWaylandQuickCompositor::grabSurface(QWaylandSurfaceGrabber *grabber, const QWaylandBufferRef &buffer) |
| 91 | { |
| 92 | if (buffer.isSharedMemory()) { |
| 93 | QWaylandCompositor::grabSurface(grabber, buffer); |
| 94 | return; |
| 95 | } |
| 96 | |
| 97 | #if QT_CONFIG(opengl) |
| 98 | QWaylandQuickOutput *output = static_cast<QWaylandQuickOutput *>(defaultOutput()); |
| 99 | if (!output) { |
| 100 | emit grabber->failed(error: QWaylandSurfaceGrabber::RendererNotReady); |
| 101 | return; |
| 102 | } |
| 103 | |
| 104 | // We cannot grab the surface now, we need to have a current opengl context, so we |
| 105 | // need to be in the render thread |
| 106 | class GrabState : public QRunnable |
| 107 | { |
| 108 | public: |
| 109 | QWaylandSurfaceGrabber *grabber = nullptr; |
| 110 | QWaylandBufferRef buffer; |
| 111 | |
| 112 | void run() override |
| 113 | { |
| 114 | QOpenGLFramebufferObject fbo(buffer.size()); |
| 115 | fbo.bind(); |
| 116 | QOpenGLTextureBlitter blitter; |
| 117 | blitter.create(); |
| 118 | |
| 119 | glViewport(x: 0, y: 0, width: buffer.size().width(), height: buffer.size().height()); |
| 120 | |
| 121 | QOpenGLTextureBlitter::Origin surfaceOrigin = |
| 122 | buffer.origin() == QWaylandSurface::OriginTopLeft |
| 123 | ? QOpenGLTextureBlitter::OriginTopLeft |
| 124 | : QOpenGLTextureBlitter::OriginBottomLeft; |
| 125 | |
| 126 | auto texture = buffer.toOpenGLTexture(); |
| 127 | blitter.bind(target: texture->target()); |
| 128 | blitter.blit(texture: texture->textureId(), targetTransform: QMatrix4x4(), sourceOrigin: surfaceOrigin); |
| 129 | blitter.release(); |
| 130 | |
| 131 | emit grabber->success(image: fbo.toImage()); |
| 132 | } |
| 133 | }; |
| 134 | |
| 135 | GrabState *state = new GrabState; |
| 136 | state->grabber = grabber; |
| 137 | state->buffer = buffer; |
| 138 | static_cast<QQuickWindow *>(output->window())->scheduleRenderJob(job: state, schedule: QQuickWindow::AfterRenderingStage); |
| 139 | #else |
| 140 | emit grabber->failed(QWaylandSurfaceGrabber::UnknownBufferType); |
| 141 | #endif |
| 142 | } |
| 143 | |
| 144 | QT_END_NAMESPACE |
| 145 | |
| 146 | #include "moc_qwaylandquickcompositor.cpp" |
| 147 | |