WaylandNativeWindow::WaylandNativeWindow(struct wl_egl_window *window, struct wl_display *display, const gralloc_module_t* gralloc, alloc_device_t* alloc_device) { int wayland_ok; HYBRIS_TRACE_BEGIN("wayland-platform", "create_window", ""); this->m_window = window; this->m_window->nativewindow = (void *) this; this->m_display = display; this->m_width = window->width; this->m_height = window->height; this->m_defaultWidth = window->width; this->m_defaultHeight = window->height; this->m_window->resize_callback = resize_callback; this->m_format = 1; this->wl_queue = wl_display_create_queue(display); this->frame_callback = NULL; this->registry = wl_display_get_registry(display); wl_proxy_set_queue((struct wl_proxy *) this->registry, this->wl_queue); wl_registry_add_listener(this->registry, ®istry_listener, this); wayland_ok = wayland_roundtrip(this); assert(wayland_ok >= 0); assert(this->m_android_wlegl != NULL); this->m_gralloc = gralloc; this->m_alloc = alloc_device; m_usage=GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; pthread_mutex_init(&mutex, NULL); pthread_cond_init(&cond, NULL); m_freeBufs = 0; setBufferCount(3); HYBRIS_TRACE_END("wayland-platform", "create_window", ""); }
void WaylandNativeWindow::frame() { HYBRIS_TRACE_BEGIN("wayland-platform", "frame_event", ""); this->frame_callback = NULL; HYBRIS_TRACE_END("wayland-platform", "frame_event", ""); }
int WaylandNativeWindow::cancelBuffer(BaseNativeWindowBuffer* buffer, int fenceFd){ std::list<WaylandNativeWindowBuffer *>::iterator it; WaylandNativeWindowBuffer *wnb = (WaylandNativeWindowBuffer*) buffer; lock(); HYBRIS_TRACE_BEGIN("wayland-platform", "cancelBuffer", "-%p", wnb); /* Check first that it really is our buffer */ for (it = m_bufList.begin(); it != m_bufList.end(); it++) { if ((*it) == wnb) break; } assert(it != m_bufList.end()); wnb->busy = 0; ++m_freeBufs; HYBRIS_TRACE_COUNTER("wayland-platform", "m_freeBufs", "%i", m_freeBufs); for (it = m_bufList.begin(); it != m_bufList.end(); it++) { (*it)->youngest = 0; } wnb->youngest = 1; pthread_cond_signal(&cond); HYBRIS_TRACE_END("wayland-platform", "cancelBuffer", "-%p", wnb); unlock(); return 0; }
extern "C" void eglplatformcommon_passthroughImageKHR(EGLContext *ctx, EGLenum *target, EGLClientBuffer *buffer, const EGLint **attrib_list) { #ifdef WANT_WAYLAND static int debugenvchecked = 0; if (*target == EGL_WAYLAND_BUFFER_WL) { server_wlegl_buffer *buf = server_wlegl_buffer_from((struct wl_buffer *)*buffer); HYBRIS_TRACE_BEGIN("eglplatformcommon", "Wayland_eglImageKHR", "-resource@%i", ((struct wl_buffer *)*buffer)->resource.object.id); HYBRIS_TRACE_END("eglplatformcommon", "Wayland_eglImageKHR", "-resource@%i", ((struct wl_buffer *)*buffer)->resource.object.id); if (debugenvchecked == 0) { if (getenv("HYBRIS_WAYLAND_KHR_DUMP_BUFFERS") != NULL) debugenvchecked = 2; else debugenvchecked = 1; } else if (debugenvchecked == 2) { hybris_dump_buffer_to_file((ANativeWindowBuffer *) buf->buf); } *buffer = (EGLClientBuffer) (ANativeWindowBuffer *) buf->buf; *target = EGL_NATIVE_BUFFER_ANDROID; *ctx = EGL_NO_CONTEXT; *attrib_list = NULL; } #endif }
/* * Hook called by EGL to acquire a buffer. This call may block if no * buffers are available. * * The window holds a reference to the buffer between dequeueBuffer and * either queueBuffer or cancelBuffer, so clients only need their own * reference if they might use the buffer after queueing or canceling it. * Holding a reference to a buffer after queueing or canceling it is only * allowed if a specific buffer count has been set. * * The libsync fence file descriptor returned in the int pointed to by the * fenceFd argument will refer to the fence that must signal before the * dequeued buffer may be written to. A value of -1 indicates that the * caller may access the buffer immediately without waiting on a fence. If * a valid file descriptor is returned (i.e. any value except -1) then the * caller is responsible for closing the file descriptor. * * Returns 0 on success or -errno on error. */ int HWComposerNativeWindow::dequeueBuffer(BaseNativeWindowBuffer** buffer, int *fenceFd) { HYBRIS_TRACE_BEGIN("hwcomposer-platform", "dequeueBuffer", ""); pthread_mutex_lock(&m_mutex); // Allocate buffers if the list is empty, typically on the first call if (m_bufList.empty()) allocateBuffers(); assert(!m_bufList.empty()); assert(m_nextBuffer < m_bufList.size()); // Grabe the next available buffer in the list and assign m_nextBuffer to // the next one. HWComposerNativeWindowBuffer *b = m_bufList.at(m_nextBuffer); TRACE("idx=%d, buffer=%p, fence=%d", m_nextBuffer, b, b->fenceFd); *buffer = b; m_nextBuffer++; if (m_nextBuffer >= m_bufList.size()) m_nextBuffer = 0; // assign the buffer's fence to fenceFd and close/reset our fd. int fence = b->fenceFd; if (fenceFd) *fenceFd = dup(fence); if (fence != -1) { close(b->fenceFd); b->fenceFd = -1; } pthread_mutex_unlock(&m_mutex); HYBRIS_TRACE_END("hwcomposer-platform", "dequeueBuffer", ""); return 0; }
/* * Hook called by EGL when modifications to the render buffer are done. * This unlocks and post the buffer. * * The window holds a reference to the buffer between dequeueBuffer and * either queueBuffer or cancelBuffer, so clients only need their own * reference if they might use the buffer after queueing or canceling it. * Holding a reference to a buffer after queueing or canceling it is only * allowed if a specific buffer count has been set. * * The fenceFd argument specifies a libsync fence file descriptor for a * fence that must signal before the buffer can be accessed. If the buffer * can be accessed immediately then a value of -1 should be used. The * caller must not use the file descriptor after it is passed to * queueBuffer, and the ANativeWindow implementation is responsible for * closing it. * * Returns 0 on success or -errno on error. */ int HWComposerNativeWindow::queueBuffer(BaseNativeWindowBuffer* buffer, int fenceFd) { TRACE("%lu %d", pthread_self(), fenceFd); HWComposerNativeWindowBuffer* fbnb = (HWComposerNativeWindowBuffer*) buffer; HYBRIS_TRACE_BEGIN("hwcomposer-platform", "queueBuffer", "-%p", fbnb); fbnb->fenceFd = fenceFd; pthread_mutex_lock(&_mutex); /* Front buffer hasn't yet been picked up for posting */ while (m_frontBuf && m_frontBuf->busy >= 2) { pthread_cond_wait(&_cond, &_mutex); } assert(fbnb->busy==1); fbnb->busy = 2; m_frontBuf = fbnb; m_freeBufs++; sync_wait(fenceFd, -1); ::close(fenceFd); pthread_cond_signal(&_cond); TRACE("%lu %p %p",pthread_self(), m_frontBuf, fbnb); pthread_mutex_unlock(&_mutex); HYBRIS_TRACE_END("hwcomposer-platform", "queueBuffer", "-%p", fbnb); return 0; }
void WaylandNativeWindow::releaseBuffer(struct wl_buffer *buffer) { lock(); std::list<WaylandNativeWindowBuffer *>::iterator it = posted.begin(); for (; it != posted.end(); it++) { if ((*it)->wlbuffer == buffer) break; } if (it != posted.end()) { WaylandNativeWindowBuffer* pwnb = *it; posted.erase(it); TRACE("released posted buffer: %p", buffer); pwnb->busy = 0; pthread_cond_signal(&cond); unlock(); return; } it = fronted.begin(); for (; it != fronted.end(); it++) { if ((*it)->wlbuffer == buffer) break; } assert(it != fronted.end()); WaylandNativeWindowBuffer* wnb = *it; fronted.erase(it); HYBRIS_TRACE_COUNTER("wayland-platform", "fronted.size", "%i", fronted.size()); for (it = m_bufList.begin(); it != m_bufList.end(); it++) { if ((*it) == wnb) break; } assert(it != m_bufList.end()); HYBRIS_TRACE_BEGIN("wayland-platform", "releaseBuffer", "-%p", wnb); wnb->busy = 0; ++m_freeBufs; HYBRIS_TRACE_COUNTER("wayland-platform", "m_freeBufs", "%i", m_freeBufs); for (it = m_bufList.begin(); it != m_bufList.end(); it++) { (*it)->youngest = 0; } wnb->youngest = 1; pthread_cond_signal(&cond); HYBRIS_TRACE_END("wayland-platform", "releaseBuffer", "-%p", wnb); unlock(); }
EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) { EGLBoolean ret; HYBRIS_TRACE_BEGIN("hybris-egl", "eglSwapBuffers", ""); ret = _my_eglSwapBuffersWithDamageEXT(dpy, surface, NULL, 0); HYBRIS_TRACE_END("hybris-egl", "eglSwapBuffers", ""); return ret; }
void WaylandNativeWindow::finishSwap() { int ret = 0; lock(); WaylandNativeWindowBuffer *wnb = queue.front(); if (!wnb) { wnb = m_lastBuffer; } else { queue.pop_front(); } assert(wnb); m_lastBuffer = wnb; wnb->busy = 1; ret = readQueue(false); if (this->frame_callback) { do { ret = readQueue(true); } while (this->frame_callback && ret != -1); } if (ret < 0) { HYBRIS_TRACE_END("wayland-platform", "queueBuffer_wait_for_frame_callback", "-%p", wnb); return; } if (wnb->wlbuffer == NULL) { wnb->wlbuffer_from_native_handle(m_android_wlegl, m_display, wl_queue); TRACE("%p add listener with %p inside", wnb, wnb->wlbuffer); wl_buffer_add_listener(wnb->wlbuffer, &wl_buffer_listener, this); wl_proxy_set_queue((struct wl_proxy *) wnb->wlbuffer, this->wl_queue); } if (m_swap_interval > 0) { this->frame_callback = wl_surface_frame(m_window->surface); wl_callback_add_listener(this->frame_callback, &frame_listener, this); wl_proxy_set_queue((struct wl_proxy *) this->frame_callback, this->wl_queue); } wl_surface_attach(m_window->surface, wnb->wlbuffer, 0, 0); wl_surface_damage(m_window->surface, 0, 0, wnb->width, wnb->height); wl_surface_commit(m_window->surface); // Some compositors, namely Weston, queue buffer release events instead // of sending them immediately. If a frame event is used, this should // not be a problem. Without a frame event, we need to send a sync // request to ensure that they get flushed. wl_callback_destroy(wl_display_sync(m_display)); wl_display_flush(m_display); fronted.push_back(wnb); m_window->attached_width = wnb->width; m_window->attached_height = wnb->height; m_damage_rects = NULL; m_damage_n_rects = 0; unlock(); }
EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) { EGLBoolean ret; HYBRIS_TRACE_BEGIN("hybris-egl", "eglSwapBuffers", ""); EGL_DLSYM(&_eglSwapBuffers, "eglSwapBuffers"); ret = (*_eglSwapBuffers)(dpy, surface); HYBRIS_TRACE_END("hybris-egl", "eglSwapBuffers", ""); return ret; }
EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list) { EGL_DLSYM(&_eglCreateWindowSurface, "eglCreateWindowSurface"); HYBRIS_TRACE_BEGIN("hybris-egl", "eglCreateWindowSurface", ""); struct _EGLDisplay *display = hybris_egl_display_get_mapping(dpy); win = ws_CreateWindow(win, display); assert(((struct ANativeWindowBuffer *) win)->common.magic == ANDROID_NATIVE_WINDOW_MAGIC); HYBRIS_TRACE_BEGIN("native-egl", "eglCreateWindowSurface", ""); EGLSurface result = (*_eglCreateWindowSurface)(dpy, config, win, attrib_list); HYBRIS_TRACE_END("native-egl", "eglCreateWindowSurface", ""); egl_helper_push_mapping(result, win); HYBRIS_TRACE_END("hybris-egl", "eglCreateWindowSurface", ""); return result; }
int WaylandNativeWindow::queueBuffer(BaseNativeWindowBuffer* buffer, int fenceFd) { WaylandNativeWindowBuffer *wnb = (WaylandNativeWindowBuffer*) buffer; int ret = 0; HYBRIS_TRACE_BEGIN("wayland-platform", "queueBuffer", "-%p", wnb); lock(); if (debugenvchecked == 0) { if (getenv("HYBRIS_WAYLAND_DUMP_BUFFERS") != NULL) debugenvchecked = 2; else debugenvchecked = 1; } if (debugenvchecked == 2) { HYBRIS_TRACE_BEGIN("wayland-platform", "queueBuffer_dumping_buffer", "-%p", wnb); hybris_dump_buffer_to_file(wnb->getNativeBuffer()); HYBRIS_TRACE_END("wayland-platform", "queueBuffer_dumping_buffer", "-%p", wnb); } #if ANDROID_VERSION_MAJOR>=4 && ANDROID_VERSION_MINOR>=2 HYBRIS_TRACE_BEGIN("wayland-platform", "queueBuffer_waiting_for_fence", "-%p", wnb); if (fenceFd >= 0) { sync_wait(fenceFd, -1); close(fenceFd); } HYBRIS_TRACE_END("wayland-platform", "queueBuffer_waiting_for_fence", "-%p", wnb); #endif HYBRIS_TRACE_COUNTER("wayland-platform", "fronted.size", "%i", fronted.size()); HYBRIS_TRACE_END("wayland-platform", "queueBuffer", "-%p", wnb); unlock(); return NO_ERROR; }
/* * Hook called by EGL when modifications to the render buffer are done. * This unlocks and post the buffer. * * The window holds a reference to the buffer between dequeueBuffer and * either queueBuffer or cancelBuffer, so clients only need their own * reference if they might use the buffer after queueing or canceling it. * Holding a reference to a buffer after queueing or canceling it is only * allowed if a specific buffer count has been set. * * The fenceFd argument specifies a libsync fence file descriptor for a * fence that must signal before the buffer can be accessed. If the buffer * can be accessed immediately then a value of -1 should be used. The * caller must not use the file descriptor after it is passed to * queueBuffer, and the ANativeWindow implementation is responsible for * closing it. * * Returns 0 on success or -errno on error. */ int FbDevNativeWindow::queueBuffer(BaseNativeWindowBuffer* buffer, int fenceFd) { FbDevNativeWindowBuffer* fbnb = (FbDevNativeWindowBuffer*) buffer; HYBRIS_TRACE_BEGIN("fbdev-platform", "queueBuffer", "-%p", fbnb); pthread_mutex_lock(&_mutex); assert(fbnb->busy==1); fbnb->busy = 2; pthread_mutex_unlock(&_mutex); HYBRIS_TRACE_BEGIN("fbdev-platform", "queueBuffer-post", "-%p", fbnb); int rv = m_fbDev->post(m_fbDev, fbnb->handle); if (rv!=0) { fprintf(stderr,"ERROR: fb->post(%s)\n",strerror(-rv)); } HYBRIS_TRACE_END("fbdev-platform", "queueBuffer-post", "-%p", fbnb); pthread_mutex_lock(&_mutex); fbnb->busy=0; m_frontBuf = fbnb; m_freeBufs++; TRACE("%lu %p %p",pthread_self(), m_frontBuf, fbnb); pthread_cond_signal(&_cond); pthread_mutex_unlock(&_mutex); HYBRIS_TRACE_END("fbdev-platform", "queueBuffer", "-%p", fbnb); return rv; }
EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) { EGLBoolean ret; EGLSurface surface; EGLNativeWindowType win; HYBRIS_TRACE_BEGIN("hybris-egl", "eglSwapInterval", "=%d", interval); /* Some egl implementations don't pass through the setSwapInterval * call. Since we may support various swap intervals internally, we'll * call it anyway and then give the wrapped egl implementation a chance * to chage it. */ EGL_DLSYM(&_eglGetCurrentSurface, "eglGetCurrentSurface"); surface = (*_eglGetCurrentSurface)(EGL_DRAW); if (egl_helper_has_mapping(surface)) ws_setSwapInterval(dpy, egl_helper_get_mapping(surface), interval); HYBRIS_TRACE_BEGIN("native-egl", "eglSwapInterval", "=%d", interval); EGL_DLSYM(&_eglSwapInterval, "eglSwapInterval"); ret = (*_eglSwapInterval)(dpy, interval); HYBRIS_TRACE_END("native-egl", "eglSwapInterval", ""); HYBRIS_TRACE_END("hybris-egl", "eglSwapInterval", ""); return ret; }
WaylandNativeWindow::WaylandNativeWindow(struct wl_egl_window *window, struct wl_display *display, alloc_device_t* alloc_device) : m_android_wlegl(NULL) { int wayland_ok; HYBRIS_TRACE_BEGIN("wayland-platform", "create_window", ""); this->m_window = window; this->m_window->nativewindow = (void *) this; this->m_display = display; this->m_width = window->width; this->m_height = window->height; this->m_defaultWidth = window->width; this->m_defaultHeight = window->height; this->m_window->resize_callback = resize_callback; this->m_window->free_callback = free_callback; this->m_format = 1; this->frame_callback = NULL; this->wl_queue = wl_display_create_queue(display); this->registry = wl_display_get_registry(display); this->m_android_wlegl = NULL; wl_proxy_set_queue((struct wl_proxy *) this->registry, this->wl_queue); wl_registry_add_listener(this->registry, ®istry_listener, this); const_cast<int&>(ANativeWindow::minSwapInterval) = 0; const_cast<int&>(ANativeWindow::maxSwapInterval) = 1; // This is the default as per the EGL documentation this->m_swap_interval = 1; wayland_ok = wayland_roundtrip(this); assert(wayland_ok >= 0); assert(this->m_android_wlegl != NULL); this->m_alloc = alloc_device; m_usage=GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; pthread_mutex_init(&mutex, NULL); pthread_cond_init(&cond, NULL); m_queueReads = 0; m_freeBufs = 0; m_damage_rects = NULL; m_damage_n_rects = 0; m_lastBuffer = 0; setBufferCount(3); HYBRIS_TRACE_END("wayland-platform", "create_window", ""); }
/* * Hook called by EGL when modifications to the render buffer are done. * This unlocks and post the buffer. * * The window holds a reference to the buffer between dequeueBuffer and * either queueBuffer or cancelBuffer, so clients only need their own * reference if they might use the buffer after queueing or canceling it. * Holding a reference to a buffer after queueing or canceling it is only * allowed if a specific buffer count has been set. * * The fenceFd argument specifies a libsync fence file descriptor for a * fence that must signal before the buffer can be accessed. If the buffer * can be accessed immediately then a value of -1 should be used. The * caller must not use the file descriptor after it is passed to * queueBuffer, and the ANativeWindow implementation is responsible for * closing it. * * Returns 0 on success or -errno on error. */ int HWComposerNativeWindow::queueBuffer(BaseNativeWindowBuffer* buffer, int fenceFd) { HWComposerNativeWindowBuffer* b = (HWComposerNativeWindowBuffer*) buffer; HYBRIS_TRACE_BEGIN("hwcomposer-platform", "queueBuffer", "-%p", b); TRACE("%lu %p %d", pthread_self(), buffer, fenceFd); pthread_mutex_lock(&m_mutex); assert(b->fenceFd == -1); // We reset it in dequeue, so it better be -1 still.. b->fenceFd = fenceFd; this->present(b); pthread_mutex_unlock(&m_mutex); TRACE("%lu %p %d", pthread_self(), b, b->fenceFd); HYBRIS_TRACE_END("hwcomposer-platform", "queueBuffer", "-%p", b); return 0; }
// overloads from BaseNativeWindow int WaylandNativeWindow::setSwapInterval(int interval) { TRACE("interval:%i", interval); if (interval < 0) interval = 0; if (interval > 1) interval = 1; HYBRIS_TRACE_BEGIN("wayland-platform", "swap_interval", "=%d", interval); lock(); m_swap_interval = interval; unlock(); HYBRIS_TRACE_END("wayland-platform", "swap_interval", ""); return 0; }
EGLBoolean _my_eglSwapBuffersWithDamageEXT(EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects) { EGLNativeWindowType win; EGLBoolean ret; HYBRIS_TRACE_BEGIN("hybris-egl", "eglSwapBuffersWithDamageEXT", ""); EGL_DLSYM(&_eglSwapBuffers, "eglSwapBuffers"); if (egl_helper_has_mapping(surface)) { win = egl_helper_get_mapping(surface); ws_prepareSwap(dpy, win, rects, n_rects); ret = (*_eglSwapBuffers)(dpy, surface); ws_finishSwap(dpy, win); } else { ret = (*_eglSwapBuffers)(dpy, surface); } HYBRIS_TRACE_END("hybris-egl", "eglSwapBuffersWithDamageEXT", ""); return ret; }
int FbDevNativeWindow::lockBuffer(BaseNativeWindowBuffer* buffer) { FbDevNativeWindowBuffer* fbnb = (FbDevNativeWindowBuffer*)buffer; HYBRIS_TRACE_BEGIN("fbdev-platform", "lockBuffer", "-%p", fbnb); pthread_mutex_lock(&_mutex); // wait that the buffer we're locking is not front anymore while (m_frontBuf==fbnb) { TRACE("waiting %p %p", m_frontBuf, fbnb); pthread_cond_wait(&_cond, &_mutex); } pthread_mutex_unlock(&_mutex); HYBRIS_TRACE_END("fbdev-platform", "lockBuffer", "-%p", fbnb); return NO_ERROR; }
int WaylandNativeWindow::cancelBuffer(BaseNativeWindowBuffer* buffer, int fenceFd){ std::list<WaylandNativeWindowBuffer *>::iterator it; WaylandNativeWindowBuffer *wnb = (WaylandNativeWindowBuffer*) buffer; lock(); HYBRIS_TRACE_BEGIN("wayland-platform", "cancelBuffer", "-%p", wnb); /* Check first that it really is our buffer */ for (it = m_bufList.begin(); it != m_bufList.end(); it++) { if ((*it) == wnb) break; } assert(it != m_bufList.end()); wnb->busy = 0; ++m_freeBufs; HYBRIS_TRACE_COUNTER("wayland-platform", "m_freeBufs", "%i", m_freeBufs); for (it = m_bufList.begin(); it != m_bufList.end(); it++) { (*it)->youngest = 0; } wnb->youngest = 1; if (m_queueReads != 0) { // Some thread is waiting on wl_display_dispatch_queue(), possibly waiting for a wl_buffer.release // event. Since we have now cancelled a buffer push an artificial event so that the dispatch returns // and the thread can notice the cancelled buffer. This means there is a delay of one roundtrip, // but I don't see other solution except having one dedicated thread for calling wl_display_dispatch_queue(). wl_callback_destroy(wl_display_sync(m_display)); } HYBRIS_TRACE_END("wayland-platform", "cancelBuffer", "-%p", wnb); unlock(); return 0; }
WaylandNativeWindow::WaylandNativeWindow(struct wl_egl_window *window, struct wl_display *display, android_wlegl *wlegl, alloc_device_t* alloc_device, gralloc_module_t *gralloc) : m_android_wlegl(wlegl) { int wayland_ok; HYBRIS_TRACE_BEGIN("wayland-platform", "create_window", ""); this->m_window = window; this->m_window->nativewindow = (void *) this; this->m_display = display; this->m_width = window->width; this->m_height = window->height; this->m_defaultWidth = window->width; this->m_defaultHeight = window->height; this->m_window->resize_callback = resize_callback; this->m_window->free_callback = free_callback; this->frame_callback = NULL; this->wl_queue = wl_display_create_queue(display); this->m_format = 1; const_cast<int&>(ANativeWindow::minSwapInterval) = 0; const_cast<int&>(ANativeWindow::maxSwapInterval) = 1; // This is the default as per the EGL documentation this->m_swap_interval = 1; this->m_alloc = alloc_device; m_gralloc = gralloc; m_usage=GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; pthread_mutex_init(&mutex, NULL); pthread_cond_init(&cond, NULL); m_queueReads = 0; m_freeBufs = 0; m_damage_rects = NULL; m_damage_n_rects = 0; m_lastBuffer = 0; setBufferCount(3); HYBRIS_TRACE_END("wayland-platform", "create_window", ""); }
int WaylandNativeWindow::queueBuffer(BaseNativeWindowBuffer* buffer, int fenceFd) { WaylandNativeWindowBuffer *wnb = (WaylandNativeWindowBuffer*) buffer; int ret = 0; HYBRIS_TRACE_BEGIN("wayland-platform", "queueBuffer", "-%p", wnb); lock(); wnb->busy = 1; unlock(); /* XXX locking/something is a bit fishy here */ HYBRIS_TRACE_BEGIN("wayland-platform", "queueBuffer_wait_for_frame_callback", "-%p", wnb); while (this->frame_callback && ret != -1) { ret = wl_display_dispatch_queue(m_display, this->wl_queue); } if (ret < 0) { TRACE("wl_display_dispatch_queue returned an error"); HYBRIS_TRACE_END("wayland-platform", "queueBuffer_wait_for_frame_callback", "-%p", wnb); check_fatal_error(m_display); return ret; } HYBRIS_TRACE_END("wayland-platform", "queueBuffer_wait_for_frame_callback", "-%p", wnb); lock(); if (debugenvchecked == 0) { if (getenv("HYBRIS_WAYLAND_DUMP_BUFFERS") != NULL) debugenvchecked = 2; else debugenvchecked = 1; } if (debugenvchecked == 2) { HYBRIS_TRACE_BEGIN("wayland-platform", "queueBuffer_dumping_buffer", "-%p", wnb); hybris_dump_buffer_to_file(wnb->getNativeBuffer()); HYBRIS_TRACE_END("wayland-platform", "queueBuffer_dumping_buffer", "-%p", wnb); } #if ANDROID_VERSION_MAJOR>=4 && ANDROID_VERSION_MINOR>=2 HYBRIS_TRACE_BEGIN("wayland-platform", "queueBuffer_waiting_for_fence", "-%p", wnb); sync_wait(fenceFd, -1); close(fenceFd); HYBRIS_TRACE_END("wayland-platform", "queueBuffer_waiting_for_fence", "-%p", wnb); #endif this->frame_callback = wl_surface_frame(m_window->surface); wl_callback_add_listener(this->frame_callback, &frame_listener, this); wl_proxy_set_queue((struct wl_proxy *) this->frame_callback, this->wl_queue); if (wnb->wlbuffer == NULL) { wnb->wlbuffer_from_native_handle(m_android_wlegl); TRACE("%p add listener with %p inside", wnb, wnb->wlbuffer); wl_buffer_add_listener(wnb->wlbuffer, &wl_buffer_listener, this); wl_proxy_set_queue((struct wl_proxy *) wnb->wlbuffer, this->wl_queue); } TRACE("%p DAMAGE AREA: %dx%d", wnb, wnb->width, wnb->height); HYBRIS_TRACE_BEGIN("wayland-platform", "queueBuffer_attachdamagecommit", "-resource@%i", wl_proxy_get_id((struct wl_proxy *) wnb->wlbuffer)); wl_surface_attach(m_window->surface, wnb->wlbuffer, 0, 0); wl_surface_damage(m_window->surface, 0, 0, wnb->width, wnb->height); wl_surface_commit(m_window->surface); wl_display_flush(m_display); HYBRIS_TRACE_END("wayland-platform", "queueBuffer_attachdamagecommit", "-resource@%i", wl_proxy_get_id((struct wl_proxy *) wnb->wlbuffer)); //--m_freeBufs; //pthread_cond_signal(&cond); fronted.push_back(wnb); HYBRIS_TRACE_COUNTER("wayland-platform", "fronted.size", "%i", fronted.size()); if (fronted.size() == m_bufList.size()) { HYBRIS_TRACE_BEGIN("wayland-platform", "queueBuffer_wait_for_nonfronted_buffer", "-%p", wnb); /* We have fronted all our buffers, let's wait for one of them to be free */ do { unlock(); ret = wl_display_dispatch_queue(m_display, this->wl_queue); lock(); if (ret == -1) { check_fatal_error(m_display); break; } HYBRIS_TRACE_COUNTER("wayland-platform", "fronted.size", "%i", fronted.size()); if (fronted.size() != m_bufList.size()) break; } while (1); HYBRIS_TRACE_END("wayland-platform", "queueBuffer_wait_for_nonfronted_buffer", "-%p", wnb); } HYBRIS_TRACE_END("wayland-platform", "queueBuffer", "-%p", wnb); unlock(); return NO_ERROR; }
/* * Hook called by EGL to acquire a buffer. This call may block if no * buffers are available. * * The window holds a reference to the buffer between dequeueBuffer and * either queueBuffer or cancelBuffer, so clients only need their own * reference if they might use the buffer after queueing or canceling it. * Holding a reference to a buffer after queueing or canceling it is only * allowed if a specific buffer count has been set. * * The libsync fence file descriptor returned in the int pointed to by the * fenceFd argument will refer to the fence that must signal before the * dequeued buffer may be written to. A value of -1 indicates that the * caller may access the buffer immediately without waiting on a fence. If * a valid file descriptor is returned (i.e. any value except -1) then the * caller is responsible for closing the file descriptor. * * Returns 0 on success or -errno on error. */ int HWComposerNativeWindow::dequeueBuffer(BaseNativeWindowBuffer** buffer, int *fenceFd) { HYBRIS_TRACE_BEGIN("hwcomposer-platform", "dequeueBuffer", ""); HWComposerNativeWindowBuffer* fbnb=NULL; pthread_mutex_lock(&_mutex); HYBRIS_TRACE_BEGIN("hwcomposer-platform", "dequeueBuffer-wait", ""); #if defined(DEBUG) if (m_frontBuf) TRACE("Status: Has front buf %p", m_frontBuf); std::list<HWComposerNativeWindowBuffer*>::iterator cit = m_bufList.begin(); for (; cit != m_bufList.end(); ++cit) { TRACE("Status: Buffer %p with busy %i\n", (*cit), (*cit)->busy); } #endif while (m_freeBufs==0) { pthread_cond_wait(&_cond, &_mutex); } while (1) { std::list<HWComposerNativeWindowBuffer*>::iterator it = m_bufList.begin(); for (; it != m_bufList.end(); ++it) { if (*it==m_frontBuf) continue; if ((*it)->busy==0) { TRACE("Found a free non-front buffer"); break; } } if (it == m_bufList.end()) { // have to wait once again pthread_cond_wait(&_cond, &_mutex); continue; } fbnb = *it; break; } HYBRIS_TRACE_END("hwcomposer-platform", "dequeueBuffer-wait", ""); assert(fbnb!=NULL); fbnb->busy = 1; m_freeBufs--; *buffer = fbnb; *fenceFd = -1; TRACE("%lu DONE --> %p", pthread_self(), fbnb); pthread_mutex_unlock(&_mutex); HYBRIS_TRACE_END("hwcomposer-platform", "dequeueBuffer", ""); return 0; }
int WaylandNativeWindow::lockBuffer(BaseNativeWindowBuffer* buffer){ WaylandNativeWindowBuffer *wnb = (WaylandNativeWindowBuffer*) buffer; HYBRIS_TRACE_BEGIN("wayland-platform", "lockBuffer", "-%p", wnb); HYBRIS_TRACE_END("wayland-platform", "lockBuffer", "-%p", wnb); return NO_ERROR; }
int WaylandNativeWindow::dequeueBuffer(BaseNativeWindowBuffer **buffer, int *fenceFd){ HYBRIS_TRACE_BEGIN("wayland-platform", "dequeueBuffer", ""); WaylandNativeWindowBuffer *wnb=NULL; TRACE("%p", buffer); lock(); HYBRIS_TRACE_BEGIN("wayland-platform", "dequeueBuffer_wait_for_buffer", ""); HYBRIS_TRACE_COUNTER("wayland-platform", "m_freeBufs", "%i", m_freeBufs); while (m_freeBufs==0) { HYBRIS_TRACE_COUNTER("wayland-platform", "m_freeBufs", "%i", m_freeBufs); pthread_cond_wait(&cond,&mutex); } std::list<WaylandNativeWindowBuffer *>::iterator it = m_bufList.begin(); for (; it != m_bufList.end(); it++) { if ((*it)->busy) continue; if ((*it)->youngest == 1) continue; break; } if (it==m_bufList.end()) { HYBRIS_TRACE_BEGIN("wayland-platform", "dequeueBuffer_worst_case_scenario", ""); HYBRIS_TRACE_END("wayland-platform", "dequeueBuffer_worst_case_scenario", ""); it = m_bufList.begin(); for (; it != m_bufList.end() && (*it)->busy; it++) {} } if (it==m_bufList.end()) { unlock(); HYBRIS_TRACE_BEGIN("wayland-platform", "dequeueBuffer_no_free_buffers", ""); HYBRIS_TRACE_END("wayland-platform", "dequeueBuffer_no_free_buffers", ""); TRACE("%p: no free buffers", buffer); return NO_ERROR; } wnb = *it; assert(wnb!=NULL); HYBRIS_TRACE_END("wayland-platform", "dequeueBuffer_wait_for_buffer", ""); /* If the buffer doesn't match the window anymore, re-allocate */ if (wnb->width != m_window->width || wnb->height != m_window->height || wnb->format != m_format || wnb->usage != m_usage) { TRACE("wnb:%p,win:%p %i,%i %i,%i x%x,x%x x%x,x%x", wnb,m_window, wnb->width,m_window->width, wnb->height,m_window->height, wnb->format,m_format, wnb->usage,m_usage); destroyBuffer(wnb); m_bufList.erase(it); wnb = addBuffer(); } wnb->busy = 1; *buffer = wnb; --m_freeBufs; HYBRIS_TRACE_COUNTER("wayland-platform", "m_freeBufs", "%i", m_freeBufs); HYBRIS_TRACE_BEGIN("wayland-platform", "dequeueBuffer_gotBuffer", "-%p", wnb); HYBRIS_TRACE_END("wayland-platform", "dequeueBuffer_gotBuffer", "-%p", wnb); HYBRIS_TRACE_END("wayland-platform", "dequeueBuffer_wait_for_buffer", ""); unlock(); return NO_ERROR; }
/* * Hook called by EGL to acquire a buffer. This call may block if no * buffers are available. * * The window holds a reference to the buffer between dequeueBuffer and * either queueBuffer or cancelBuffer, so clients only need their own * reference if they might use the buffer after queueing or canceling it. * Holding a reference to a buffer after queueing or canceling it is only * allowed if a specific buffer count has been set. * * The libsync fence file descriptor returned in the int pointed to by the * fenceFd argument will refer to the fence that must signal before the * dequeued buffer may be written to. A value of -1 indicates that the * caller may access the buffer immediately without waiting on a fence. If * a valid file descriptor is returned (i.e. any value except -1) then the * caller is responsible for closing the file descriptor. * * Returns 0 on success or -errno on error. */ int FbDevNativeWindow::dequeueBuffer(BaseNativeWindowBuffer** buffer, int *fenceFd) { HYBRIS_TRACE_BEGIN("fbdev-platform", "dequeueBuffer", ""); FbDevNativeWindowBuffer* fbnb=NULL; pthread_mutex_lock(&_mutex); HYBRIS_TRACE_BEGIN("fbdev-platform", "dequeueBuffer-wait", ""); #if defined(DEBUG) if (m_frontBuf) TRACE("Status: Has front buf %p", m_frontBuf); std::list<FbDevNativeWindowBuffer*>::iterator cit = m_bufList.begin(); for (; cit != m_bufList.end(); ++cit) { TRACE("Status: Buffer %p with busy %i\n", (*cit), (*cit)->busy); } #endif while (m_freeBufs==0) { pthread_cond_wait(&_cond, &_mutex); } while (1) { std::list<FbDevNativeWindowBuffer*>::iterator it = m_bufList.begin(); for (; it != m_bufList.end(); ++it) { if (*it==m_frontBuf) continue; if ((*it)->busy==0) { TRACE("Found a free non-front buffer"); break; } } if (it == m_bufList.end()) { #if ANDROID_VERSION_MAJOR<=4 && ANDROID_VERSION_MINOR<2 /* * This is acceptable in case you are on a stack that calls lock() before starting to render into buffer * When you are using fences (>= 2) you'll be waiting on the fence to signal instead. * * This optimization allows eglSwapBuffers to return and you can begin to utilize the GPU for rendering. * The actual lock() probably first comes at glFlush/eglSwapBuffers */ if (m_frontBuf && m_frontBuf->busy == 0) { TRACE("Used front buffer as buffer"); fbnb = m_frontBuf; break; } #endif // have to wait once again pthread_cond_wait(&_cond, &_mutex); continue; } fbnb = *it; break; } HYBRIS_TRACE_END("fbdev-platform", "dequeueBuffer-wait", ""); assert(fbnb!=NULL); fbnb->busy = 1; m_freeBufs--; *buffer = fbnb; *fenceFd = -1; TRACE("%lu DONE --> %p", pthread_self(), fbnb); pthread_mutex_unlock(&_mutex); HYBRIS_TRACE_END("fbdev-platform", "dequeueBuffer", ""); return 0; }