2 * Copyright (C) 2013 Intel Corporation. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "WaylandSurface.h"
29 #include "EGLHelper.h"
30 #include "GLPlatformContext.h"
31 #include "WaylandCompositor.h"
32 #include "WaylandDisplay.h"
35 static const struct wl_callback_listener frameListener = {
36 WaylandSurface::surfaceFrameCallback
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
51 WaylandSurface::WaylandSurface(struct wl_compositor* compositor)
55 , m_surfaceAttached(false)
58 static WaylandSurfaceId bufferHandleId = 0;
59 m_surface = wl_compositor_create_surface(compositor);
62 LOG_ERROR("WaylandSurface: Failed to create surface.");
67 m_id = bufferHandleId;
68 WaylandDisplay::instance()->addPendingEvent();
71 WaylandSurface::~WaylandSurface()
74 deleteFrameCallBack();
77 wl_surface_destroy(m_surface);
81 if (WaylandDisplay::instance())
82 WaylandDisplay::instance()->addPendingEvent();
85 void WaylandSurface::addFrameCallBack()
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();
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);
101 void WaylandSurface::deleteFrameCallBack()
103 if (m_frameCallBack) {
104 wl_callback_destroy(m_frameCallBack);
109 wl_event_queue_destroy(m_queue);
114 int WaylandSurface::ensureFrameCallBackDone()
117 if (m_frameCallBack) {
118 while (m_frameCallBack && ret != -1)
119 ret = wl_display_dispatch_queue(WaylandDisplay::instance()->nativeDisplay(), m_queue);
121 wl_display_dispatch_pending(WaylandDisplay::instance()->nativeDisplay());
127 void WaylandSurface::surfaceFrameCallback(void* data, struct wl_callback* callback, uint32_t)
129 WaylandSurface* surface = static_cast<WaylandSurface *>(data);
130 wl_callback_destroy(callback);
131 surface->destroyFrameCallBack();
134 void WaylandSurface::destroyFrameCallBack()
139 void WaylandSurface::ensureSurfaceMapped()
141 if (!m_surfaceAttached) {
142 WaylandDisplay::instance()->addPendingEvent();
143 m_surfaceAttached = true;
147 WaylandBuffer::WaylandBuffer(wl_client* client, uint32_t id)
148 : m_bufferResource(0)
149 , m_commitedResource(0)
150 , m_useLinearFilter(false)
156 static WaylandSurfaceId bufferHandleId = 0;
160 m_id = bufferHandleId;
162 for (i=0; i<s_maxPlaneCount; i++) {
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);
170 WaylandBuffer::~WaylandBuffer()
176 uint32_t WaylandBuffer::textureId()
178 if (m_state & PendingUpdate)
179 bindTextureToImage(true);
181 if (!m_textureIds[0]) {
182 WaylandDisplay::instance()->lock();
183 WaylandDisplay::instance()->handlePendingEvents();
184 if (!m_textureIds[0])
185 handleSurfaceCommit();
187 bindTextureToImage(true);
188 WaylandDisplay::instance()->unlock();
191 return m_textureIds[0];
194 void WaylandBuffer::mapSurface(bool useLinearFilter)
196 if ((m_state & Destroyed) || (m_state & Mapped))
200 m_useLinearFilter = useLinearFilter;
201 if (!m_textureIds[0])
202 m_state |= PendingUpdate;
205 void WaylandBuffer::unmapSurface()
211 void WaylandBuffer::release()
214 for (i=0; i<m_numPlanes; i++) {
215 glActiveTexture(GL_TEXTURE0 + i);
216 glBindTexture(GL_TEXTURE_2D, 0);
218 glDeleteTextures(1, &m_textureIds[i]);
222 glActiveTexture(GL_TEXTURE0);
227 void WaylandBuffer::attach(wl_resource* bufferResource)
229 if (m_bufferResource == bufferResource)
232 if (m_bufferResource)
233 wl_buffer_send_release(m_bufferResource);
235 m_bufferResource = bufferResource;
238 void WaylandBuffer::handleSurfaceCommit()
240 m_commitedResource = m_bufferResource;
242 if (m_commitedResource) {
243 m_state |= PendingUpdate;
249 void WaylandBuffer::bindTextureToImage(bool bindFirstTextureOnly)
253 EGLImageKHR eglImage = EGL_NO_IMAGE_KHR;
254 int bindTextureCount;
257 if (!m_commitedResource || (m_state & Destroyed))
260 if (bindFirstTextureOnly) {
261 bindTextureCount = 1;
262 m_numPlanes = bindTextureCount;
264 if (!m_textureIds[0])
265 glGenTextures(1, &m_textureIds[0]);
269 queryBufferInformation();
271 bindTextureCount = m_numPlanes;
274 display = WaylandCompositor::getInstance()->m_eglDisplay;
275 m_state &= ~PendingUpdate;
277 for (i = 0; i < bindTextureCount; i++) {
278 attribs[0] = EGL_WAYLAND_PLANE_WL;
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);
287 glActiveTexture(GL_TEXTURE0 + i);
288 glBindTexture(GL_TEXTURE_2D, m_textureIds[i]);
289 EGLHelper::imageTargetTexture2DOES(eglImage);
291 EGLHelper::destroyEGLImage(eglImage, display);
292 eglImage = EGL_NO_IMAGE_KHR;
295 m_commitedResource = 0;
298 void WaylandBuffer::updateFilter()
300 GLfloat filter = GL_NEAREST;
301 if (m_useLinearFilter)
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);
309 uint32_t WaylandBuffer::textureFormat()
312 queryBufferInformation();
317 uint32_t WaylandBuffer::totalPlanes()
320 queryBufferInformation();
325 uint32_t* WaylandBuffer::textureIds()
327 if (m_state & PendingUpdate)
328 bindTextureToImage();
330 if (!m_textureIds[0]) {
331 WaylandDisplay::instance()->lock();
332 WaylandDisplay::instance()->handlePendingEvents();
333 if (!m_textureIds[0])
334 handleSurfaceCommit();
336 bindTextureToImage();
337 WaylandDisplay::instance()->unlock();
343 void WaylandBuffer::queryBufferInformation()
347 if (!m_commitedResource || (m_state & Destroyed)) {
348 WaylandDisplay::instance()->lock();
349 WaylandDisplay::instance()->handlePendingEvents();
350 handleSurfaceCommit();
351 WaylandDisplay::instance()->unlock();
353 if (!m_commitedResource || (m_state & Destroyed))
357 EGLDisplay display = WaylandCompositor::getInstance()->m_eglDisplay;
358 if (display == EGL_NO_DISPLAY) {
359 LOG_ERROR("No Valid EGLDisplay connection.");
363 m_format = EGLHelper::queryWaylandBufferWLFormat(wl_resource_get_user_data(m_commitedResource), display);
365 case EGL_TEXTURE_Y_UV_WL:
368 case EGL_TEXTURE_Y_U_V_WL:
371 case EGL_TEXTURE_Y_XUXV_WL:
374 case EGL_TEXTURE_RGB:
375 case EGL_TEXTURE_RGBA:
381 if (numPlanes > m_numPlanes) {
382 glGenTextures(numPlanes - m_numPlanes, &m_textureIds[m_numPlanes]);
383 } else if (numPlanes < m_numPlanes) {
385 for (i=numPlanes; i<m_numPlanes; i++) {
386 glActiveTexture(GL_TEXTURE0 + i);
387 glBindTexture(GL_TEXTURE_2D, 0);
389 glDeleteTextures(1, &m_textureIds[i]);
394 m_numPlanes = numPlanes;
397 void WaylandBuffer::surfaceCommitCallBack()
399 struct frameCallback* frameCallback;
400 struct frameCallback* next;
401 bool callbackSent = false;
404 WaylandCompositor* compositor = WaylandCompositor::getInstance();
406 time = compositor->m_time;
408 wl_list_for_each_safe(frameCallback, next, &m_callbackList, link)
410 wl_callback_send_done(frameCallback->resource, time);
411 wl_resource_destroy(frameCallback->resource);
416 wl_list_init(&m_callbackList);
419 void WaylandBuffer::destroySurface(wl_resource* resource)
421 WaylandBuffer* buffer = getBuffer(resource);
423 LOG_ERROR("Not a valid buffer");
427 if (!(buffer->m_state & WaylandBuffer::Destroyed)) {
428 buffer->m_state |= WaylandBuffer::Destroyed;
429 buffer->m_state &= ~WaylandBuffer::Mapped;
430 WaylandCompositor* compositor = WaylandCompositor::getInstance();
432 compositor->bufferDestroyed(buffer->handle());
436 void WaylandBuffer::surfaceDestroy(wl_client*, wl_resource* resource)
438 wl_resource_destroy(resource);
441 WaylandBuffer* WaylandBuffer::getBuffer(wl_resource* resource)
443 return static_cast<WaylandBuffer*>(wl_resource_get_user_data(resource));
446 void WaylandBuffer::surfaceAttach(wl_client*, wl_resource* resource, wl_resource* buffer_resource, int32_t, int32_t)
448 WaylandBuffer* buffer = getBuffer(resource);
449 buffer->attach(buffer_resource);
452 void WaylandBuffer::surfaceDamage(wl_client*, wl_resource*, int32_t, int32_t, int32_t, int32_t)
456 void WaylandBuffer::surfaceFrame(wl_client* client, wl_resource* resource, uint32_t id)
458 WaylandBuffer* buffer = getBuffer(resource);
462 struct frameCallback* callback = new frameCallback;
464 wl_resource_post_no_memory(resource);
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);
473 void WaylandBuffer::surfaceSetOpaqueRegion(wl_client*, wl_resource*, wl_resource*)
477 void WaylandBuffer::surfaceSetInputRegion(wl_client*, wl_resource*, wl_resource*)
481 void WaylandBuffer::surfaceCommit(wl_client*, wl_resource* resource)
483 WaylandBuffer* buffer = getBuffer(resource);
487 buffer->surfaceCommitCallBack();
489 if (!(buffer->m_state & WaylandBuffer::Mapped))
492 WaylandCompositor* compositor = WaylandCompositor::getInstance();
494 compositor->addBufferToPendingQueue(buffer);
497 void WaylandBuffer::surfaceSetBufferTransform(struct wl_client *, struct wl_resource *, int)
501 void WaylandBuffer::surfaceSetBufferScale(struct wl_client*, struct wl_resource*, int32_t)
505 void WaylandBuffer::destroyFrameCallback(struct wl_resource* resource)
507 struct frameCallback* callback = static_cast<struct frameCallback*>(wl_resource_get_user_data(resource));
509 wl_list_remove(&callback->link);