Inform the platform plugin when direct rendering is active
[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 #include "waylandsurfaceitem.h"
45
46 #include "wlcompositor.h"
47 #include "wlinputdevice.h"
48 #include "wlextendedsurface.h"
49 #include "wlregion.h"
50 #include "wlsubsurface.h"
51 #include "wlsurfacebuffer.h"
52 #include "wlshellsurface.h"
53
54 #include <QtCore/QDebug>
55 #include <QTouchEvent>
56
57 #include <wayland-server.h>
58
59 #ifdef QT_COMPOSITOR_WAYLAND_GL
60 #include "hardware_integration/graphicshardwareintegration.h"
61 #include <qpa/qplatformopenglcontext.h>
62 #endif
63
64 #ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT
65 #include "waylandwindowmanagerintegration.h"
66 #endif
67
68 namespace Wayland {
69
70 void destroy_surface(struct wl_resource *resource)
71 {
72     Surface *surface = resolve<Surface>(resource);
73     surface->compositor()->surfaceDestroyed(surface);
74     delete surface;
75 }
76
77 Surface::Surface(struct wl_client *client, uint32_t id, Compositor *compositor)
78     : m_compositor(compositor)
79     , m_waylandSurface(new WaylandSurface(this))
80     , m_backBuffer(0)
81     , m_frontBuffer(0)
82     , m_surfaceMapped(false)
83     , m_extendedSurface(0)
84     , m_subSurface(0)
85     , m_shellSurface(0)
86 {
87     wl_list_init(&m_frame_callback_list);
88     addClientResource(client, &base()->resource, id, &wl_surface_interface,
89             &Surface::surface_interface, destroy_surface);
90     for (int i = 0; i < buffer_pool_size; i++) {
91         m_bufferPool[i] = new SurfaceBuffer(this);
92     }
93 }
94
95 Surface::~Surface()
96 {
97     delete m_waylandSurface;
98     delete m_extendedSurface;
99     delete m_subSurface;
100     delete m_shellSurface;
101
102     for (int i = 0; i < buffer_pool_size; i++) {
103         if (!m_bufferPool[i]->pageFlipperHasBuffer())
104             delete m_bufferPool[i];
105     }
106 }
107
108 WaylandSurface::Type Surface::type() const
109 {
110     SurfaceBuffer *surfaceBuffer = currentSurfaceBuffer();
111     if (surfaceBuffer && surfaceBuffer->waylandBufferHandle()) {
112         if (surfaceBuffer->isShmBuffer()) {
113             return WaylandSurface::Shm;
114         } else {
115             return WaylandSurface::Texture;
116         }
117     }
118     return WaylandSurface::Invalid;
119 }
120
121 bool Surface::isYInverted() const
122 {
123     bool ret = false;
124     static bool negateReturn = qgetenv("QT_COMPOSITOR_NEGATE_INVERTED_Y").toInt();
125     GraphicsHardwareIntegration *graphicsHWIntegration = m_compositor->graphicsHWIntegration();
126
127 #ifdef QT_COMPOSITOR_WAYLAND_GL
128     SurfaceBuffer *surfacebuffer = currentSurfaceBuffer();
129     if (!surfacebuffer) {
130         ret = false;
131     } else if (graphicsHWIntegration && surfacebuffer->waylandBufferHandle() && type() != WaylandSurface::Shm) {
132         ret = graphicsHWIntegration->isYInverted(surfacebuffer->waylandBufferHandle());
133     } else
134 #endif
135         ret = true;
136
137     return ret != negateReturn;
138 }
139
140 bool Surface::visible() const
141 {
142
143     SurfaceBuffer *surfacebuffer = currentSurfaceBuffer();
144     return surfacebuffer->waylandBufferHandle();
145 }
146
147 QPointF Surface::pos() const
148 {
149     return m_shellSurface ? m_shellSurface->adjustedPosToTransientParent() : m_position;
150 }
151
152 QPointF Surface::nonAdjustedPos() const
153 {
154     return m_position;
155 }
156
157 void Surface::setPos(const QPointF &pos)
158 {
159     bool emitChange = pos != m_position;
160     m_position = pos;
161     if (emitChange)
162         m_waylandSurface->posChanged();
163 }
164
165 QSize Surface::size() const
166 {
167     return m_size;
168 }
169
170 void Surface::setSize(const QSize &size)
171 {
172     if (size != m_size) {
173         m_opaqueRegion = QRegion();
174         m_inputRegion = QRegion(QRect(QPoint(), size));
175         m_size = size;
176         if (m_shellSurface) {
177             m_shellSurface->adjustPosInResize();
178         }
179         m_waylandSurface->sizeChanged();
180     }
181 }
182
183 QRegion Surface::inputRegion() const
184 {
185     return m_inputRegion;
186 }
187
188 QRegion Surface::opaqueRegion() const
189 {
190     return m_opaqueRegion;
191 }
192
193 QImage Surface::image() const
194 {
195     SurfaceBuffer *surfacebuffer = currentSurfaceBuffer();
196     if (surfacebuffer && !surfacebuffer->isDestroyed() && type() == WaylandSurface::Shm) {
197         struct wl_buffer *buffer = surfacebuffer->waylandBufferHandle();
198         int stride = wl_shm_buffer_get_stride(buffer);
199         uint format = wl_shm_buffer_get_format(buffer);
200         (void) format;
201         void *data = wl_shm_buffer_get_data(buffer);
202         const uchar *char_data = static_cast<const uchar *>(data);
203         QImage img(char_data, buffer->width, buffer->height, stride, QImage::Format_ARGB32_Premultiplied);
204         return img;
205     }
206     return QImage();
207 }
208
209 #ifdef QT_COMPOSITOR_WAYLAND_GL
210 GLuint Surface::textureId(QOpenGLContext *context) const
211 {
212     const SurfaceBuffer *surfacebuffer = currentSurfaceBuffer();
213
214     if (m_compositor->graphicsHWIntegration() && type() == WaylandSurface::Texture
215          && !surfacebuffer->textureCreated()) {
216         GraphicsHardwareIntegration *hwIntegration = m_compositor->graphicsHWIntegration();
217         const_cast<SurfaceBuffer *>(surfacebuffer)->createTexture(hwIntegration,context);
218     }
219     return surfacebuffer->texture();
220 }
221 #endif // QT_COMPOSITOR_WAYLAND_GL
222
223 void Surface::sendFrameCallback()
224 {
225     SurfaceBuffer *surfacebuffer = currentSurfaceBuffer();
226     surfacebuffer->setDisplayed();
227     if (m_backBuffer) {
228         if (m_frontBuffer)
229             m_frontBuffer->disown();
230         m_frontBuffer = m_backBuffer;
231     }
232
233     bool updateNeeded = advanceBufferQueue();
234
235     uint time = Compositor::currentTimeMsecs();
236     struct wl_resource *frame_callback;
237     wl_list_for_each(frame_callback, &m_frame_callback_list, link) {
238         wl_callback_send_done(frame_callback, time);
239         wl_resource_destroy(frame_callback);
240     }
241     wl_list_init(&m_frame_callback_list);
242
243     if (updateNeeded)
244         doUpdate();
245 }
246
247 void Surface::frameFinished()
248 {
249     m_compositor->frameFinished(this);
250 }
251
252 WaylandSurface * Surface::waylandSurface() const
253 {
254     return m_waylandSurface;
255 }
256
257 QPoint Surface::lastMousePos() const
258 {
259     return m_lastLocalMousePos;
260 }
261
262 void Surface::setExtendedSurface(ExtendedSurface *extendedSurface)
263 {
264     m_extendedSurface = extendedSurface;
265     if (m_extendedSurface)
266         emit m_waylandSurface->extendedSurfaceReady();
267 }
268
269 ExtendedSurface *Surface::extendedSurface() const
270 {
271     return m_extendedSurface;
272 }
273
274 void Surface::setSubSurface(SubSurface *subSurface)
275 {
276     m_subSurface = subSurface;
277 }
278
279 SubSurface *Surface::subSurface() const
280 {
281     return m_subSurface;
282 }
283
284 void Surface::setShellSurface(ShellSurface *shellSurface)
285 {
286     m_shellSurface = shellSurface;
287 }
288
289 ShellSurface *Surface::shellSurface() const
290 {
291     return m_shellSurface;
292 }
293
294 Compositor *Surface::compositor() const
295 {
296     return m_compositor;
297 }
298
299 bool Surface::advanceBufferQueue()
300 {
301     //has current buffer been displayed,
302     //do we have another buffer in the queue
303     //and does it have a valid damage rect
304
305     if (m_bufferQueue.size()) {
306         int width = 0;
307         int height = 0;
308         if (m_backBuffer) {
309             width = m_backBuffer->width();
310             height = m_backBuffer->height();
311         }
312
313         m_backBuffer = m_bufferQueue.takeFirst();
314         while (m_backBuffer && m_backBuffer->isDestroyed()) {
315             m_backBuffer->disown();
316             m_backBuffer = m_bufferQueue.size() ? m_bufferQueue.takeFirst() : 0;
317         }
318
319         if (!m_backBuffer)
320             return false; //we have no new backbuffer;
321
322         if (m_backBuffer->waylandBufferHandle()) {
323             width = m_backBuffer->width();
324             height = m_backBuffer->height();
325         }
326         setSize(QSize(width,height));
327
328
329         if (m_backBuffer &&  (!m_subSurface || !m_subSurface->parent()) && !m_surfaceMapped) {
330             m_surfaceMapped = true;
331             emit m_waylandSurface->mapped();
332         } else if (m_backBuffer && !m_backBuffer->waylandBufferHandle() && m_surfaceMapped) {
333             m_surfaceMapped = false;
334             emit m_waylandSurface->unmapped();
335         }
336
337     } else {
338         m_backBuffer = 0;
339         return false;
340     }
341
342     return true;
343 }
344
345 void Surface::doUpdate() {
346     if (postBuffer()) {
347         WaylandSurfaceItem *surfaceItem = waylandSurface()->surfaceItem();
348         if (surfaceItem)
349             surfaceItem->setDamagedFlag(true); // avoid flicker when we switch back to composited mode
350         sendFrameCallback();
351     } else {
352         SurfaceBuffer *surfaceBuffer = currentSurfaceBuffer();
353         if (surfaceBuffer) {
354             if (surfaceBuffer->damageRect().isValid()) {
355                 m_compositor->markSurfaceAsDirty(this);
356                 emit m_waylandSurface->damaged(surfaceBuffer->damageRect());
357             }
358         }
359     }
360 }
361
362 SurfaceBuffer *Surface::createSurfaceBuffer(struct wl_buffer *buffer)
363 {
364     SurfaceBuffer *newBuffer = 0;
365     for (int i = 0; i < Surface::buffer_pool_size; i++) {
366         if (!m_bufferPool[i]->isRegisteredWithBuffer()) {
367             newBuffer = m_bufferPool[i];
368             newBuffer->initialize(buffer);
369             break;
370         }
371     }
372
373     Q_ASSERT(newBuffer);
374     return newBuffer;
375 }
376
377 bool Surface::postBuffer() {
378 #ifdef QT_COMPOSITOR_WAYLAND_GL
379     if (m_waylandSurface->handle() == m_compositor->directRenderSurface()) {
380         SurfaceBuffer *surfaceBuffer = m_backBuffer? m_backBuffer : m_frontBuffer;
381         if (surfaceBuffer && m_compositor->pageFlipper()) {
382             if (m_compositor->pageFlipper()->displayBuffer(surfaceBuffer)) {
383                 surfaceBuffer->setPageFlipperHasBuffer(true);
384                 m_compositor->setDirectRenderingActive(true);
385                 return true;
386             } else {
387                 qDebug() << "could not post buffer";
388             }
389         }
390     }
391 #endif
392     return false;
393 }
394
395 void Surface::attach(struct wl_buffer *buffer)
396 {
397     SurfaceBuffer *last = m_bufferQueue.size()?m_bufferQueue.last():0;
398     if (last) {
399         if (last->waylandBufferHandle() == buffer)
400             return;
401         if (!last->damageRect().isValid()) {
402             last->disown();
403             m_bufferQueue.takeLast();
404         }
405     }
406
407     m_bufferQueue <<  createSurfaceBuffer(buffer);
408 }
409
410 void Surface::damage(const QRect &rect)
411 {
412     SurfaceBuffer *surfaceBuffer = m_bufferQueue.isEmpty() ? currentSurfaceBuffer() : m_bufferQueue.last();
413     if (surfaceBuffer)
414         surfaceBuffer->setDamage(rect);
415     else
416         qWarning() << "Surface::damage() null buffer";
417
418     if (!m_bufferQueue.isEmpty() && !m_backBuffer)
419         advanceBufferQueue();
420
421     doUpdate();
422 }
423
424 const struct wl_surface_interface Surface::surface_interface = {
425         Surface::surface_destroy,
426         Surface::surface_attach,
427         Surface::surface_damage,
428         Surface::surface_frame,
429         Surface::surface_set_opaque_region,
430         Surface::surface_set_input_region
431 };
432
433 void Surface::surface_destroy(struct wl_client *, struct wl_resource *surface_resource)
434 {
435     wl_resource_destroy(surface_resource);
436 }
437
438 void Surface::surface_attach(struct wl_client *client, struct wl_resource *surface,
439                     struct wl_resource *buffer, int x, int y)
440 {
441     Q_UNUSED(client);
442     Q_UNUSED(x);
443     Q_UNUSED(y);
444     resolve<Surface>(surface)->attach(buffer ? reinterpret_cast<wl_buffer *>(buffer->data) : 0);
445 }
446
447 void Surface::surface_damage(struct wl_client *client, struct wl_resource *surface,
448                     int32_t x, int32_t y, int32_t width, int32_t height)
449 {
450     Q_UNUSED(client);
451     resolve<Surface>(surface)->damage(QRect(x, y, width, height));
452 }
453
454 void Surface::surface_frame(struct wl_client *client,
455                    struct wl_resource *resource,
456                    uint32_t callback)
457 {
458     Surface *surface = resolve<Surface>(resource);
459     struct wl_resource *frame_callback = wl_client_add_object(client,&wl_callback_interface,0,callback,surface);
460     wl_list_insert(&surface->m_frame_callback_list,&frame_callback->link);
461 }
462
463 void Surface::surface_set_opaque_region(struct wl_client *client, struct wl_resource *surfaceResource,
464                                         struct wl_resource *region)
465 {
466     Q_UNUSED(client);
467     Surface *surface = resolve<Surface>(surfaceResource);
468     surface->m_opaqueRegion = region ? resolve<Region>(region)->region() : QRegion();
469 }
470
471 void Surface::surface_set_input_region(struct wl_client *client, struct wl_resource *surfaceResource,
472                                        struct wl_resource *region)
473 {
474     Q_UNUSED(client);
475     Surface *surface = resolve<Surface>(surfaceResource);
476     surface->m_inputRegion = region ? resolve<Region>(region)->region() : QRegion(QRect(QPoint(), surface->size()));
477 }
478
479 void Surface::setTitle(const QString &title)
480 {
481     if (m_title != title) {
482         m_title = title;
483         emit waylandSurface()->titleChanged();
484     }
485 }
486
487 } // namespace Wayland
488