Esempio n. 1
0
void gp2x_frontend_deinit(void)
{
	int ret;
    
	dispman_update = vc_dispmanx_update_start( 0 );
	ret = vc_dispmanx_element_remove( dispman_update, dispman_element );
	ret = vc_dispmanx_update_submit_sync( dispman_update );
	ret = vc_dispmanx_resource_delete( resource0 );
	ret = vc_dispmanx_resource_delete( resource1 );
	ret = vc_dispmanx_display_close( dispman_display );
    
	if(gp2x_screen8) free(gp2x_screen8);
	if(gp2x_screen15) free(gp2x_screen15);
	gp2x_screen8=0;
	gp2x_screen15=0;
    
}
static void
gst_gl_window_dispmanx_egl_close (GstGLWindow * window)
{
  GstGLWindowDispmanxEGL *window_egl;
  DISPMANX_UPDATE_HANDLE_T dispman_update;

  window_egl = GST_GL_WINDOW_DISPMANX_EGL (window);

  if (window_egl->native.element) {
    dispman_update = vc_dispmanx_update_start (0);
    vc_dispmanx_element_remove (dispman_update, window_egl->native.element);
    vc_dispmanx_update_submit_sync (dispman_update);
  }
  vc_dispmanx_display_close (window_egl->display);

  GST_GL_WINDOW_CLASS (parent_class)->close (window);
}
gboolean
platform_destroy_native_window (EGLNativeDisplayType display,
    EGLNativeWindowType window, gpointer * window_data)
{
  DISPMANX_DISPLAY_HANDLE_T dispman_display;
  DISPMANX_UPDATE_HANDLE_T dispman_update;
  RPIWindowData *data = *window_data;

  dispman_display = data->d;
  dispman_update = vc_dispmanx_update_start (0);
  vc_dispmanx_element_remove (dispman_update, data->w.element);
  vc_dispmanx_update_submit_sync (dispman_update);
  vc_dispmanx_display_close (dispman_display);

  g_slice_free (RPIWindowData, data);
  *window_data = NULL;
  return TRUE;
}
Esempio n. 4
0
static void dispmanx_free_menu_resources (void *data)
{
   struct dispmanx_video *_dispvars = data;

   if (!_dispvars)
      return;

   _dispvars->update = vc_dispmanx_update_start(0);

   vc_dispmanx_resource_delete(_dispvars->menu_resources[0]);
   vc_dispmanx_resource_delete(_dispvars->menu_resources[1]);

   vc_dispmanx_element_remove(_dispvars->update, _dispvars->menu_element);

   vc_dispmanx_update_submit_sync(_dispvars->update);		

   _dispvars->menu_width = 0;
   _dispvars->menu_height = 0;
}
static void dispmanx_surface_free(void *data, struct dispmanx_surface *surface)
{
   int i;	
   struct dispmanx_video *_dispvars = data;
   
   for (i = 0; i < surface->numpages; i++) { 
      vc_dispmanx_resource_delete(surface->pages[i].resource);
      surface->pages[i].used = false;   
      slock_free(surface->pages[i].page_used_mutex); 
   }
   
   free(surface->pages);
   
   _dispvars->update = vc_dispmanx_update_start(0);
   vc_dispmanx_element_remove(_dispvars->update, surface->element);
   vc_dispmanx_update_submit_sync(_dispvars->update);		

   surface->setup = false;
}
static void
gst_gl_window_dispmanx_egl_close (GstGLWindow * window)
{
  GstGLWindowDispmanxEGL *window_egl;
  DISPMANX_UPDATE_HANDLE_T dispman_update;

  window_egl = GST_GL_WINDOW_DISPMANX_EGL (window);

  if (window_egl->native.element) {
    dispman_update = vc_dispmanx_update_start (0);
    vc_dispmanx_element_remove (dispman_update, window_egl->native.element);
    vc_dispmanx_update_submit_sync (dispman_update);
  }
  vc_dispmanx_display_close (window_egl->display);

  g_main_loop_unref (window_egl->loop);
  window_egl->loop = NULL;
  g_main_context_unref (window_egl->main_context);
  window_egl->main_context = NULL;
}
static void
gst_gl_window_dispmanx_egl_set_window_handle (GstGLWindow * window,
    guintptr handle)
{
  GstGLWindowDispmanxEGL *window_egl = GST_GL_WINDOW_DISPMANX_EGL (window);
  EGL_DISPMANX_WINDOW_T *foreign_window = (EGL_DISPMANX_WINDOW_T *)handle;
  DISPMANX_UPDATE_HANDLE_T dispman_update;

  GST_DEBUG_OBJECT (window, "set window handle with size %dx%d", foreign_window->width, foreign_window->height);

  if (window_egl->native.element) {
    dispman_update = vc_dispmanx_update_start (0);
    vc_dispmanx_element_remove (dispman_update, window_egl->native.element);
    vc_dispmanx_update_submit_sync (dispman_update);
  }

  window_egl->native.element = window_egl->foreign.element = foreign_window->element;
  window_egl->native.width =  window_egl->foreign.width = foreign_window->width;
  window_egl->native.height =  window_egl->foreign.height = foreign_window->height;
}
Esempio n. 8
0
static void
close_ogl (void)
{
#if defined (USE_OMX_TARGET_RPI)
    DISPMANX_UPDATE_HANDLE_T dispman_update;
#endif

    if (state->fshader) {
        glDeleteShader (state->fshader);
        glDetachShader (state->program, state->fshader);
    }

    if (state->vshader) {
        glDeleteShader (state->vshader);
        glDetachShader (state->program, state->vshader);
    }

    if (state->program)
        glDeleteProgram (state->program);

    if (state->tex)
        glDeleteTextures (1, &state->tex);

    /* clear screen */
    glClear (GL_COLOR_BUFFER_BIT);
    eglSwapBuffers (state->display, state->surface);

    /* Release OpenGL resources */
    eglMakeCurrent (state->display, EGL_NO_SURFACE, EGL_NO_SURFACE,
                    EGL_NO_CONTEXT);
    eglDestroySurface (state->display, state->surface);
    eglDestroyContext (state->display, state->context);
    gst_object_unref (state->gst_display);

#if defined (USE_OMX_TARGET_RPI)
    dispman_update = vc_dispmanx_update_start (0);
    vc_dispmanx_element_remove (dispman_update, state->dispman_element);
    vc_dispmanx_update_submit_sync (dispman_update);
    vc_dispmanx_display_close (state->dispman_display);
#endif
}
Esempio n. 9
0
GLUSvoid _glusDestroyNativeWindow()
{
	if (_nativeWindowCreated)
	{
		DISPMANX_UPDATE_HANDLE_T dispmanUpdate;

		dispmanUpdate = vc_dispmanx_update_start(0);
		vc_dispmanx_element_remove(dispmanUpdate, _nativeWindow.element);
		vc_dispmanx_update_submit_sync(dispmanUpdate);

		_nativeWindowCreated = GLUS_FALSE;
	}
	memset(&_nativeWindow, 0, sizeof(_nativeWindow));

	if (_nativeDisplay)
	{
		vc_dispmanx_display_close(_nativeDisplay);

		_nativeDisplay = 0;
	}

	if (_fullscreen)
	{
		vc_tv_register_callback(resizeDone, 0);

		if (vc_tv_hdmi_power_on_preferred() == 0)
		{
			waitResizeDone();
		}

		vc_tv_unregister_callback(resizeDone);

		_fullscreen = GLUS_FALSE;
	}

	SDL_ShowCursor(SDL_ENABLE);

	SDL_Quit();

	bcm_host_deinit();
}
Esempio n. 10
0
static void destroy_dispmanx(struct ra_ctx *ctx)
{
    struct priv *p = ctx->priv;

    if (p->egl_surface) {
        eglMakeCurrent(p->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
                       EGL_NO_CONTEXT);
        eglDestroySurface(p->egl_display, p->egl_surface);
        p->egl_surface = EGL_NO_SURFACE;
    }

    if (p->window)
        vc_dispmanx_element_remove(p->update, p->window);
    p->window = 0;
    if (p->display)
        vc_dispmanx_display_close(p->display);
    p->display = 0;
    if (p->update)
        vc_dispmanx_update_submit_sync(p->update);
    p->update = 0;
}
Esempio n. 11
0
void vo_close(RECT_VARS_T* vars)
{
    int ret;

    /* Cleanup code from dispmanx.c */
    vars->update = vc_dispmanx_update_start( 10 );
    assert( vars->update );

    ret = vc_dispmanx_element_remove( vars->update, vars->element );
    assert( ret == 0 );

    ret = vc_dispmanx_update_submit_sync( vars->update );
    assert( ret == 0 );

    ret = vc_dispmanx_resource_delete( vars->resource );
    assert( ret == 0 );

    ret = vc_dispmanx_display_close( vars->display );
    assert( ret == 0 );
    /* End of cleanup */
}
Esempio n. 12
0
static void
close_ogl (void)
{
  DISPMANX_UPDATE_HANDLE_T dispman_update;

  /* clear screen */
  glClear (GL_COLOR_BUFFER_BIT);
  eglSwapBuffers (state->display, state->surface);

  /* Release OpenGL resources */
  eglMakeCurrent (state->display, EGL_NO_SURFACE, EGL_NO_SURFACE,
      EGL_NO_CONTEXT);
  eglDestroySurface (state->display, state->surface);
  eglDestroyContext (state->display, state->context);
  gst_egl_display_unref (state->gst_display);

  dispman_update = vc_dispmanx_update_start (0);
  vc_dispmanx_element_remove (dispman_update, state->dispman_element);
  vc_dispmanx_update_submit_sync (dispman_update);
  vc_dispmanx_display_close (state->dispman_display);
}
Esempio n. 13
0
void SubtitleRenderer::destroy_window() {  
  if (dispman_element_) {
    auto dispman_update = vc_dispmanx_update_start(0);
    assert(dispman_update);

    if (dispman_update) {
      auto error = vc_dispmanx_element_remove(dispman_update, dispman_element_);
      assert(!error);

      error = vc_dispmanx_update_submit_sync(dispman_update);
      assert(!error);
    }

    dispman_element_ = {};
  }

  if (dispman_display_) {
    auto error = vc_dispmanx_display_close(dispman_display_);
    assert(!error);

    dispman_display_ = {};
  }
}
Esempio n. 14
0
void
destroyWorms(
    WORMS_T *worms)
{
    uint16_t i = 0;
    for (i = 0 ; i < worms->size ; i++)
    {
        WORM_T *worm = &(worms->worms[i]);
        destroyWorm(worm);
    }

    free(worms->worms);

    worms->size = 0;
    worms->worms = NULL;

    destroyImage(&(worms->image));


    //---------------------------------------------------------------------

    int result = 0;

    DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0);
    assert(update != 0);
    result = vc_dispmanx_element_remove(update, worms->element);
    assert(result == 0);
    result = vc_dispmanx_update_submit_sync(update);
    assert(result == 0);

    //---------------------------------------------------------------------

    result = vc_dispmanx_resource_delete(worms->frontResource);
    assert(result == 0);
    result = vc_dispmanx_resource_delete(worms->backResource);
    assert(result == 0);
}
Esempio n. 15
0
static void *display_thread (void *unused)
{
	VC_DISPMANX_ALPHA_T alpha = {
		(DISPMANX_FLAGS_ALPHA_T)(DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS), 
		255 /*alpha 0->255*/ , 	0
	};
	uint32_t vc_image_ptr;
	SDL_Surface *Dummy_prSDLScreen;
	int width, height;
	bool callback_registered = false;
	
  for(;;) {
    display_thread_busy = false;
    uae_u32 signal = read_comm_pipe_u32_blocking(display_pipe);
    display_thread_busy = true;
    switch(signal) {
      case DISPLAY_SIGNAL_SETUP:
        if(!callback_registered) {
  				bcm_host_init();
  				dispmanxdisplay = vc_dispmanx_display_open(0);
  			  vc_dispmanx_vsync_callback(dispmanxdisplay, vsync_callback, NULL);
  			  callback_registered = true;
  			}
			  break;

			case DISPLAY_SIGNAL_SUBSHUTDOWN:
				if (DispManXElementpresent == 1) {
					DispManXElementpresent = 0;
					dispmanxupdate = vc_dispmanx_update_start(0);
					vc_dispmanx_element_remove(dispmanxupdate, dispmanxelement);
					vc_dispmanx_update_submit_sync(dispmanxupdate);
				}
			
				if (dispmanxresource_amigafb_1 != 0) {
					vc_dispmanx_resource_delete(dispmanxresource_amigafb_1);
					dispmanxresource_amigafb_1 = 0;
			  }
				if (dispmanxresource_amigafb_2 != 0) {
					vc_dispmanx_resource_delete(dispmanxresource_amigafb_2);
					dispmanxresource_amigafb_2 = 0;
			  }
			  
			  if(prSDLScreen != NULL) {
			    SDL_FreeSurface(prSDLScreen);
			    prSDLScreen = NULL;
			  }
        uae_sem_post (&display_sem);
        break;
				
			case DISPLAY_SIGNAL_OPEN:
				width = display_width;
				height = display_height;
				
				Dummy_prSDLScreen = SDL_SetVideoMode(width, height, 16, SDL_SWSURFACE | SDL_FULLSCREEN);
				prSDLScreen = SDL_CreateRGBSurface(SDL_HWSURFACE, width, height, 16,
					Dummy_prSDLScreen->format->Rmask,	Dummy_prSDLScreen->format->Gmask, Dummy_prSDLScreen->format->Bmask, Dummy_prSDLScreen->format->Amask);
				SDL_FreeSurface(Dummy_prSDLScreen);
			
				vc_dispmanx_display_get_info(dispmanxdisplay, &dispmanxdinfo);
			
				dispmanxresource_amigafb_1 = vc_dispmanx_resource_create(VC_IMAGE_RGB565, width, height, &vc_image_ptr);
				dispmanxresource_amigafb_2 = vc_dispmanx_resource_create(VC_IMAGE_RGB565, width, height, &vc_image_ptr);
			
				vc_dispmanx_rect_set(&blit_rect, 0, 0, width, height);
				vc_dispmanx_resource_write_data(dispmanxresource_amigafb_1, VC_IMAGE_RGB565, prSDLScreen->pitch, prSDLScreen->pixels, &blit_rect);
				vc_dispmanx_rect_set(&src_rect, 0, 0, width << 16, height << 16);
			
				// 16/9 to 4/3 ratio adaptation.
				if (currprefs.gfx_correct_aspect == 0 || screen_is_picasso) {
				  // Fullscreen.
					int scaled_width = dispmanxdinfo.width * currprefs.gfx_fullscreen_ratio / 100;
					int scaled_height = dispmanxdinfo.height * currprefs.gfx_fullscreen_ratio / 100;
					vc_dispmanx_rect_set( &dst_rect, (dispmanxdinfo.width - scaled_width)/2, (dispmanxdinfo.height - scaled_height)/2,
						scaled_width,	scaled_height);
				}	else {
				  // 4/3 shrink.
					int scaled_width = dispmanxdinfo.width * currprefs.gfx_fullscreen_ratio / 100;
					int scaled_height = dispmanxdinfo.height * currprefs.gfx_fullscreen_ratio / 100;
					vc_dispmanx_rect_set( &dst_rect, (dispmanxdinfo.width - scaled_width / 16 * 12)/2, (dispmanxdinfo.height - scaled_height)/2,
						scaled_width/16*12,	scaled_height);
				}
			
				if (DispManXElementpresent == 0) {
					DispManXElementpresent = 1;
					dispmanxupdate = vc_dispmanx_update_start(0);
					dispmanxelement = vc_dispmanx_element_add(dispmanxupdate, dispmanxdisplay,	2,               // layer
						&dst_rect, dispmanxresource_amigafb_1, &src_rect,	DISPMANX_PROTECTION_NONE,	&alpha,	NULL, DISPMANX_NO_ROTATE);
			
					vc_dispmanx_update_submit(dispmanxupdate, NULL, NULL);
				}
        uae_sem_post (&display_sem);
        break;

			case DISPLAY_SIGNAL_SHOW:
				if (current_resource_amigafb == 1) {
					current_resource_amigafb = 0;
				  vc_dispmanx_resource_write_data(dispmanxresource_amigafb_1, VC_IMAGE_RGB565,
					  adisplays.gfxvidinfo.drawbuffer.rowbytes, adisplays.gfxvidinfo.drawbuffer.bufmem, &blit_rect);
				  dispmanxupdate = vc_dispmanx_update_start(0);
				  vc_dispmanx_element_change_source(dispmanxupdate, dispmanxelement, dispmanxresource_amigafb_1);
				} else {
					current_resource_amigafb = 1;
					vc_dispmanx_resource_write_data(dispmanxresource_amigafb_2,	VC_IMAGE_RGB565,
						adisplays.gfxvidinfo.drawbuffer.rowbytes,	adisplays.gfxvidinfo.drawbuffer.bufmem,	&blit_rect);
					dispmanxupdate = vc_dispmanx_update_start(0);
					vc_dispmanx_element_change_source(dispmanxupdate, dispmanxelement, dispmanxresource_amigafb_2);
				}
			  vc_dispmanx_update_submit(dispmanxupdate, NULL, NULL);
				break;
								
      case DISPLAY_SIGNAL_QUIT:
        callback_registered = false;
			  vc_dispmanx_vsync_callback(dispmanxdisplay, NULL, NULL);
				vc_dispmanx_display_close(dispmanxdisplay);
				bcm_host_deinit();
				SDL_VideoQuit();
        display_tid = 0;
        return 0;
    }
  }
}
Esempio n. 16
0
/* Show the specified cursor, or hide if cursor is NULL */
static int
RPI_ShowCursor(SDL_Cursor * cursor)
{
    int ret;
    DISPMANX_UPDATE_HANDLE_T update;
    RPI_CursorData *curdata;
    VC_RECT_T src_rect, dst_rect;
    SDL_Mouse *mouse;
    SDL_VideoDisplay *display;
    SDL_DisplayData *data;
    VC_DISPMANX_ALPHA_T alpha = {  DISPMANX_FLAGS_ALPHA_FROM_SOURCE /* flags */ , 255 /*opacity 0->255*/,  0 /* mask */ };
    
    mouse = SDL_GetMouse();
    if (mouse == NULL) {
        return -1;
    }
    
    if (cursor == NULL) {
        /* FIXME: We hide the current mouse's cursor, what we actually need is *_HideCursor */

        if ( mouse->cur_cursor != NULL && mouse->cur_cursor->driverdata != NULL) {
            curdata = (RPI_CursorData *) mouse->cur_cursor->driverdata;
            if (curdata->element > DISPMANX_NO_HANDLE) {
                update = vc_dispmanx_update_start( 10 );
                SDL_assert( update );
                ret = vc_dispmanx_element_remove( update, curdata->element );
                SDL_assert( ret == DISPMANX_SUCCESS );
                ret = vc_dispmanx_update_submit_sync( update );
                SDL_assert( ret == DISPMANX_SUCCESS );
                curdata->element = DISPMANX_NO_HANDLE;
            }
        }
        return 0;
    }
    
    curdata = (RPI_CursorData *) cursor->driverdata;
    if (curdata == NULL) {
        return -1;
    }
    
    if (mouse->focus == NULL) {
        return -1;
    }
    
    display = SDL_GetDisplayForWindow(mouse->focus);
    if (display == NULL) {
        return -1;
    }
    
    data = (SDL_DisplayData*) display->driverdata;
    if (data == NULL) {
        return -1;
    }
    
    if (curdata->element == DISPMANX_NO_HANDLE) {
        vc_dispmanx_rect_set( &src_rect, 0, 0, curdata->w << 16, curdata->h << 16 );
        vc_dispmanx_rect_set( &dst_rect, 0, 0, curdata->w, curdata->h);
        
        update = vc_dispmanx_update_start( 10 );
        SDL_assert( update );

        curdata->element = vc_dispmanx_element_add( update,
                                                    data->dispman_display,
                                                    SDL_RPI_MOUSELAYER, // layer
                                                    &dst_rect,
                                                    curdata->resource,
                                                    &src_rect,
                                                    DISPMANX_PROTECTION_NONE,
                                                    &alpha,
                                                    DISPMANX_NO_HANDLE, // clamp
                                                    VC_IMAGE_ROT0 );
        SDL_assert( curdata->element > DISPMANX_NO_HANDLE);
        ret = vc_dispmanx_update_submit_sync( update );
        SDL_assert( ret == DISPMANX_SUCCESS );
    }
    
    return 0;
}
Esempio n. 17
0
static void DISPMANX_VideoQuit(_THIS)
{
	int i,j;
		
	if ( this->screen ) {
	   /* Clear screen and tell SDL not to free the pixels */
	   const char *dontClearPixels = SDL_getenv("SDL_FBCON_DONT_CLEAR");
	      //En este caso sí tenemos que limpiar el framebuffer	
	      if ( !dontClearPixels && this->screen->pixels 
	      && DISPMANX_InGraphicsMode(this) ) {
#if defined(__powerpc__) || defined(__ia64__)	
	         /* SIGBUS when using SDL_memset() ?? */
		 Uint8 *rowp = (Uint8 *)this->screen->pixels;
		 int left = this->screen->pitch*this->screen->h;
		 while ( left-- ) { *rowp++ = 0; }
#else
		 SDL_memset(this->screen->pixels,0,
		 this->screen->h*this->screen->pitch);
#endif
	      }
		
	      if ( ((char *)this->screen->pixels >= mapped_mem) &&
	         ( (char *)this->screen->pixels < (mapped_mem+mapped_memlen)) ) 
		    this->screen->pixels = NULL;
		 
	}
	
	/* Clear the lock mutex */
	if ( hw_lock ) {
		SDL_DestroyMutex(hw_lock);
		hw_lock = NULL;
	}

	/* Clean up defined video modes */
	for ( i=0; i<NUM_MODELISTS; ++i ) {
		if ( SDL_modelist[i] != NULL ) {
			for ( j=0; SDL_modelist[i][j]; ++j ) {
				SDL_free(SDL_modelist[i][j]);
			}
			SDL_free(SDL_modelist[i]);
			SDL_modelist[i] = NULL;
		}
	}

	/* Clean up the memory bucket list */
	DISPMANX_FreeHWSurfaces(this);

	/* Unmap the video framebuffer and I/O registers */
	if ( mapped_mem ) {
		munmap(mapped_mem, mapped_memlen);
		mapped_mem = NULL;
	}
	if ( mapped_io ) {
		munmap(mapped_io, mapped_iolen);
		mapped_io = NULL;
	}
		
	//MAC liberamos lo relacionado con dispmanx
	printf ("\nDeleting dispmanx elements;\n");
	dispvars->update = vc_dispmanx_update_start( 0 );
    	assert( dispvars->update );
    	vc_dispmanx_element_remove(dispvars->update, dispvars->element);
    	vc_dispmanx_resource_delete( dispvars->resources[0] );
    	vc_dispmanx_resource_delete( dispvars->resources[1] );
	vc_dispmanx_display_close( dispvars->display );
	vc_dispmanx_update_submit_sync( dispvars->update );		
	bcm_host_deinit();

	DISPMANX_CloseMouse(this);
	DISPMANX_CloseKeyboard(this);
	exit (0);
}
Esempio n. 18
0
ViewBackend::Cursor::~Cursor()
{
    DISPMANX_UPDATE_HANDLE_T updateHandle = vc_dispmanx_update_start(0);
    vc_dispmanx_element_remove(updateHandle, cursorHandle);
    vc_dispmanx_update_submit_sync(updateHandle);
}
Esempio n. 19
0
int main(int argc, char *argv[])
{
    int ret;
    VC_RECT_T       src_rect;
    VC_RECT_T       dst_rect;

    DISPMANX_UPDATE_HANDLE_T    update;
    uint32_t                    vc_image_ptr;

    bcm_host_init();

    display = vc_dispmanx_display_open( 0 );

    image = calloc( 1, PITCH * HEIGHT ); // buffer 0
    assert(image);

    // initialize image buffer with clock run in
    int n, m, clock = 0x275555;
    for (m=0; m<24; m++) {
        for (n=0; n<HEIGHT; n++) {
            ROW(n)[m] = clock&1;
        }
        clock = clock >> 1;
    }

    // fill up image with filler packets
    // get_packet will return filler because we haven't loaded the fifo yet.
    get_packet(ROW(0)+24);
    for (n=1; n<HEIGHT; n++) {
        memcpy(ROW(n)+24, ROW(0)+24, 336);
    }

    // set up some resources
    vc_dispmanx_rect_set( &image_rect, 0, 0, WIDTH, HEIGHT);
    for (n=0;n<3;n++) {
        resource[n] = vc_dispmanx_resource_create( TYPE, WIDTH, HEIGHT, &vc_image_ptr );
        assert( resource[n] );
        ret = vc_dispmanx_resource_set_palette(  resource[n], palette, 0, sizeof palette );
        assert( ret == 0 );
        ret = vc_dispmanx_resource_write_data(  resource[n], TYPE, PITCH, image, &image_rect );
        assert( ret == 0 );
    }
    vc_dispmanx_rect_set( &image_rect, OFFSET+24, 0, 336, HEIGHT); // from now on, only copy the parts that change

    update = vc_dispmanx_update_start( 10 );
    assert( update );

    vc_dispmanx_rect_set( &src_rect, 0, 0, WIDTH << 16, HEIGHT << 16 );
    vc_dispmanx_rect_set( &dst_rect, 0, 0, 720, HEIGHT );
    element = vc_dispmanx_element_add( update, display, 2000,
                                       &dst_rect, resource[2], &src_rect,
                                       DISPMANX_PROTECTION_NONE,
                                       NULL, NULL, VC_IMAGE_ROT0 );

    ret = vc_dispmanx_update_submit_sync( update );
    assert( ret == 0 );

    // BUG: clear any existing callbacks, even to other apps.
    // https://github.com/raspberrypi/userland/issues/218
    vc_dispmanx_vsync_callback(display, NULL, NULL);

    vc_dispmanx_vsync_callback(display, vsync, NULL);

    if (argc == 2 && argv[1][0] == '-') {
        while(read_packets()) {
            ;
        }
    } else {
        demo();
    }

    vc_dispmanx_vsync_callback(display, NULL, NULL); // disable callback

    update = vc_dispmanx_update_start( 10 );
    assert( update );
    ret = vc_dispmanx_element_remove( update, element );
    assert( ret == 0 );
    ret = vc_dispmanx_update_submit_sync( update );
    assert( ret == 0 );
    for (n=0; n<3; n++) {
        ret = vc_dispmanx_resource_delete( resource[0] );
        assert( ret == 0 );
    }
    ret = vc_dispmanx_display_close( display );
    assert( ret == 0 );

    return 0;
}
int
main(
    int argc,
    char *argv[])
{
    const char *program = basename(argv[0]);

    int fps = DEFAULT_FPS;
    suseconds_t frameDuration =  1000000 / fps;
    bool isDaemon =  false;
    uint32_t sourceDisplayNumber = DEFAULT_SOURCE_DISPLAY_NUMBER;
    uint32_t destDisplayNumber = DEFAULT_DESTINATION_DISPLAY_NUMBER;
	int32_t layerNumber = DEFAULT_LAYER_NUMBER;
    const char *pidfile = NULL;

    //---------------------------------------------------------------------

    static const char *sopts = "d:f:hl:p:s:D";
    static struct option lopts[] = 
    {
        { "destination", required_argument, NULL, 'd' },
        { "fps", required_argument, NULL, 'f' },
        { "help", no_argument, NULL, 'h' },
        { "layer", required_argument, NULL, 'l' },
        { "pidfile", required_argument, NULL, 'p' },
        { "source", required_argument, NULL, 's' },
        { "daemon", no_argument, NULL, 'D' },
        { NULL, no_argument, NULL, 0 }
    };

    int opt = 0;

    while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1)
    {
        switch (opt)
        {
        case 'd':

            destDisplayNumber = atoi(optarg);
            break;

        case 'f':

            fps = atoi(optarg);

            if (fps > 0)
            {
                frameDuration = 1000000 / fps;
            }
            else
            {
                fps = 1000000 / frameDuration;
            }

            break;

        case 'h':

            printUsage(stdout, program);
            exit(EXIT_SUCCESS);

            break;

        case 'l':

            layerNumber = atoi(optarg);
            break;

        case 'p':

            pidfile = optarg;

            break;

        case 's':

            sourceDisplayNumber = atoi(optarg);
            break;

        case 'D':

            isDaemon = true;
            break;

        default:

            printUsage(stderr, program);
            exit(EXIT_FAILURE);

            break;
        }
    }

    //---------------------------------------------------------------------

    struct pidfh *pfh = NULL;

    if (isDaemon)
    {
        if (pidfile != NULL)
        {
            pid_t otherpid;
            pfh = pidfile_open(pidfile, 0600, &otherpid);

            if (pfh == NULL)
            {
                fprintf(stderr,
                        "%s is already running %jd\n",
                        program,
                        (intmax_t)otherpid);
                exit(EXIT_FAILURE);
            }
        }
        
        if (daemon(0, 0) == -1)
        {
            fprintf(stderr, "daemonize failed\n");

            exitAndRemovePidFile(EXIT_FAILURE, pfh);
        }

        if (pfh)
        {
            pidfile_write(pfh);
        }

        openlog(program, LOG_PID, LOG_USER);
    }

    //---------------------------------------------------------------------

    if (signal(SIGINT, signalHandler) == SIG_ERR)
    {
        perrorLog(isDaemon, program, "installing SIGINT signal handler");

        exitAndRemovePidFile(EXIT_FAILURE, pfh);
    }

    //---------------------------------------------------------------------

    if (signal(SIGTERM, signalHandler) == SIG_ERR)
    {
        perrorLog(isDaemon, program, "installing SIGTERM signal handler");

        exitAndRemovePidFile(EXIT_FAILURE, pfh);
    }

    //---------------------------------------------------------------------

    bcm_host_init();

    //---------------------------------------------------------------------

    int result = 0;

    //---------------------------------------------------------------------
    // Make sure the VC_DISPLAY variable isn't set. 

    unsetenv("VC_DISPLAY");

    //---------------------------------------------------------------------

    DISPMANX_DISPLAY_HANDLE_T sourceDisplay
        = vc_dispmanx_display_open(sourceDisplayNumber);

    if (sourceDisplay == 0)
    {
        messageLog(isDaemon,
                   program,
                   LOG_ERR,
                   "open source display failed");
        exitAndRemovePidFile(EXIT_FAILURE, pfh);
    }

    DISPMANX_MODEINFO_T sourceInfo;

    result = vc_dispmanx_display_get_info(sourceDisplay, &sourceInfo);

    if (result != 0)
    {
        messageLog(isDaemon,
                   program,
                   LOG_ERR,
                   "getting source display dimensions failed");

        exitAndRemovePidFile(EXIT_FAILURE, pfh);
    }

    //---------------------------------------------------------------------

    DISPMANX_DISPLAY_HANDLE_T destDisplay
        = vc_dispmanx_display_open(destDisplayNumber);

    if (destDisplay == 0)
    {
        messageLog(isDaemon,
                   program,
                   LOG_ERR,
                   "open destination display failed");
        exitAndRemovePidFile(EXIT_FAILURE, pfh);
    }

    DISPMANX_MODEINFO_T destInfo;

    result = vc_dispmanx_display_get_info(destDisplay, &destInfo);

    if (result != 0)
    {
        messageLog(isDaemon,
                   program,
                   LOG_ERR,
                   "getting destination display dimensions failed");
        exitAndRemovePidFile(EXIT_FAILURE, pfh);
    }

    //---------------------------------------------------------------------

    messageLog(isDaemon,
               program,
               LOG_INFO,
               "copying from [%d] %dx%d to [%d] %dx%d",
               sourceDisplayNumber,
               sourceInfo.width,
               sourceInfo.height,
               destDisplayNumber,
               destInfo.width,
               destInfo.height);

    //---------------------------------------------------------------------

    uint32_t image_ptr;

    DISPMANX_RESOURCE_HANDLE_T resource = 
        vc_dispmanx_resource_create(VC_IMAGE_RGBA32,
                                    destInfo.width,
                                    destInfo.height,
                                    &image_ptr);

    //---------------------------------------------------------------------

    VC_RECT_T sourceRect;
    vc_dispmanx_rect_set(&sourceRect,
                         0,
                         0,
                         destInfo.width << 16,
                         destInfo.height << 16);
    
    VC_RECT_T destRect;
    vc_dispmanx_rect_set(&destRect, 0, 0, 0, 0);

    //---------------------------------------------------------------------

    VC_DISPMANX_ALPHA_T alpha =
    {
        DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS,
        255,
        0
    };

    DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0);

    if (update == 0)
    {
        messageLog(isDaemon,
                   program,
                   LOG_ERR,
                   "display update failed");
        exitAndRemovePidFile(EXIT_FAILURE, pfh);
    }

    DISPMANX_ELEMENT_HANDLE_T element;
    element = vc_dispmanx_element_add(update,
                                      destDisplay,
                                      layerNumber,
                                      &destRect,
                                      resource,
                                      &sourceRect,
                                      DISPMANX_PROTECTION_NONE,
                                      &alpha,
                                      NULL,
                                      DISPMANX_NO_ROTATE);
    if (element == 0)
    {
        messageLog(isDaemon,
                   program,
                   LOG_ERR,
                   "failed to create DispmanX element");
        exitAndRemovePidFile(EXIT_FAILURE, pfh);
    }

    vc_dispmanx_update_submit_sync(update);

    //---------------------------------------------------------------------

    struct timeval start_time;
    struct timeval end_time;
    struct timeval elapsed_time;

    //---------------------------------------------------------------------

    while (run)
    {
        gettimeofday(&start_time, NULL);

        //-----------------------------------------------------------------

        result = vc_dispmanx_snapshot(sourceDisplay,
                                      resource,
                                      DISPMANX_NO_ROTATE);

        if (result != 0)
        {
            messageLog(isDaemon,
                       program,
                       LOG_ERR,
                       "DispmanX snapshot failed");
            exitAndRemovePidFile(EXIT_FAILURE, pfh);
        }

        //-----------------------------------------------------------------

        update = vc_dispmanx_update_start(0);

        if (update == 0)
        {
            messageLog(isDaemon,
                       program,
                       LOG_ERR,
                       "display update failed");
            exitAndRemovePidFile(EXIT_FAILURE, pfh);
        }

        vc_dispmanx_element_change_source(update, element, resource);
        vc_dispmanx_update_submit_sync(update);

        //-----------------------------------------------------------------

        gettimeofday(&end_time, NULL);
        timersub(&end_time, &start_time, &elapsed_time);

        if (elapsed_time.tv_sec == 0)
        {
            if (elapsed_time.tv_usec < frameDuration)
            {
                usleep(frameDuration -  elapsed_time.tv_usec);
            }
        }
    }

    //---------------------------------------------------------------------

    update = vc_dispmanx_update_start(0);
    vc_dispmanx_element_remove(update, element);
    vc_dispmanx_update_submit_sync(update);

    vc_dispmanx_resource_delete(resource);

    vc_dispmanx_display_close(sourceDisplay);
    vc_dispmanx_display_close(destDisplay);

    //---------------------------------------------------------------------

    messageLog(isDaemon, program, LOG_INFO, "exiting");

    if (isDaemon)
    {
        closelog();
    }

    if (pfh)
    {
        pidfile_remove(pfh);
    }

    //---------------------------------------------------------------------

    return 0 ;
}