Fixed the problem that the webview becomes black when loading a webpage.
[platform/framework/web/webkit-efl.git] / Source / WebCore / platform / graphics / surfaces / wayland / WaylandSurface.cpp
1 /*
2  * Copyright (C) 2013 Intel Corporation. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "WaylandSurface.h"
28
29 #include "EGLHelper.h"
30 #include "GLPlatformContext.h"
31 #include "WaylandCompositor.h"
32 #include "WaylandDisplay.h"
33
34 namespace WebCore {
35 static const struct wl_callback_listener frameListener = {
36     WaylandSurface::surfaceFrameCallback
37 };
38
39 static const struct wl_surface_interface surfaceInterface = {
40     WaylandBuffer::surfaceDestroy,
41     WaylandBuffer::surfaceAttach,
42     WaylandBuffer::surfaceDamage,
43     WaylandBuffer::surfaceFrame,
44     WaylandBuffer::surfaceSetOpaqueRegion,
45     WaylandBuffer::surfaceSetInputRegion,
46     WaylandBuffer::surfaceCommit,
47     WaylandBuffer::surfaceSetBufferTransform,
48     WaylandBuffer::surfaceSetBufferScale
49 };
50
51 WaylandSurface::WaylandSurface(struct wl_compositor* compositor)
52     : m_surface(0)
53     , m_frameCallBack(0)
54     , m_queue(0)
55     , m_surfaceAttached(false)
56     , m_id(0)
57 {
58     static WaylandSurfaceId bufferHandleId = 0;
59     m_surface = wl_compositor_create_surface(compositor);
60
61     if (!m_surface) {
62         LOG_ERROR("WaylandSurface: Failed to create surface.");
63         return;
64     }
65
66     bufferHandleId++;
67     m_id = bufferHandleId;
68     WaylandDisplay::instance()->addPendingEvent();
69 }
70
71 WaylandSurface::~WaylandSurface()
72 {
73     m_id = 0;
74     deleteFrameCallBack();
75
76     if (m_surface) {
77         wl_surface_destroy(m_surface);
78         m_surface = 0;
79     }
80
81     if (WaylandDisplay::instance())
82         WaylandDisplay::instance()->addPendingEvent();
83 }
84
85 void WaylandSurface::addFrameCallBack()
86 {
87     if (m_frameCallBack)
88         return;
89
90     if (!m_queue) {
91         m_queue = wl_display_create_queue(WaylandDisplay::instance()->nativeDisplay());
92         wl_proxy_set_queue((struct wl_proxy *)WaylandDisplay::instance()->registry(), m_queue);
93         ensureSurfaceMapped();
94     }
95
96     m_frameCallBack = wl_surface_frame(m_surface);
97     wl_callback_add_listener(m_frameCallBack, &frameListener, this);
98     wl_proxy_set_queue((struct wl_proxy *)m_frameCallBack, m_queue);
99 }
100
101 void WaylandSurface::deleteFrameCallBack()
102 {
103     if (m_frameCallBack) {
104         wl_callback_destroy(m_frameCallBack);
105         m_frameCallBack = 0;
106     }
107
108     if (m_queue) {
109         wl_event_queue_destroy(m_queue);
110         m_queue = 0;
111     }
112 }
113
114 int WaylandSurface::ensureFrameCallBackDone()
115 {
116     int ret = 0;
117     if (m_frameCallBack) {
118         while (m_frameCallBack && ret != -1)
119             ret = wl_display_dispatch_queue(WaylandDisplay::instance()->nativeDisplay(), m_queue);
120
121         wl_display_dispatch_pending(WaylandDisplay::instance()->nativeDisplay());
122     }
123
124     return ret;
125 }
126
127 void WaylandSurface::surfaceFrameCallback(void* data, struct wl_callback* callback, uint32_t)
128 {
129     WaylandSurface* surface = static_cast<WaylandSurface *>(data);
130     wl_callback_destroy(callback);
131     surface->destroyFrameCallBack();
132 }
133
134 void WaylandSurface::destroyFrameCallBack()
135 {
136     m_frameCallBack = 0;
137 }
138
139 void WaylandSurface::ensureSurfaceMapped()
140 {
141     if (!m_surfaceAttached) {
142         WaylandDisplay::instance()->addPendingEvent();
143         m_surfaceAttached = true;
144     }
145 }
146
147 WaylandBuffer::WaylandBuffer(wl_client* client, uint32_t id)
148     : m_bufferResource(0)
149     , m_commitedResource(0)
150     , m_useLinearFilter(false)
151     , m_state(Default)
152     , m_id(0)
153     , m_format(0)
154     , m_numPlanes(0)
155 {
156     static WaylandSurfaceId bufferHandleId = 0;
157     int i;
158
159     bufferHandleId++;
160     m_id = bufferHandleId;
161
162     for (i=0; i<s_maxPlaneCount; i++) {
163         m_textureIds[i] = 0;
164     }
165     wl_resource* resource = wl_resource_create(client, &wl_surface_interface, 1, id);
166     wl_resource_set_implementation(resource, &surfaceInterface, this, WaylandBuffer::destroySurface);
167     wl_list_init(&m_callbackList);
168 }
169
170 WaylandBuffer::~WaylandBuffer()
171 {
172     unmapSurface();
173     m_id = 0;
174 }
175
176 uint32_t WaylandBuffer::textureId()
177 {
178     if (m_state & PendingUpdate)
179         bindTextureToImage(true);
180
181     if (!m_textureIds[0]) {
182         WaylandDisplay::instance()->lock();
183         WaylandDisplay::instance()->handlePendingEvents();
184         if (!m_textureIds[0])
185             handleSurfaceCommit();
186
187         bindTextureToImage(true);
188         WaylandDisplay::instance()->unlock();
189     }
190
191     return m_textureIds[0];
192 }
193
194 void WaylandBuffer::mapSurface(bool useLinearFilter)
195 {
196     if ((m_state & Destroyed) || (m_state & Mapped))
197         return;
198
199     m_state |= Mapped;
200     m_useLinearFilter = useLinearFilter;
201     if (!m_textureIds[0])
202         m_state |= PendingUpdate;
203 }
204
205 void WaylandBuffer::unmapSurface()
206 {
207     m_state &= ~Mapped;
208     release();
209 }
210
211 void WaylandBuffer::release()
212 {
213     int i;
214     for (i=0; i<m_numPlanes; i++) {
215         glActiveTexture(GL_TEXTURE0 + i);
216         glBindTexture(GL_TEXTURE_2D, 0);
217         if (m_textureIds[i])
218             glDeleteTextures(1, &m_textureIds[i]);
219         m_textureIds[i] = 0;
220     }
221
222     glActiveTexture(GL_TEXTURE0);
223     m_numPlanes = 0;
224     m_format    = 0;
225 }
226
227 void WaylandBuffer::attach(wl_resource* bufferResource)
228 {
229     if (m_bufferResource == bufferResource)
230         return;
231
232     if (m_bufferResource)
233         wl_buffer_send_release(m_bufferResource);
234
235     m_bufferResource = bufferResource;
236 }
237
238 void WaylandBuffer::handleSurfaceCommit()
239 {
240     m_commitedResource = m_bufferResource;
241
242     if (m_commitedResource) {
243         m_state |= PendingUpdate;
244         m_format = 0;
245         m_numPlanes = 0;
246     }
247 }
248
249 void WaylandBuffer::bindTextureToImage(bool bindFirstTextureOnly)
250 {
251     EGLDisplay display;
252     EGLint attribs[3];
253     EGLImageKHR eglImage = EGL_NO_IMAGE_KHR;
254     int bindTextureCount;
255     int i;
256
257     if (!m_commitedResource || (m_state & Destroyed))
258         return;
259
260     if (bindFirstTextureOnly) {
261         bindTextureCount = 1;
262         m_numPlanes = bindTextureCount;
263
264         if (!m_textureIds[0])
265             glGenTextures(1, &m_textureIds[0]);
266     }
267     else {
268         if (!m_numPlanes)
269             queryBufferInformation();
270
271         bindTextureCount = m_numPlanes;
272     }
273
274     display = WaylandCompositor::getInstance()->m_eglDisplay;
275     m_state &= ~PendingUpdate;
276
277     for (i = 0; i < bindTextureCount; i++) {
278         attribs[0] = EGL_WAYLAND_PLANE_WL;
279         attribs[1] = i;
280         attribs[2] = EGL_NONE;
281         EGLHelper::createEGLImage(&eglImage, EGL_WAYLAND_BUFFER_WL, m_commitedResource, attribs, display);
282         if (eglImage == EGL_NO_IMAGE_KHR) {
283             LOG_ERROR("failed to create img for plane %d\n", i);
284             continue;
285         }
286
287         glActiveTexture(GL_TEXTURE0 + i);
288         glBindTexture(GL_TEXTURE_2D, m_textureIds[i]);
289         EGLHelper::imageTargetTexture2DOES(eglImage);
290         updateFilter();
291         EGLHelper::destroyEGLImage(eglImage, display);
292         eglImage = EGL_NO_IMAGE_KHR;
293     }
294
295     m_commitedResource = 0;
296 }
297
298 void WaylandBuffer::updateFilter()
299 {
300     GLfloat filter = GL_NEAREST;
301     if (m_useLinearFilter)
302         filter = GL_LINEAR;
303     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
304     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
305     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
306     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
307 }
308
309 uint32_t WaylandBuffer::textureFormat()
310 {
311     if (!m_format)
312         queryBufferInformation();
313
314     return m_format;
315 }
316
317 uint32_t WaylandBuffer::totalPlanes()
318 {
319     if (!m_numPlanes)
320         queryBufferInformation();
321
322     return m_numPlanes;
323 }
324
325 uint32_t* WaylandBuffer::textureIds()
326 {
327     if (m_state & PendingUpdate)
328         bindTextureToImage();
329
330     if (!m_textureIds[0]) {
331         WaylandDisplay::instance()->lock();
332         WaylandDisplay::instance()->handlePendingEvents();
333         if (!m_textureIds[0])
334             handleSurfaceCommit();
335
336         bindTextureToImage();
337         WaylandDisplay::instance()->unlock();
338     }
339
340     return m_textureIds;
341 }
342
343 void WaylandBuffer::queryBufferInformation()
344 {
345     int numPlanes = 0;
346
347     if (!m_commitedResource || (m_state & Destroyed)) {
348             WaylandDisplay::instance()->lock();
349             WaylandDisplay::instance()->handlePendingEvents();
350             handleSurfaceCommit();
351             WaylandDisplay::instance()->unlock();
352
353         if (!m_commitedResource || (m_state & Destroyed))
354             return;
355     }
356
357     EGLDisplay display = WaylandCompositor::getInstance()->m_eglDisplay;
358     if (display == EGL_NO_DISPLAY) {
359         LOG_ERROR("No Valid EGLDisplay connection.");
360         return;
361     }
362
363     m_format = EGLHelper::queryWaylandBufferWLFormat(wl_resource_get_user_data(m_commitedResource), display);
364     switch (m_format) {
365     case EGL_TEXTURE_Y_UV_WL:
366         numPlanes = 2;
367         break;
368     case EGL_TEXTURE_Y_U_V_WL:
369         numPlanes = 3;
370         break;
371     case EGL_TEXTURE_Y_XUXV_WL:
372         numPlanes = 2;
373         break;
374     case EGL_TEXTURE_RGB:
375     case EGL_TEXTURE_RGBA:
376     default:
377         numPlanes = 1;
378         break;
379     }
380
381     if (numPlanes > m_numPlanes) {
382         glGenTextures(numPlanes - m_numPlanes, &m_textureIds[m_numPlanes]);
383     } else if (numPlanes < m_numPlanes) {
384         int i;
385         for (i=numPlanes; i<m_numPlanes; i++) {
386             glActiveTexture(GL_TEXTURE0 + i);
387             glBindTexture(GL_TEXTURE_2D, 0);
388             if (m_textureIds[i])
389                 glDeleteTextures(1, &m_textureIds[i]);
390             m_textureIds[i] = 0;
391         }
392     }
393
394     m_numPlanes = numPlanes;
395 }
396
397 void WaylandBuffer::surfaceCommitCallBack()
398 {
399     struct frameCallback* frameCallback;
400     struct frameCallback* next;
401     bool callbackSent = false;
402
403     uint32_t time = 0;
404     WaylandCompositor* compositor = WaylandCompositor::getInstance();
405     if (compositor)
406         time = compositor->m_time;
407
408     wl_list_for_each_safe(frameCallback, next, &m_callbackList, link)
409     {
410         wl_callback_send_done(frameCallback->resource, time);
411         wl_resource_destroy(frameCallback->resource);
412         callbackSent = true;
413     }
414
415     if (callbackSent)
416         wl_list_init(&m_callbackList);
417 }
418
419 void WaylandBuffer::destroySurface(wl_resource* resource)
420 {
421     WaylandBuffer* buffer = getBuffer(resource);
422     if (!buffer) {
423         LOG_ERROR("Not a valid buffer");
424         return;
425     }
426
427     if (!(buffer->m_state & WaylandBuffer::Destroyed)) {
428         buffer->m_state |= WaylandBuffer::Destroyed;
429         buffer->m_state &= ~WaylandBuffer::Mapped;
430         WaylandCompositor* compositor = WaylandCompositor::getInstance();
431         if (compositor)
432             compositor->bufferDestroyed(buffer->handle());
433     }
434 }
435
436 void WaylandBuffer::surfaceDestroy(wl_client*, wl_resource* resource)
437 {
438     wl_resource_destroy(resource);
439 }
440
441 WaylandBuffer* WaylandBuffer::getBuffer(wl_resource* resource)
442 {
443     return static_cast<WaylandBuffer*>(wl_resource_get_user_data(resource));
444 }
445
446 void WaylandBuffer::surfaceAttach(wl_client*, wl_resource* resource, wl_resource* buffer_resource, int32_t, int32_t)
447 {
448     WaylandBuffer* buffer = getBuffer(resource);
449     buffer->attach(buffer_resource);
450 }
451
452 void WaylandBuffer::surfaceDamage(wl_client*, wl_resource*, int32_t, int32_t, int32_t, int32_t)
453 {
454 }
455
456 void WaylandBuffer::surfaceFrame(wl_client* client, wl_resource* resource, uint32_t id)
457 {
458     WaylandBuffer* buffer = getBuffer(resource);
459     if (!buffer)
460         return;
461
462     struct frameCallback* callback = new frameCallback;
463     if (!callback) {
464         wl_resource_post_no_memory(resource);
465         return;
466     }
467
468     callback->resource = wl_resource_create(client, &wl_callback_interface, 1, id);
469     wl_resource_set_implementation(callback->resource, 0, callback, WaylandBuffer::destroyFrameCallback);
470     wl_list_insert(buffer->m_callbackList.prev, &callback->link);
471 }
472
473 void WaylandBuffer::surfaceSetOpaqueRegion(wl_client*, wl_resource*, wl_resource*)
474 {
475 }
476
477 void WaylandBuffer::surfaceSetInputRegion(wl_client*, wl_resource*, wl_resource*)
478 {
479 }
480
481 void WaylandBuffer::surfaceCommit(wl_client*, wl_resource* resource)
482 {
483     WaylandBuffer* buffer = getBuffer(resource);
484     if (!buffer)
485         return;
486
487     buffer->surfaceCommitCallBack();
488
489     if (!(buffer->m_state & WaylandBuffer::Mapped))
490         return;
491
492     WaylandCompositor* compositor = WaylandCompositor::getInstance();
493     if (compositor)
494         compositor->addBufferToPendingQueue(buffer);
495 }
496
497 void WaylandBuffer::surfaceSetBufferTransform(struct wl_client *, struct wl_resource *, int)
498 {
499 }
500
501 void WaylandBuffer::surfaceSetBufferScale(struct wl_client*, struct wl_resource*, int32_t)
502 {
503 }
504
505 void WaylandBuffer::destroyFrameCallback(struct wl_resource* resource)
506 {
507     struct frameCallback* callback = static_cast<struct frameCallback*>(wl_resource_get_user_data(resource));
508     if (callback) {
509         wl_list_remove(&callback->link);
510         delete callback;
511     }
512 }
513
514 }