1 /****************************************************************************
2 **
3 ** Copyright (C) 2017 Jolla Ltd, author: <giulio.camuffo@jollamobile.com>
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 or (at your option) any later version
20 ** approved by the KDE Free Qt Foundation. The licenses are as published by
21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 ** included in the packaging of this file. Please review the following
23 ** information to ensure the GNU General Public License requirements will
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 **
26 ** $QT_END_LICENSE$
27 **
28 ****************************************************************************/
29 
30 #include "qwaylandview.h"
31 #include "qwaylandview_p.h"
32 #include "qwaylandsurface.h"
33 #include <QtWaylandCompositor/QWaylandSeat>
34 #include <QtWaylandCompositor/QWaylandCompositor>
35 
36 #include <QtWaylandCompositor/private/qwaylandsurface_p.h>
37 #include <QtWaylandCompositor/private/qwaylandoutput_p.h>
38 
39 #include <QtCore/QMutex>
40 
41 QT_BEGIN_NAMESPACE
42 
markSurfaceAsDestroyed(QWaylandSurface * surface)43 void QWaylandViewPrivate::markSurfaceAsDestroyed(QWaylandSurface *surface)
44 {
45     Q_Q(QWaylandView);
46     Q_ASSERT(surface == this->surface);
47 
48     setSurface(nullptr);
49     QPointer<QWaylandView> deleteGuard(q);
50     emit q->surfaceDestroyed();
51     if (!deleteGuard.isNull())
52         clearFrontBuffer();
53 }
54 
55 /*!
56  * \qmltype WaylandView
57  * \inqmlmodule QtWayland.Compositor
58  * \since 5.8
59  * \brief Represents a view of a surface on an output.
60  *
61  * The WaylandView corresponds to the presentation of a surface on a specific
62  * output, managing the buffers that contain the contents to be rendered.
63  * You can have several views into the same surface.
64  */
65 
66 /*!
67  * \class QWaylandView
68  * \inmodule QtWaylandCompositor
69  * \since 5.8
70  * \brief The QWaylandView class represents a view of a surface on an output.
71  *
72  * The QWaylandView corresponds to the presentation of a surface on a specific
73  * output, managing the buffers that contain the contents to be rendered.
74  * You can have several views into the same surface.
75  */
76 
77 /*!
78  * Constructs a QWaylandView with the given \a renderObject and \a parent.
79  */
QWaylandView(QObject * renderObject,QObject * parent)80 QWaylandView::QWaylandView(QObject *renderObject, QObject *parent)
81     : QObject(*new QWaylandViewPrivate(),parent)
82 {
83     d_func()->renderObject = renderObject;
84 }
85 
86 /*!
87  * Destroys the QWaylandView.
88  */
~QWaylandView()89 QWaylandView::~QWaylandView()
90 {
91     Q_D(QWaylandView);
92     if (d->surface) {
93         if (d->output)
94             QWaylandOutputPrivate::get(d->output)->removeView(this, d->surface);
95 
96         QWaylandSurfacePrivate::get(d->surface)->derefView(this);
97     }
98 
99 }
100 
101 /*!
102 * \internal
103 *  Didn't we decide to remove this property?
104 */
renderObject() const105 QObject *QWaylandView::renderObject() const
106 {
107     Q_D(const QWaylandView);
108     return d->renderObject;
109 }
110 
111 /*!
112  * \qmlproperty WaylandSurface QtWaylandCompositor::WaylandView::surface
113  *
114  * This property holds the surface viewed by this WaylandView.
115  */
116 
117 /*!
118  * \property QWaylandView::surface
119  *
120  * This property holds the surface viewed by this QWaylandView.
121  */
surface() const122 QWaylandSurface *QWaylandView::surface() const
123 {
124     Q_D(const QWaylandView);
125     return d->surface;
126 }
127 
128 
setSurface(QWaylandSurface * newSurface)129 void QWaylandViewPrivate::setSurface(QWaylandSurface *newSurface)
130 {
131     Q_Q(QWaylandView);
132     if (surface) {
133         QWaylandSurfacePrivate::get(surface)->derefView(q);
134         if (output)
135             QWaylandOutputPrivate::get(output)->removeView(q, surface);
136     }
137 
138     surface = newSurface;
139 
140     nextBuffer = QWaylandBufferRef();
141     nextBufferCommitted = false;
142     nextDamage = QRegion();
143 
144     if (surface) {
145         QWaylandSurfacePrivate::get(surface)->refView(q);
146         if (output)
147             QWaylandOutputPrivate::get(output)->addView(q, surface);
148     }
149 }
150 
clearFrontBuffer()151 void QWaylandViewPrivate::clearFrontBuffer()
152 {
153     if (!bufferLocked) {
154         currentBuffer = QWaylandBufferRef();
155         currentDamage = QRegion();
156     }
157 }
158 
setSurface(QWaylandSurface * newSurface)159 void QWaylandView::setSurface(QWaylandSurface *newSurface)
160 {
161     Q_D(QWaylandView);
162     if (d->surface == newSurface)
163         return;
164 
165     d->setSurface(newSurface);
166     d->clearFrontBuffer();
167     emit surfaceChanged();
168 }
169 
170 /*!
171  * \qmlproperty WaylandOutput QtWaylandCompositor::WaylandView::output
172  *
173  * This property holds the output on which this view displays its surface.
174  */
175 
176 /*!
177  * \property QWaylandView::output
178  *
179  * This property holds the output on which this view displays its surface.
180  */
output() const181 QWaylandOutput *QWaylandView::output() const
182 {
183     Q_D(const QWaylandView);
184     return d->output;
185 }
186 
setOutput(QWaylandOutput * newOutput)187 void QWaylandView::setOutput(QWaylandOutput *newOutput)
188 {
189     Q_D(QWaylandView);
190     if (d->output == newOutput)
191         return;
192 
193     if (d->output && d->surface)
194         QWaylandOutputPrivate::get(d->output)->removeView(this, d->surface);
195 
196     d->output = newOutput;
197 
198     if (d->output && d->surface)
199         QWaylandOutputPrivate::get(d->output)->addView(this, d->surface);
200 
201     emit outputChanged();
202 }
203 
204 /*!
205  * This function is called when a new \a buffer is committed to this view's surface.
206  * \a damage contains the region that is different from the current buffer, i.e. the
207  * region that needs to be updated.
208  * The new \a buffer will become current on the next call to advance().
209  *
210  * Subclasses that reimplement this function \e must call the base implementation.
211  */
bufferCommitted(const QWaylandBufferRef & buffer,const QRegion & damage)212 void QWaylandView::bufferCommitted(const QWaylandBufferRef &buffer, const QRegion &damage)
213 {
214     Q_D(QWaylandView);
215     QMutexLocker locker(&d->bufferMutex);
216     d->nextBuffer = buffer;
217     d->nextDamage = damage;
218     d->nextBufferCommitted = true;
219 }
220 
221 /*!
222  * Updates the current buffer and damage region to the latest version committed by the client.
223  * Returns true if new content was committed since the previous call to advance().
224  * Otherwise returns false.
225  *
226  * \sa currentBuffer(), currentDamage()
227  */
advance()228 bool QWaylandView::advance()
229 {
230     Q_D(QWaylandView);
231 
232     if (!d->nextBufferCommitted && !d->forceAdvanceSucceed)
233         return false;
234 
235     if (d->bufferLocked)
236         return false;
237 
238     if (d->surface && d->surface->primaryView() == this) {
239         const auto views = d->surface->views();
240         for (QWaylandView *view : views) {
241             if (view != this && view->allowDiscardFrontBuffer() && view->d_func()->currentBuffer == d->currentBuffer)
242                 view->discardCurrentBuffer();
243         }
244     }
245 
246     QMutexLocker locker(&d->bufferMutex);
247     d->forceAdvanceSucceed = false;
248     d->nextBufferCommitted = false;
249     d->currentBuffer = d->nextBuffer;
250     d->currentDamage = d->nextDamage;
251     return true;
252 }
253 
254 /*!
255  * Force the view to discard its current buffer, to allow it to be reused on the client side.
256  */
discardCurrentBuffer()257 void QWaylandView::discardCurrentBuffer()
258 {
259     Q_D(QWaylandView);
260     QMutexLocker locker(&d->bufferMutex);
261     d->currentBuffer = QWaylandBufferRef();
262     d->forceAdvanceSucceed = true;
263 }
264 
265 /*!
266  * Returns a reference to this view's current buffer.
267  */
currentBuffer()268 QWaylandBufferRef QWaylandView::currentBuffer()
269 {
270     Q_D(QWaylandView);
271     QMutexLocker locker(&d->bufferMutex);
272     return d->currentBuffer;
273 }
274 
275 /*!
276  * Returns the current damage region of this view.
277  */
currentDamage()278 QRegion QWaylandView::currentDamage()
279 {
280     Q_D(QWaylandView);
281     QMutexLocker locker(&d->bufferMutex);
282     return d->currentDamage;
283 }
284 
285 /*!
286  * \qmlproperty bool QtWaylandCompositor::WaylandView::bufferLocked
287  *
288  * This property holds whether the view's buffer is currently locked. When
289  * the buffer is locked, advance() will not advance to the next buffer and
290  * returns \c false.
291  *
292  * The default is \c false.
293  */
294 
295 /*!
296  * \property QWaylandView::bufferLocked
297  *
298  * This property holds whether the view's buffer is currently locked. When
299  * the buffer is locked, advance() will not advance to the next buffer
300  * and returns \c false.
301  *
302  * The default is \c false.
303  */
isBufferLocked() const304 bool QWaylandView::isBufferLocked() const
305 {
306     Q_D(const QWaylandView);
307     return d->bufferLocked;
308 }
309 
setBufferLocked(bool locked)310 void QWaylandView::setBufferLocked(bool locked)
311 {
312     Q_D(QWaylandView);
313     if (d->bufferLocked == locked)
314         return;
315     d->bufferLocked = locked;
316     emit bufferLockedChanged();
317 }
318 /*!
319  * \qmlproperty bool QtWaylandCompositor::WaylandView::allowDiscardFrontBuffer
320  *
321  * By default, the view locks the current buffer until advance() is called. Set this property
322  * to true to allow Qt to release the buffer when the primary view is no longer using it.
323  *
324  * This can be used to avoid the situation where a secondary view that updates on a lower
325  * frequency will throttle the frame rate of the client application.
326  */
327 
328 /*!
329  * \property QWaylandView::allowDiscardFrontBuffer
330  *
331  * By default, the view locks the current buffer until advance() is called. Set this property
332  * to \c true to allow Qt to release the buffer when the primary view is no longer using it.
333  *
334  * This can be used to avoid the situation where a secondary view that updates on a lower
335  * frequency will throttle the frame rate of the client application.
336  */
allowDiscardFrontBuffer() const337 bool QWaylandView::allowDiscardFrontBuffer() const
338 {
339     Q_D(const QWaylandView);
340     return d->allowDiscardFrontBuffer;
341 }
342 
setAllowDiscardFrontBuffer(bool discard)343 void QWaylandView::setAllowDiscardFrontBuffer(bool discard)
344 {
345     Q_D(QWaylandView);
346     if (d->allowDiscardFrontBuffer == discard)
347         return;
348     d->allowDiscardFrontBuffer = discard;
349     emit allowDiscardFrontBufferChanged();
350 }
351 
352 /*!
353  * Makes this QWaylandView the primary view for the surface.
354  *
355  * It has no effect if this QWaylandView is not holding any QWaylandSurface
356  *
357  * \sa QWaylandSurface::primaryView
358  */
setPrimary()359 void QWaylandView::setPrimary()
360 {
361     Q_D(QWaylandView);
362     if (d->surface)
363         d->surface->setPrimaryView(this);
364     else
365         qWarning("Calling setPrimary() on a QWaylandView without a surface has no effect.");
366 }
367 
368 /*!
369  * Returns true if this QWaylandView is the primary view for the QWaylandSurface
370  *
371  * \sa QWaylandSurface::primaryView
372  */
isPrimary() const373 bool QWaylandView::isPrimary() const
374 {
375     Q_D(const QWaylandView);
376     return d->surface && d->surface->primaryView() == this;
377 }
378 
379 /*!
380  * Returns the Wayland surface resource for this QWaylandView.
381  */
surfaceResource() const382 struct wl_resource *QWaylandView::surfaceResource() const
383 {
384     Q_D(const QWaylandView);
385     if (!d->surface)
386         return nullptr;
387     return d->surface->resource();
388 }
389 
390 QT_END_NAMESPACE
391