void platform_get_dimensions(EGLDisplay dpy, EGLNativeWindowType win, uint32_t *width, uint32_t *height, uint32_t *swapchain_count) { Window w = (Window) win; XWindowAttributes attr; GC gc; Status rc = XGetWindowAttributes(hacky_display, w, &attr); // check rc is OK and if it is (vcos_assert(rc == 0);?????) *width = attr.width; *height = attr.height; *swapchain_count = 0; /* Hackily assume if this function is called then they want to fill with GL stuff. So fill window with chromakey. */ vcos_log_trace("Calling XCreateGC %d",(int)w); gc = XCreateGC(hacky_display, w, 0, NULL); XSetForeground(hacky_display, gc, CHROMA_KEY_565); vcos_log_trace("Calling XFillRectangle %d %dx%d",(int)w,attr.width, attr.height); XFillRectangle(hacky_display, w, gc, 0, 0, attr.width, attr.height); vcos_log_trace("Calling XFreeGC"); XFreeGC(hacky_display, gc); vcos_log_trace("Done platform_get_dimensions"); //debugging dump_hierarchy(attr.root, w, 0, 0); }
/** Create a new vidtex instance */ static VIDTEX_T *vidtex_create(EGLNativeWindowType win) { VIDTEX_T *vt; VCOS_STATUS_T st; vt = vcos_calloc(1, sizeof(*vt), "vidtex"); if (vt == NULL) { vcos_log_trace("Memory allocation failure"); return NULL; } st = vcos_semaphore_create(&vt->sem_decoded, "vidtex-dec", 0); if (st != VCOS_SUCCESS) { vcos_log_trace("Error creating semaphore"); goto error_ctx; } st = vcos_semaphore_create(&vt->sem_drawn, "vidtex-drw", 0); if (st != VCOS_SUCCESS) { vcos_log_trace("Error creating semaphore"); goto error_sem1; } st = vcos_mutex_create(&vt->mutex, "vidtex"); if (st != VCOS_SUCCESS) { vcos_log_trace("Error creating semaphore"); goto error_sem2; } if (vidtex_gl_init(vt, win) != 0) { vcos_log_trace("Error initialising EGL"); goto error_mutex; } vt->quit = false; vt->stop_reason = 0; return vt; error_mutex: vcos_mutex_delete(&vt->mutex); error_sem2: vcos_semaphore_delete(&vt->sem_drawn); error_sem1: vcos_semaphore_delete(&vt->sem_decoded); error_ctx: vcos_free(vt); return NULL; }
void *vcos_generic_blockpool_elem_from_handle( VCOS_BLOCKPOOL_T *pool, uint32_t handle) { VCOS_BLOCKPOOL_SUBPOOL_T *subpool; uint32_t subpool_id; uint32_t index; void *ret = NULL; ASSERT_POOL(pool); vcos_mutex_lock(&pool->mutex); subpool_id = VCOS_BLOCKPOOL_HANDLE_GET_SUBPOOL(handle); if (subpool_id < pool->num_subpools) { index = VCOS_BLOCKPOOL_HANDLE_GET_INDEX(handle); subpool = &pool->subpools[subpool_id]; if (pool->subpools[subpool_id].magic == VCOS_BLOCKPOOL_SUBPOOL_MAGIC && pool->subpools[subpool_id].mem && index < subpool->num_blocks) { VCOS_BLOCKPOOL_HEADER_T *hdr = (VCOS_BLOCKPOOL_HEADER_T*) ((size_t) subpool->start + (index * pool->block_size)); if (hdr->owner.subpool == subpool) /* Check block is allocated */ ret = hdr + 1; } } vcos_mutex_unlock(&pool->mutex); vcos_log_trace("%s: pool %p handle 0x%08x elem %p", VCOS_FUNCTION, pool, handle, ret); return ret; }
VCOS_STATUS_T vcos_generic_blockpool_extend(VCOS_BLOCKPOOL_T *pool, VCOS_UNSIGNED num_extensions, VCOS_UNSIGNED num_blocks) { VCOS_UNSIGNED i; ASSERT_POOL(pool); vcos_log_trace("%s: pool %p num_extensions %d num_blocks %d", VCOS_FUNCTION, pool, num_extensions, num_blocks); /* Extend may only be called once */ if (pool->num_subpools > 1) return VCOS_EACCESS; if (num_extensions < 1 || num_extensions > VCOS_BLOCKPOOL_MAX_SUBPOOLS - 1) return VCOS_EINVAL; if (num_blocks < 1) return VCOS_EINVAL; pool->num_subpools += num_extensions; pool->num_extension_blocks = num_blocks; /* Mark these subpools as valid but unallocated */ for (i = 1; i < pool->num_subpools; ++i) { pool->subpools[i].magic = VCOS_BLOCKPOOL_SUBPOOL_MAGIC; pool->subpools[i].start = NULL; pool->subpools[i].mem = NULL; } return VCOS_SUCCESS; }
static void free_pagelist(PAGELIST_T *pagelist, int actual) { vm_page_t *pages; unsigned int num_pages, i; vcos_log_trace("free_pagelist - %x, %d", (unsigned int)pagelist, actual); num_pages = (pagelist->length + pagelist->offset + PAGE_SIZE - 1) / PAGE_SIZE; pages = (vm_page_t *)(pagelist->addrs + num_pages); /* Deal with any partial cache lines (fragments) */ if (pagelist->type >= PAGELIST_READ_WITH_FRAGMENTS) { FRAGMENTS_T *fragments = g_fragments_base + (pagelist->type - PAGELIST_READ_WITH_FRAGMENTS); int head_bytes, tail_bytes; if (actual >= 0) { /* XXXBSD: might be inefficient */ void *page_address = pmap_mapdev(VM_PAGE_TO_PHYS(pages[0]), PAGE_SIZE*num_pages); if ((head_bytes = (CACHE_LINE_SIZE - pagelist->offset) & (CACHE_LINE_SIZE - 1)) != 0) { if (head_bytes > actual) head_bytes = actual; memcpy((char *)page_address + pagelist->offset, fragments->headbuf, head_bytes); } if ((head_bytes < actual) && (tail_bytes = (pagelist->offset + actual) & (CACHE_LINE_SIZE - 1)) != 0) { memcpy((char *)page_address + PAGE_SIZE*(num_pages - 1) + ((pagelist->offset + actual) & (PAGE_SIZE - 1) & ~(CACHE_LINE_SIZE - 1)), fragments->tailbuf, tail_bytes); } pmap_qremove((vm_offset_t)page_address, PAGE_SIZE*num_pages); } mtx_lock(&g_free_fragments_mutex); *(FRAGMENTS_T **) fragments = g_free_fragments; g_free_fragments = fragments; mtx_unlock(&g_free_fragments_mutex); sema_post(&g_free_fragments_sema); } for (i = 0; i < num_pages; i++) { if (pagelist->type != PAGELIST_WRITE) vm_page_dirty(pages[i]); } vm_page_unhold_pages(pages, num_pages); free(pagelist, M_VCPAGELIST); }
void vcos_generic_blockpool_delete(VCOS_BLOCKPOOL_T *pool) { vcos_log_trace("%s: pool %p", VCOS_FUNCTION, pool); if (pool) { VCOS_UNSIGNED i; ASSERT_POOL(pool); for (i = 0; i < pool->num_subpools; ++i) { VCOS_BLOCKPOOL_SUBPOOL_T *subpool = &pool->subpools[i]; ASSERT_SUBPOOL(subpool); if (subpool->mem) { /* For debugging */ memset(subpool->mem, 0xBE, VCOS_BLOCKPOOL_SIZE(subpool->num_blocks, pool->block_data_size, pool->align)); if (subpool->flags & VCOS_BLOCKPOOL_SUBPOOL_FLAG_OWNS_MEM) vcos_free(subpool->mem); subpool->mem = NULL; subpool->start = NULL; } } vcos_mutex_delete(&pool->mutex); memset(pool, 0xBE, sizeof(VCOS_BLOCKPOOL_T)); /* For debugging */ } }
/** * Creates an OpenGL ES 2.X context. * @param raspitex_state A pointer to the GL preview state. * @return Zero if successful. */ int raspitexutil_gl_init_2_0(RASPITEX_STATE *raspitex_state) { int rc; const EGLint* attribs = raspitex_state->egl_config_attribs;; const EGLint default_attribs[] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 16, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE }; const EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; if (! attribs) attribs = default_attribs; vcos_log_trace("%s", VCOS_FUNCTION); rc = raspitexutil_gl_common(raspitex_state, attribs, context_attribs); if (rc != 0) goto end; rc = raspitexutil_create_textures(raspitex_state); end: return rc; }
VCOS_STATUS_T vcos_generic_blockpool_create_on_heap(VCOS_BLOCKPOOL_T *pool, VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size, VCOS_UNSIGNED align, VCOS_UNSIGNED flags, const char *name) { VCOS_STATUS_T status = VCOS_SUCCESS; size_t size = VCOS_BLOCKPOOL_SIZE(num_blocks, block_size, align); void* mem = vcos_malloc(size, name); vcos_log_trace("%s: num_blocks %d block_size %d name %s", VCOS_FUNCTION, num_blocks, block_size, name); if (! mem) return VCOS_ENOMEM; status = vcos_generic_blockpool_init(pool, num_blocks, block_size, mem, size, align, flags, name); if (status != VCOS_SUCCESS) goto fail; pool->subpools[0].flags |= VCOS_BLOCKPOOL_SUBPOOL_FLAG_OWNS_MEM; return status; fail: vcos_free(mem); return status; }
/** * Deletes textures and EGL surfaces and context. * @param raspitex_state Pointer to the Raspi */ void raspitexutil_gl_term(RASPITEX_STATE *raspitex_state) { vcos_log_trace("%s", VCOS_FUNCTION); /* Delete OES textures */ glDeleteTextures(1, &raspitex_state->texture); eglDestroyImageKHR(raspitex_state->display, raspitex_state->egl_image); raspitex_state->egl_image = EGL_NO_IMAGE_KHR; glDeleteTextures(1, &raspitex_state->y_texture); eglDestroyImageKHR(raspitex_state->display, raspitex_state->y_egl_image); raspitex_state->y_egl_image = EGL_NO_IMAGE_KHR; glDeleteTextures(1, &raspitex_state->u_texture); eglDestroyImageKHR(raspitex_state->display, raspitex_state->u_egl_image); raspitex_state->u_egl_image = EGL_NO_IMAGE_KHR; glDeleteTextures(1, &raspitex_state->v_texture); eglDestroyImageKHR(raspitex_state->display, raspitex_state->v_egl_image); raspitex_state->u_egl_image = EGL_NO_IMAGE_KHR; /* Terminate EGL */ eglMakeCurrent(raspitex_state->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroyContext(raspitex_state->display, raspitex_state->context); eglDestroySurface(raspitex_state->display, raspitex_state->surface); eglTerminate(raspitex_state->display); }
/** * Uses glReadPixels to grab the current frame-buffer contents * and returns the result in a newly allocate buffer along with * the its size. * Data is returned in BGRA format for TGA output. PPM output doesn't * require the channel order swap but would require a vflip. The TGA * format also supports alpha. The byte swap is not done in this function * to avoid blocking the GL rendering thread. * @param state Pointer to the GL preview state. * @param buffer Address of pointer to set to pointer to new buffer. * @param buffer_size The size of the new buffer in bytes (out param) * @return Zero if successful. */ int raspitexutil_capture_bgra(RASPITEX_STATE *state, uint8_t **buffer, size_t *buffer_size) { const int bytes_per_pixel = 4; vcos_log_trace("%s: %dx%d %d", VCOS_FUNCTION, state->width, state->height, bytes_per_pixel); *buffer_size = state->width * state->height * bytes_per_pixel; *buffer = calloc(*buffer_size, 1); if (! *buffer) goto error; glReadPixels(0, 0, state->width, state->height, GL_RGBA, GL_UNSIGNED_BYTE, *buffer); if (glGetError() != GL_NO_ERROR) goto error; return 0; error: *buffer_size = 0; if (*buffer) free(*buffer); *buffer = NULL; return -1; }
GL_API void GL_APIENTRY glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image) { CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE(); if (IS_OPENGLES_11_OR_20(thread)) { #if EGL_BRCM_global_image if ((uintptr_t)image & (1u << 31)) { GLuint global_image_id[2]; if (check_global_image_egl_image(global_image_id, image, thread, false)) { RPC_CALL3(glGlobalImageTexture2DOES_impl, thread, GLGLOBALIMAGETEXTURE2DOES_ID, RPC_ENUM(target), RPC_UINT(global_image_id[0]), RPC_UINT(global_image_id[1])); } else { set_error(GLXX_GET_CLIENT_STATE(thread), GL_INVALID_VALUE); } } else { #endif vcos_log_trace("[%s] target 0x%x image %d", __FUNCTION__, target, (uint32_t)image); RPC_CALL2(glEGLImageTargetTexture2DOES_impl, thread, GLEGLIMAGETARGETTEXTURE2DOES_ID, RPC_ENUM(target), RPC_EGLID(image)); RPC_FLUSH(thread); #if EGL_BRCM_global_image } #endif } }
void *platform_tls_get(PLATFORM_TLS_T tls) { void *ret; if (!process_attached) /* TODO: this isn't thread safe */ { vcos_log_trace("Attaching process"); client_process_attach(); process_attached = true; tls = client_tls; vc_vchi_khronos_init(); } ret = vcos_tls_get(tls); if (!ret) { /* The problem here is that on VCFW, the first notification we get that a thread * exists at all is when it calls an arbitrary EGL function. We need to detect this * case and initiliase the per-thread state. * * On Windows this gets done in DllMain. */ client_thread_attach(); vcos_thread_at_exit(client_thread_detach, NULL); ret = vcos_tls_get(tls); } return ret; }
/** Preview worker thread. * Ensures camera preview is supplied with buffers and sends preview frames to GL. * @param arg Pointer to state. * @return NULL always. */ static void *preview_worker(void *arg) { RASPITEX_STATE* state = arg; MMAL_PORT_T *preview_port = state->preview_port; MMAL_BUFFER_HEADER_T *buf; MMAL_STATUS_T st; int rc; vcos_log_trace("%s: port %p", VCOS_FUNCTION, preview_port); rc = state->ops.create_native_window(state); if (rc != 0) goto end; rc = state->ops.gl_init(state); if (rc != 0) goto end; while (state->preview_stop == 0) { /* Send empty buffers to camera preview port */ while ((buf = mmal_queue_get(state->preview_pool->queue)) != NULL) { st = mmal_port_send_buffer(preview_port, buf); if (st != MMAL_SUCCESS) { vcos_log_error("Failed to send buffer to %s", preview_port->name); } } /* Process returned buffers */ if (preview_process_returned_bufs(state) != 0) { vcos_log_error("Preview error. Exiting."); state->preview_stop = 1; } } end: /* Make sure all buffers are returned on exit */ while ((buf = mmal_queue_get(state->preview_queue)) != NULL) mmal_buffer_header_release(buf); /* Tear down GL */ state->ops.gl_term(state); vcos_log_trace("Exiting preview worker"); return NULL; }
static int application_error_handler(Display *display, XErrorEvent *theEvent) { vcos_log_trace( "Ignoring Xlib error: error code %d request code %d\n", theEvent->error_code, theEvent->request_code) ; return 0 ; }
/** * MMAL Callback from camera preview output port. * @param port The camera preview port. * @param buf The new preview buffer. **/ static void preview_output_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf) { RASPITEX_STATE *state = (RASPITEX_STATE*) port->userdata; if (buf->length == 0) { vcos_log_trace("%s: zero-length buffer => EOS", port->name); state->preview_stop = 1; mmal_buffer_header_release(buf); } else if (buf->data == NULL) { vcos_log_trace("%s: zero buffer handle", port->name); mmal_buffer_header_release(buf); } else { /* Enqueue the preview frame for rendering and return to * avoid blocking MMAL core. */ //mmal_queue_put(state->preview_queue, buf); //to handle the user not reading frames, remove and return any pre-existing ones if(mmal_queue_length( state->preview_queue ) >= 2) { //fprintf(stderr, "mmal_queue_length too long\n" ); MMAL_BUFFER_HEADER_T *existing_buffer = mmal_queue_get( state->preview_queue ); if(existing_buffer) { mmal_buffer_header_release(existing_buffer); if (port->is_enabled) { fill_port_buffer_simple( port, state->preview_pool, "preview_output_cb" ); } // if (port->is_enabled) } // if(existing_buffer) } //add the buffer to the output queue mmal_queue_put(state->preview_queue, buf ); } }
/* Stops the rendering loop and destroys MMAL resources * @param state Pointer to the GL preview state. */ void raspitex_stop(RASPITEX_STATE *state) { if (! state->preview_stop) { vcos_log_trace("Stopping GL preview"); state->preview_stop = 1; vcos_thread_join(&state->preview_thread, NULL); } }
/** Creates a native window for the GL surface using dispmanx * @param raspitex_state A pointer to the GL preview state. * @return Zero if successful, otherwise, -1 is returned. */ int raspitexutil_create_native_window(RASPITEX_STATE *raspitex_state) { VC_DISPMANX_ALPHA_T alpha = {DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS, 255, 0}; VC_RECT_T src_rect = {0}; VC_RECT_T dest_rect = {0}; uint32_t disp_num = 0; // Primary uint32_t layer_num = 0; DISPMANX_ELEMENT_HANDLE_T elem; DISPMANX_UPDATE_HANDLE_T update; alpha.opacity = raspitex_state->opacity; dest_rect.x = raspitex_state->x; dest_rect.y = raspitex_state->y; dest_rect.width = raspitex_state->width; dest_rect.height = raspitex_state->height; vcos_log_trace("%s: %d,%d,%d,%d %d,%d,0x%x,0x%x", VCOS_FUNCTION, src_rect.x, src_rect.y, src_rect.width, src_rect.height, dest_rect.x, dest_rect.y, dest_rect.width, dest_rect.height); src_rect.width = dest_rect.width << 16; src_rect.height = dest_rect.height << 16; raspitex_state->disp = vc_dispmanx_display_open(disp_num); if (raspitex_state->disp == DISPMANX_NO_HANDLE) { vcos_log_error("Failed to open display handle"); goto error; } update = vc_dispmanx_update_start(0); if (update == DISPMANX_NO_HANDLE) { vcos_log_error("Failed to open update handle"); goto error; } elem = vc_dispmanx_element_add(update, raspitex_state->disp, layer_num, &dest_rect, 0, &src_rect, DISPMANX_PROTECTION_NONE, &alpha, NULL, DISPMANX_NO_ROTATE); if (elem == DISPMANX_NO_HANDLE) { vcos_log_error("Failed to create element handle"); goto error; } raspitex_state->win.element = elem; raspitex_state->win.width = raspitex_state->width; raspitex_state->win.height = raspitex_state->height; vc_dispmanx_update_submit_sync(update); raspitex_state->native_window = (EGLNativeWindowType*) &raspitex_state->win; return 0; error: return -1; }
/** Destroys the pools of buffers used by the GL renderer. * @param raspitex_state A pointer to the GL preview state. */ void raspitexutil_destroy_native_window(RASPITEX_STATE *raspitex_state) { vcos_log_trace("%s", VCOS_FUNCTION); if (raspitex_state->disp != DISPMANX_NO_HANDLE) { vc_dispmanx_display_close(raspitex_state->disp); raspitex_state->disp = DISPMANX_NO_HANDLE; } }
/* Initialises GL preview state and creates the dispmanx native window. * @param state Pointer to the GL preview state. * @return Zero if successful. */ int raspitex_init(RASPITEX_STATE *state) { VCOS_STATUS_T status; int rc; vcos_init(); vcos_log_register("RaspiTex", VCOS_LOG_CATEGORY); vcos_log_set_level(VCOS_LOG_CATEGORY, state->verbose ? VCOS_LOG_INFO : VCOS_LOG_WARN); vcos_log_trace("%s", VCOS_FUNCTION); status = vcos_semaphore_create(&state->capture.start_sem, "glcap_start_sem", 1); if (status != VCOS_SUCCESS) goto error; status = vcos_semaphore_create(&state->capture.completed_sem, "glcap_completed_sem", 0); if (status != VCOS_SUCCESS) goto error; switch (state->scene_id) { case RASPITEX_SCENE_SQUARE: rc = square_open(state); break; case RASPITEX_SCENE_MIRROR: rc = mirror_open(state); break; case RASPITEX_SCENE_TEAPOT: rc = teapot_open(state); break; case RASPITEX_SCENE_YUV: rc = yuv_open(state); break; case RASPITEX_SCENE_SOBEL: rc = sobel_open(state); break; case RASPITEXT_SCENE_BGS_SIMPLE: rc = gl_simple_open(state); break; default: rc = -1; break; } if (rc != 0) goto error; return 0; error: vcos_log_error("%s: failed", VCOS_FUNCTION); return -1; }
int32_t vc_gpuserv_init( void ) { VCHIQ_SERVICE_PARAMS_T vchiq_params; VCOS_STATUS_T status = VCOS_ENXIO; VCHIQ_STATUS_T vchiq_status; vcos_once(&gpuserv_client_once, init_once); vcos_mutex_lock(&gpuserv_client.lock); if (gpuserv_client.refcount++ > 0) { /* Already initialised so nothing to do */ vcos_mutex_unlock(&gpuserv_client.lock); return VCOS_SUCCESS; } vcos_log_set_level(VCOS_LOG_CATEGORY, VCOS_LOG_TRACE); vcos_log_register("gpuserv", VCOS_LOG_CATEGORY); vcos_log_trace("%s: starting initialisation", VCOS_FUNCTION); /* Initialise a VCHIQ instance */ vchiq_status = vchiq_initialise(&gpuserv_client_vchiq_instance); if (vchiq_status != VCHIQ_SUCCESS) { vcos_log_error("%s: failed to initialise vchiq: %d", VCOS_FUNCTION, vchiq_status); goto error; } vchiq_status = vchiq_connect(gpuserv_client_vchiq_instance); if (vchiq_status != VCHIQ_SUCCESS) { vcos_log_error("%s: failed to connect to vchiq: %d", VCOS_FUNCTION, vchiq_status); goto error; } memset(&vchiq_params, 0, sizeof(vchiq_params)); vchiq_params.fourcc = VCHIQ_MAKE_FOURCC('G','P','U','S'); vchiq_params.callback = gpuserv_callback; vchiq_params.userdata = NULL; vchiq_params.version = 1; vchiq_params.version_min = 1; vchiq_status = vchiq_open_service(gpuserv_client_vchiq_instance, &vchiq_params, &gpuserv_client.service); if (vchiq_status != VCHIQ_SUCCESS) { vcos_log_error("%s: could not open vchiq service: %d", VCOS_FUNCTION, vchiq_status); goto error; } vcos_mutex_unlock(&gpuserv_client.lock); return 0; error: vcos_mutex_unlock(&gpuserv_client.lock); return -1; }
static void send_bound_pixmap(int i) { KHRN_IMAGE_WRAP_T image; vcos_log_trace("send_bound_pixmap %d %d", i, (int)pixmap_binding[i].egl_image); vcos_assert(i >= 0 && i < NUM_PIXMAP_BINDINGS); vcos_assert(pixmap_binding[i].used); platform_get_pixmap_info(pixmap_binding[i].pixmap, &image); set_egl_image_color_data(pixmap_binding[i].egl_image, &image); khrn_platform_release_pixmap_info(pixmap_binding[i].pixmap, &image); }
/** * MMAL Callback from camera preview output port. * @param port The camera preview port. * @param buf The new preview buffer. **/ static void preview_output_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf) { RASPITEX_STATE *state = (RASPITEX_STATE*) port->userdata; if (buf->length == 0) { vcos_log_trace("%s: zero-length buffer => EOS", port->name); state->preview_stop = 1; mmal_buffer_header_release(buf); } else if (buf->data == NULL) { vcos_log_trace("%s: zero buffer handle", port->name); mmal_buffer_header_release(buf); } else { /* Enqueue the preview frame for rendering and return to * avoid blocking MMAL core. */ mmal_queue_put(state->preview_queue, buf); } }
/** * Starts the worker / GL renderer thread. * @pre raspitex_init was successful * @pre raspitex_configure_preview_port was successful * @param state Pointer to the GL preview state. * @return Zero on success, otherwise, -1 is returned * */ int raspitex_start(RASPITEX_STATE *state) { VCOS_STATUS_T status; vcos_log_trace("%s", VCOS_FUNCTION); status = vcos_thread_create(&state->preview_thread, "preview-worker", NULL, preview_worker, state); if (status != VCOS_SUCCESS) vcos_log_error("%s: Failed to start worker thread %d", VCOS_FUNCTION, status); return (status == VCOS_SUCCESS ? 0 : -1); }
/** Destroy all EGL images */ static void vidtex_destroy_images(VIDTEX_T *vt) { VIDTEX_IMAGE_SLOT_T *slot; for (slot = vt->slots; slot < vt->slots + vcos_countof(vt->slots); slot++) { slot->video_frame = NULL; if (slot->image) { vcos_log_trace("Destroying EGL image %p", slot->image); eglDestroyImageKHR(vt->display, slot->image); slot->image = NULL; } } }
/** * Advances the texture and EGL image to the next MMAL buffer. * * @param display The EGL display. * @param target The EGL image target e.g. EGL_IMAGE_BRCM_MULTIMEDIA * @param mm_buf The EGL client buffer (mmal opaque buffer) that is used to * create the EGL Image for the preview texture. * @param egl_image Pointer to the EGL image to update with mm_buf. * @param texture Pointer to the texture to update from EGL image. * @return Zero if successful. */ int raspitexutil_do_update_texture(EGLDisplay display, EGLenum target, EGLClientBuffer mm_buf, GLuint *texture, EGLImageKHR *egl_image) { vcos_log_trace("%s: mm_buf %u", VCOS_FUNCTION, (unsigned) mm_buf); GLCHK(glBindTexture(GL_TEXTURE_EXTERNAL_OES, *texture)); if (*egl_image != EGL_NO_IMAGE_KHR) { /* Discard the EGL image for the preview frame */ eglDestroyImageKHR(display, *egl_image); *egl_image = EGL_NO_IMAGE_KHR; } *egl_image = eglCreateImageKHR(display, EGL_NO_CONTEXT, target, mm_buf, NULL); GLCHK(glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, *egl_image)); return 0; }
/** * Writes the next GL frame-buffer to a RAW .ppm formatted file * using the specified file-handle. * @param state Pointer to the GL preview state. * @param outpt_file Output file handle for the ppm image. * @return Zero on success. */ int raspitex_capture(RASPITEX_STATE *state, FILE *output_file) { int rc = 0; uint8_t *buffer = NULL; size_t size = 0; vcos_log_trace("%s: state %p file %p", VCOS_FUNCTION, state, output_file); if (state && output_file) { /* Only request one capture at a time */ vcos_semaphore_wait(&state->capture.start_sem); state->capture.request = 1; /* Wait for capture to start */ vcos_semaphore_wait(&state->capture.completed_sem); /* Take ownership of the captured buffer */ buffer = state->capture.buffer; size = state->capture.size; state->capture.request = 0; state->capture.buffer = 0; state->capture.size = 0; /* Allow another capture to be requested */ vcos_semaphore_post(&state->capture.start_sem); } if (size == 0 || ! buffer) { vcos_log_error("%s: capture failed", VCOS_FUNCTION); rc = -1; goto end; } raspitexutil_brga_to_rgba(buffer, size); rc = write_tga(output_file, state->width, state->height, buffer, size); fflush(output_file); end: free(buffer); return rc; }
void khrn_platform_bind_pixmap_to_egl_image(EGLNativePixmapType pixmap, EGLImageKHR egl_image, bool send) { int i; for (i = 0; i < NUM_PIXMAP_BINDINGS; i++) { if (!pixmap_binding[i].used) { vcos_log_trace("khrn_platform_bind_pixmap_to_egl_image %d", i); pixmap_binding[i].used = true; pixmap_binding[i].pixmap = pixmap; pixmap_binding[i].egl_image = egl_image; pixmap_binding[i].send = send; if(send) send_bound_pixmap(i); return; } } vcos_assert(0); /* Not enough NUM_PIXMAP_BINDINGS? */ }
/* Destroys the pools of buffers used by the GL renderer. * @param state Pointer to the GL preview state. */ void raspitex_destroy(RASPITEX_STATE *state) { vcos_log_trace("%s", VCOS_FUNCTION); if (state->preview_pool) { mmal_pool_destroy(state->preview_pool); state->preview_pool = NULL; } if (state->preview_queue) { mmal_queue_destroy(state->preview_queue); state->preview_queue = NULL; } if (state->ops.destroy_native_window) state->ops.destroy_native_window(state); if (state->ops.close) state->ops.close(state); vcos_semaphore_delete(&state->capture.start_sem); vcos_semaphore_delete(&state->capture.completed_sem); }
uint32_t vcos_generic_blockpool_elem_to_handle(void *block) { uint32_t ret = (uint32_t)-1; uint32_t index = (uint32_t)-1; VCOS_BLOCKPOOL_HEADER_T *hdr = NULL; VCOS_BLOCKPOOL_T *pool = NULL; VCOS_BLOCKPOOL_SUBPOOL_T *subpool = NULL; uint32_t subpool_id; vcos_assert(block); hdr = (VCOS_BLOCKPOOL_HEADER_T*) block - 1; subpool = hdr->owner.subpool; ASSERT_SUBPOOL(subpool); pool = subpool->owner; ASSERT_POOL(pool); vcos_mutex_lock(&pool->mutex); /* The handle is the index into the array of blocks combined * with the subpool id. */ index = ((size_t) hdr - (size_t) subpool->start) / pool->block_size; vcos_assert(index < subpool->num_blocks); subpool_id = ((char*) subpool - (char*) &pool->subpools[0]) / sizeof(VCOS_BLOCKPOOL_SUBPOOL_T); vcos_assert(subpool_id < VCOS_BLOCKPOOL_MAX_SUBPOOLS); vcos_assert(subpool_id < pool->num_subpools); ret = VCOS_BLOCKPOOL_HANDLE_CREATE(index, subpool_id); vcos_log_trace("%s: index %d subpool_id %d handle 0x%08x", VCOS_FUNCTION, index, subpool_id, ret); vcos_mutex_unlock(&pool->mutex); return ret; }
/** * Takes a description of shader program, compiles it and gets the locations * of uniforms and attributes. * * @param p The shader program state. * @return Zero if successful. */ int raspitexutil_build_shader_program(RASPITEXUTIL_SHADER_PROGRAM_T *p) { GLint status; int i = 0; char log[1024]; int logLen = 0; vcos_assert(p); vcos_assert(p->vertex_source); vcos_assert(p->fragment_source); if (! (p && p->vertex_source && p->fragment_source)) goto fail; p->vs = p->fs = 0; p->vs = glCreateShader(GL_VERTEX_SHADER); glShaderSource(p->vs, 1, &p->vertex_source, NULL); glCompileShader(p->vs); glGetShaderiv(p->vs, GL_COMPILE_STATUS, &status); if (! status) { glGetShaderInfoLog(p->vs, sizeof(log), &logLen, log); vcos_log_error("Program info log %s", log); goto fail; } p->fs = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(p->fs, 1, &p->fragment_source, NULL); glCompileShader(p->fs); glGetShaderiv(p->fs, GL_COMPILE_STATUS, &status); if (! status) { glGetShaderInfoLog(p->fs, sizeof(log), &logLen, log); vcos_log_error("Program info log %s", log); goto fail; } p->program = glCreateProgram(); glAttachShader(p->program, p->vs); glAttachShader(p->program, p->fs); glLinkProgram(p->program); glGetProgramiv(p->program, GL_LINK_STATUS, &status); if (! status) { vcos_log_error("Failed to link shader program"); glGetProgramInfoLog(p->program, sizeof(log), &logLen, log); vcos_log_error("Program info log %s", log); goto fail; } for (i = 0; i < SHADER_MAX_ATTRIBUTES; ++i) { if (! p->attribute_names[i]) break; p->attribute_locations[i] = glGetAttribLocation(p->program, p->attribute_names[i]); if (p->attribute_locations[i] == -1) { vcos_log_error("Failed to get location for attribute %s", p->attribute_names[i]); goto fail; } else { vcos_log_trace("Attribute for %s is %d", p->attribute_names[i], p->attribute_locations[i]); } } for (i = 0; i < SHADER_MAX_UNIFORMS; ++i) { if (! p->uniform_names[i]) break; p->uniform_locations[i] = glGetUniformLocation(p->program, p->uniform_names[i]); if (p->uniform_locations[i] == -1) { vcos_log_error("Failed to get location for uniform %s", p->uniform_names[i]); goto fail; } else { vcos_log_trace("Uniform for %s is %d", p->uniform_names[i], p->uniform_locations[i]); } } return 0; fail: vcos_log_error("%s: Failed to build shader program", VCOS_FUNCTION); if (p) { glDeleteProgram(p->program); glDeleteShader(p->fs); glDeleteShader(p->vs); } return -1; }