Compositor memory leak fixes
[profile/ivi/qtwayland.git] / src / compositor / wayland_wrapper / wlsurface.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the Qt Compositor.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** You may use this file under the terms of the BSD license as follows:
10 **
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
13 ** met:
14 **   * Redistributions of source code must retain the above copyright
15 **     notice, this list of conditions and the following disclaimer.
16 **   * Redistributions in binary form must reproduce the above copyright
17 **     notice, this list of conditions and the following disclaimer in
18 **     the documentation and/or other materials provided with the
19 **     distribution.
20 **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
21 **     the names of its contributors may be used to endorse or promote
22 **     products derived from this software without specific prior written
23 **     permission.
24 **
25 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40
41 #include "wlsurface.h"
42
43 #include "waylandsurface.h"
44
45 #include "wlcompositor.h"
46 #include "wlshmbuffer.h"
47 #include "wlinputdevice.h"
48 #include "wlextendedsurface.h"
49 #include "wlsubsurface.h"
50 #include "wlsurfacebuffer.h"
51 #include "wlshellsurface.h"
52
53 #include <QtCore/QDebug>
54 #include <QTouchEvent>
55
56 #include <wayland-server.h>
57
58 #ifdef QT_COMPOSITOR_WAYLAND_GL
59 #include "hardware_integration/graphicshardwareintegration.h"
60 #include <QtGui/QPlatformOpenGLContext>
61 #endif
62
63 #ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT
64 #include "waylandwindowmanagerintegration.h"
65 #endif
66
67 namespace Wayland {
68
69 void destroy_surface(struct wl_resource *resource)
70 {
71     Surface *surface = wayland_cast<Surface *>((wl_surface *)resource);
72     surface->compositor()->surfaceDestroyed(surface);
73     delete surface;
74 }
75
76 Surface::Surface(struct wl_client *client, uint32_t id, Compositor *compositor)
77     : m_compositor(compositor)
78     , m_waylandSurface(new WaylandSurface(this))
79     , m_surfaceBuffer(0)
80     , m_textureBuffer(0)
81     , m_surfaceMapped(false)
82     , m_extendedSurface(0)
83     , m_subSurface(0)
84     , m_shellSurface(0)
85 {
86     wl_list_init(&m_frame_callback_list);
87     addClientResource(client, &base()->resource, id, &wl_surface_interface,
88             &Surface::surface_interface, destroy_surface);
89 }
90
91 Surface::~Surface()
92 {
93     delete m_waylandSurface;
94     delete m_extendedSurface;
95     delete m_subSurface;
96     delete m_shellSurface;
97 }
98
99 WaylandSurface::Type Surface::type() const
100 {
101     if (m_surfaceBuffer && m_surfaceBuffer->handle()) {
102         if (m_surfaceBuffer && m_surfaceBuffer->isShmBuffer()) {
103             return WaylandSurface::Shm;
104         } else if (m_surfaceBuffer){
105             return WaylandSurface::Texture;
106         }
107     }
108     return WaylandSurface::Invalid;
109 }
110
111 bool Surface::isYInverted() const
112 {
113     bool ret = false;
114     static bool negateReturn = qgetenv("QT_COMPOSITOR_NEGATE_INVERTED_Y").toInt();
115
116 #ifdef QT_COMPOSITOR_WAYLAND_GL
117     if (!m_surfaceBuffer) {
118         ret = false;
119     } else if (m_compositor->graphicsHWIntegration() && m_surfaceBuffer->handle() && type() != WaylandSurface::Shm) {
120         ret = m_compositor->graphicsHWIntegration()->isYInverted(m_surfaceBuffer->handle());
121     } else
122 #endif
123         ret = true;
124
125     return ret != negateReturn;
126 }
127
128 bool Surface::visible() const
129 {
130     return m_surfaceBuffer && m_surfaceBuffer->handle();
131 }
132
133 QImage Surface::image() const
134 {
135     if (type() == WaylandSurface::Shm && m_surfaceBuffer && m_surfaceBuffer->handle()) {
136         ShmBuffer *shmBuffer = static_cast<ShmBuffer *>(m_surfaceBuffer->handle()->user_data);
137         //TODO SHM: m_surfaceBuffer->bufferHandled = true;
138         return shmBuffer->image();
139     }
140     return QImage();
141 }
142
143 QPointF Surface::pos() const
144 {
145     return m_position;
146 }
147
148 void Surface::setPos(const QPointF &pos)
149 {
150     bool emitChange = pos != m_position;
151     m_position = pos;
152     if (emitChange)
153         m_waylandSurface->posChanged();
154 }
155
156 QSize Surface::size() const
157 {
158     return m_size;
159 }
160
161 void Surface::setSize(const QSize &size)
162 {
163     bool emitChange = size != m_size;
164     m_size = size;
165     if (emitChange)
166         m_waylandSurface->sizeChanged();
167 }
168
169 #ifdef QT_COMPOSITOR_WAYLAND_GL
170 GLuint Surface::textureId(QOpenGLContext *context) const
171 {
172     if (!m_surfaceBuffer) {
173         return 0;
174     }
175     if (m_compositor->graphicsHWIntegration() && type() == WaylandSurface::Texture
176          && !m_surfaceBuffer->textureCreated()) {
177         Surface *that = const_cast<Surface *>(this);
178
179         if (m_textureBuffer) {
180             m_textureBuffer->destructBufferState();
181             that->m_textureBuffer = 0;
182         }
183         GraphicsHardwareIntegration *hwIntegration = m_compositor->graphicsHWIntegration();
184         that->m_textureBuffer = m_surfaceBuffer;
185         that->m_textureBuffer->setTexture(hwIntegration->createTextureFromBuffer(m_textureBuffer->handle(), context));
186     }
187     return m_textureBuffer->texture();
188 }
189 #endif // QT_COMPOSITOR_WAYLAND_GL
190
191 WaylandSurface * Surface::waylandSurface() const
192 {
193     return m_waylandSurface;
194 }
195
196 QPoint Surface::lastMousePos() const
197 {
198     return m_lastLocalMousePos;
199 }
200
201 void Surface::setExtendedSurface(ExtendedSurface *extendedSurface)
202 {
203     m_extendedSurface = extendedSurface;
204 }
205
206 ExtendedSurface *Surface::extendedSurface() const
207 {
208     return m_extendedSurface;
209 }
210
211 void Surface::setSubSurface(SubSurface *subSurface)
212 {
213     m_subSurface = subSurface;
214 }
215
216 SubSurface *Surface::subSurface() const
217 {
218     return m_subSurface;
219 }
220
221 void Surface::setShellSurface(ShellSurface *shellSurface)
222 {
223     m_shellSurface = shellSurface;
224 }
225
226 ShellSurface *Surface::shellSurface() const
227 {
228     return m_shellSurface;
229 }
230
231 Compositor *Surface::compositor() const
232 {
233     return m_compositor;
234 }
235
236 void Surface::sendFrameCallback()
237 {
238     frameFinished();
239
240     uint time = Compositor::currentTimeMsecs();
241     struct wl_resource *frame_callback;
242     wl_list_for_each(frame_callback, &m_frame_callback_list, link) {
243         wl_resource_post_event(frame_callback,WL_CALLBACK_DONE,time);
244         wl_resource_destroy(frame_callback,Compositor::currentTimeMsecs());
245     }
246
247     wl_list_init(&m_frame_callback_list);
248 }
249
250 void Surface::frameFinished()
251 {
252     m_compositor->frameFinished(this);
253 }
254
255 void Surface::doUpdate(const QRect &rect) {
256     if (postBuffer()) {
257         m_surfaceBuffer->setPosted();  // disown buffer....
258         if (m_textureBuffer) {
259             m_textureBuffer->destructBufferState();
260             m_textureBuffer = 0;
261         }
262         if (!m_bufferQueue.isEmpty()) {
263             qDebug() << "++++++++++++++++++++++++++++++++++++++++ recursive damage :-)";
264             newCurrentBuffer();
265             doUpdate(rect);
266         }
267     } else {
268         m_compositor->markSurfaceAsDirty(this);
269         emit m_waylandSurface->damaged(rect);
270     }
271 }
272
273 void Surface::newCurrentBuffer() {
274     //TODO release SHM buffer....
275     if (m_surfaceBuffer && m_surfaceBuffer->isPosted()) {
276         m_surfaceBuffer->destructBufferState();
277     } else if (m_surfaceBuffer && !m_surfaceBuffer->isDisplayed()) {
278         qDebug() << "### not skipping undisplayed buffer";
279         return;
280     }
281
282     m_surfaceBuffer = m_bufferQueue.takeFirst();
283
284     int width = 0;
285     int height = 0;
286     if (m_surfaceBuffer) {
287         width = m_surfaceBuffer->width();
288         height = m_surfaceBuffer->height();
289     }
290     setSize(QSize(width,height));
291
292     if (m_surfaceBuffer &&  (!m_subSurface || !m_subSurface->parent()) && !m_surfaceMapped) {
293         emit m_waylandSurface->mapped();
294         m_surfaceMapped = true;
295     } else if (!m_surfaceBuffer && m_surfaceMapped) {
296         emit m_waylandSurface->unmapped();
297         m_surfaceMapped = false;
298     }
299 }
300
301 SurfaceBuffer *Surface::createSurfaceBuffer(struct wl_buffer *buffer)
302 {
303     SurfaceBuffer *newBuffer = 0;
304     for (int i = 0; i < Surface::buffer_pool_size; i++) {
305         if (!m_bufferPool[i].isRegisteredWithBuffer()) {
306             newBuffer = &m_bufferPool[i];
307             newBuffer->initialize(buffer);
308             break;
309         }
310     }
311
312     Q_ASSERT(newBuffer);
313     return newBuffer;
314 }
315
316 void Surface::frameFinishedInternal() {
317     if (m_surfaceBuffer)
318         m_surfaceBuffer->setFinished();
319
320     if (!m_bufferQueue.isEmpty()) {
321         newCurrentBuffer();
322         if (m_surfaceBuffer)
323             doUpdate(m_surfaceBuffer->damageRect());
324     }
325 }
326
327 bool Surface::postBuffer() {
328 #ifdef QT_COMPOSITOR_WAYLAND_GL
329     if (m_compositor->graphicsHWIntegration() && m_waylandSurface->handle() == m_compositor->directRenderSurface()) {
330         //            qDebug() << "posting...." << bufferQueue;
331         if (m_surfaceBuffer && m_surfaceBuffer->handle() && m_compositor->graphicsHWIntegration()->postBuffer(m_surfaceBuffer->handle())) {
332             return true;
333         } else {
334             qDebug() << "could not post buffer";
335         }
336     }
337 #endif
338     return false;
339 }
340
341 void Surface::attach(struct wl_buffer *buffer)
342 {
343     static bool no_serverside_buffer_queue = qgetenv("QT_NO_SERVERSIDE_BUFFER_QUEUE").toInt();
344
345     SurfaceBuffer *newBuffer = 0;
346     if (no_serverside_buffer_queue) {
347         if (m_surfaceBuffer && !m_surfaceBuffer->textureCreated()) {
348             qDebug() << "releasing undisplayed buffer";
349             m_surfaceBuffer->destructBufferState();
350             m_surfaceBuffer = 0;
351         }
352     }
353     if (buffer) {
354         newBuffer = createSurfaceBuffer(buffer);
355     }
356
357     SurfaceBuffer *last = m_bufferQueue.size()?m_bufferQueue.last():0;
358     if (last && !last->damageRect().isValid()) {
359         last->destructBufferState();
360         m_bufferQueue.takeLast();
361     }
362     m_bufferQueue << newBuffer;
363 }
364
365 void Surface::damage(const QRect &rect)
366 {
367     if (!m_bufferQueue.isEmpty() && (!m_surfaceBuffer || m_surfaceBuffer->isFinished() || !m_surfaceBuffer->handle())) {
368             // Handle the "slow" case where we've finished the previous frame before the next damage comes.
369             newCurrentBuffer();
370             doUpdate(rect);
371     } else if (m_bufferQueue.isEmpty()) {
372         // we've receicved a second damage for the same buffer
373         doUpdate(rect);
374     } else {
375         // we're still composing the previous buffer, so just store the damage rect for later
376         SurfaceBuffer *b = m_bufferQueue.last();
377         if (b)
378             b->setDamage(rect);
379         else
380             qWarning() << "Surface::damage() null buffer";
381     }
382 }
383
384 const struct wl_surface_interface Surface::surface_interface = {
385         Surface::surface_destroy,
386         Surface::surface_attach,
387         Surface::surface_damage,
388         Surface::surface_frame
389 };
390
391 void Surface::surface_destroy(struct wl_client *, struct wl_resource *surface_resource)
392 {
393     wl_resource_destroy(surface_resource,Compositor::currentTimeMsecs());
394 }
395
396 void Surface::surface_attach(struct wl_client *client, struct wl_resource *surface,
397                     struct wl_resource *buffer, int x, int y)
398 {
399     Q_UNUSED(client);
400     Q_UNUSED(x);
401     Q_UNUSED(y);
402     reinterpret_cast<Surface *>(surface)->attach(reinterpret_cast<struct wl_buffer *>(buffer));
403 }
404
405 void Surface::surface_damage(struct wl_client *client, struct wl_resource *surface,
406                     int32_t x, int32_t y, int32_t width, int32_t height)
407 {
408     Q_UNUSED(client);
409     reinterpret_cast<Surface *>(surface)->damage(QRect(x, y, width, height));
410 }
411 void Surface::surface_frame(struct wl_client *client,
412                    struct wl_resource *resource,
413                    uint32_t callback)
414 {
415     Surface *surface = reinterpret_cast<Surface *>(resource);
416     struct wl_resource *frame_callback = wl_client_add_object(client,&wl_callback_interface,0,callback,surface);
417     wl_list_insert(&surface->m_frame_callback_list,&frame_callback->link);
418 }
419
420 } // namespace Wayland
421