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 | |