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);
}
Exemple #2
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 */
   }
}
Exemple #7
0
/**
 * 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;
}
Exemple #9
0
/**
 * 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);
}
Exemple #10
0
/**
 * 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;
}
Exemple #13
0
/** 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 );
		}
}
Exemple #16
0
/* 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);
    }
}
Exemple #17
0
/** 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;
}
Exemple #18
0
/** 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);
}
Exemple #22
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);
    }
}
Exemple #23
0
/**
 * 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);
}
Exemple #24
0
/** 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;
      }
   }
}
Exemple #25
0
/**
 * 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;
}
Exemple #26
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;
}
Exemple #30
0
/**
 * 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;
}