static void DISPMANX_DirectUpdate(_THIS, int numrects, SDL_Rect *rects) { //En OpenGL también va así. No deberíamos esperar para cambiar el buffer, de hecho la aplicación //piensa que no hay doble buffer (hasta hemos desactivado el double buffer), sino que en lugar //de esperar, simplemente deberíamos actualizar la superficie visible directamente... Pero no //puedo hacer eso porque no tengo acceso a la superficie visible: tengo la superficie de vídeo en RAM //y cada vez que se hace un cambio (o sea, cada vez que llego aquí) copio esa superficie a la VRAM //y espero a cambiar los buffers para no tener tearing, a pesar de que esta función se supone que no //hace eso. Pero en OpenGL se hace lo mismo ya que la única manera de mostrar los cambios es hacer //un GL_SWAP_BUFFERS que también es bloqueante. //Volcamos desde el ram bitmap buffer al dispmanx resource buffer que toque. cada vez a uno. vc_dispmanx_resource_write_data( dispvars->resources[flip_page], dispvars->pix_format, dispvars->pitch, dispvars->pixmem, &(dispvars->bmp_rect) ); //Empieza actualización dispvars->update = vc_dispmanx_update_start( 0 ); vc_dispmanx_element_change_source(dispvars->update, dispvars->element, dispvars->resources[flip_page]); vc_dispmanx_update_submit_sync( dispvars->update ); //vc_dispmanx_update_submit(dispvars->update, NULL, NULL); //Acaba actualización flip_page = !flip_page; return; }
static void dispmanx_flip(struct dispmanx_page *page, void *data) { struct dispmanx_video *_dispvars = data; if (!_dispvars) return; /* Dispmanx doesn't support issuing more than one pageflip. * If we do, the second CB isn't called. */ if (_dispvars->pageflip_pending > 0) { slock_lock(_dispvars->vsync_cond_mutex); scond_wait(_dispvars->vsync_condition, _dispvars->vsync_cond_mutex); slock_unlock(_dispvars->vsync_cond_mutex); } /* Issue a page flip at the next vblank interval * (will be done at vsync anyway). */ _dispvars->update = vc_dispmanx_update_start(0); vc_dispmanx_element_change_source(_dispvars->update, _dispvars->element, _dispvars->resources[page->numpage]); vc_dispmanx_update_submit(_dispvars->update, vsync_callback, (void*)page); slock_lock(_dispvars->pending_mutex); _dispvars->pageflip_pending++; slock_unlock(_dispvars->pending_mutex); }
static void dispmanx_surface_update(void *data, const void *frame, struct dispmanx_surface *surface) { struct dispmanx_video *_dispvars = data; struct dispmanx_page *page = NULL; /* Wait until last issued flip completes to get a free page. Also, dispmanx doesn't support issuing more than one pageflip.*/ slock_lock(_dispvars->pending_mutex); if (_dispvars->pageflip_pending > 0) { scond_wait(_dispvars->vsync_condition, _dispvars->pending_mutex); } slock_unlock(_dispvars->pending_mutex); page = dispmanx_get_free_page(_dispvars, surface); /* Frame blitting */ vc_dispmanx_resource_write_data(page->resource, surface->pixformat, surface->pitch, (void*)frame, &(surface->bmp_rect)); /* Issue a page flip that will be done at the next vsync. */ _dispvars->update = vc_dispmanx_update_start(0); vc_dispmanx_element_change_source(_dispvars->update, surface->element, page->resource); vc_dispmanx_update_submit(_dispvars->update, dispmanx_vsync_callback, (void*)page); slock_lock(_dispvars->pending_mutex); _dispvars->pageflip_pending++; slock_unlock(_dispvars->pending_mutex); }
static void fbDispmanSetNativeCursor(jlong nativeCursorHandle) { DISPMANX_UPDATE_HANDLE_T update; DispmanCursorImage *cursorImage = (DispmanCursorImage *)jlong_to_ptr(nativeCursorHandle); if (cursorImage != NULL && cursor.element != 0) { if (cursorImage->width != cursor.cursorWidth || cursorImage->height != cursor.cursorHeight) { fbDispmanRemoveDispmanxElement(); cursor.cursorWidth = cursorImage->width; cursor.cursorHeight = cursorImage->height; fbDispmanAddDispmanxElement(); } cursor.currentCursor = nativeCursorHandle; if (cursor.isVisible) { update = vc_dispmanx_update_start(0); vc_dispmanx_element_change_source(update, cursor.element, cursorImage->resource); vc_dispmanx_update_submit_sync(update); } } }
void vsync(DISPMANX_UPDATE_HANDLE_T u, void* arg) { int ret; DISPMANX_UPDATE_HANDLE_T update; update = vc_dispmanx_update_start( 10 ); assert( update ); ret = vc_dispmanx_element_change_source( update, element, resource[next_resource]); assert( ret == 0 ); ret = vc_dispmanx_update_submit_sync( update ); assert( ret == 0 ); if(next_resource != 2) { int real_next_resource = next_resource ^ 1; next_resource = 2; // use filler if next callback called before this one ends // fill image int n; for (n=0; n<HEIGHT; n+=2) { get_packet(ROW(n)+24); // +24 because clock never changes memcpy(ROW(n+1)+24, ROW(n)+24, 336); // double it up because the hardware scaler // will introduce blurring between lines } // write to resource ret = vc_dispmanx_resource_write_data( resource[real_next_resource], TYPE, PITCH, image, &image_rect ); assert( ret == 0 ); next_resource = real_next_resource; // queue up next real resource } }
static int DISPMANX_FlipHWSurface(_THIS, SDL_Surface *surface) { /*if ( switched_away ) { return -2; // no hardware access }*/ //Volcamos desde el ram bitmap buffer al dispmanx resource buffer //que toque. cada vez a uno. vc_dispmanx_resource_write_data( dispvars->resources[flip_page], dispvars->pix_format, dispvars->pitch, dispvars->pixmem, &(dispvars->bmp_rect) ); //**Empieza actualización*** dispvars->update = vc_dispmanx_update_start( 0 ); vc_dispmanx_element_change_source(dispvars->update, dispvars->element, dispvars->resources[flip_page]); vc_dispmanx_update_submit_sync( dispvars->update ); //vc_dispmanx_update_submit(dispvars->update, NULL, NULL); //**Acaba actualización*** flip_page = !flip_page; //MAC Esto no hace falta porque SDL siempre escribe en dispvars->pixmem, //que es el buffer en RAM y que copiamos cada vez a un resource. //surface->pixels = flip_address[flip_page]; return (0); }
static void dmx_region_update(struct dmx_region_t *dmx_region, DISPMANX_UPDATE_HANDLE_T update, picture_t *picture) { vc_dispmanx_resource_write_data(dmx_region->resource, VC_IMAGE_RGBA32, picture->p[0].i_pitch, picture->p[0].p_pixels, &dmx_region->bmp_rect); vc_dispmanx_element_change_source(update, dmx_region->element, dmx_region->resource); dmx_region->picture = picture; }
static void fbDispmanSetVisible(jboolean isVisible) { if (isVisible) { if (!cursor.isVisible && cursor.currentCursor != 0) { fbDispmanSetNativeCursor(cursor.currentCursor); DispmanCursorImage *cursorImage = (DispmanCursorImage *)jlong_to_ptr(cursor.currentCursor); DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0); vc_dispmanx_element_change_source(update, cursor.element, cursorImage->resource); vc_dispmanx_update_submit_sync(update); } } else { DISPMANX_UPDATE_HANDLE_T update; update = vc_dispmanx_update_start(0); vc_dispmanx_element_change_source(update, cursor.element, 0 ); vc_dispmanx_update_submit_sync(update); } cursor.isVisible = isVisible; }
void changeSourceWorms( WORMS_T *worms, DISPMANX_UPDATE_HANDLE_T update) { int result = 0; result = vc_dispmanx_element_change_source(update, worms->element, worms->backResource); assert(result == 0); DISPMANX_RESOURCE_HANDLE_T tmp = worms->frontResource; worms->frontResource = worms->backResource; worms->backResource = tmp; }
void FE_DisplayScreen(void) { VC_RECT_T dst_rect; vc_dispmanx_rect_set( &dst_rect, 0, 0, surface_width, surface_height ); vc_dispmanx_resource_write_data( cur_res, VC_IMAGE_RGB565, surface_width*2, gp2x_screen15, &dst_rect ); dispman_update = vc_dispmanx_update_start( 0 ); vc_dispmanx_element_change_source( dispman_update, dispman_element, cur_res ); vc_dispmanx_update_submit( dispman_update, 0, 0 ); // swap current resource tmp_res = cur_res; cur_res = prev_res; prev_res = tmp_res; }
void changeSourceLife( LIFE_T *life, DISPMANX_UPDATE_HANDLE_T update) { int result = 0; result = vc_dispmanx_element_change_source(update, life->element, life->backResource); assert(result == 0); // swap front and back resources DISPMANX_RESOURCE_HANDLE_T tmp = life->frontResource; life->frontResource = life->backResource; life->backResource = tmp; }
static bool dispmanx_gfx_frame(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch, const char *msg) { struct dispmanx_video *_dispvars = data; /* Check if neither menu nor core framebuffer is to be displayed. */ if (!_dispvars->menu_active && !frame) return true; if (width != _dispvars->width || height != _dispvars->height) { /* Sanity check. */ if (width == 0 || height == 0) return true; RARCH_LOG("video_dispmanx: internal frame resolution changed by core\n"); if (!dispmanx_setup_scale(_dispvars, width, height, pitch)) { RARCH_ERR("video_dispmanx: frame resolution set failed\n"); return false; } dispmanx_blank_console (_dispvars); } if (_dispvars->menu_active) { char buf[128]; video_monitor_get_fps(buf, sizeof(buf), NULL, 0); /* Synchronous flipping of the menu buffers. */ _dispvars->update = vc_dispmanx_update_start(0); vc_dispmanx_element_change_source(_dispvars->update, _dispvars->menu_element, _dispvars->menu_resources[_dispvars->menu_flip_page]); vc_dispmanx_update_submit_sync(_dispvars->update); return true; } /* Update main game screen: locate free page, blit and flip. */ dispmanx_update_main(_dispvars, frame); return true; }
static void fbDispmanReleaseNativeCursor(jlong nativeCursorHandle) { DispmanCursorImage *cursorImage = (DispmanCursorImage *)jlong_to_ptr(nativeCursorHandle); if (cursorImage != NULL && cursorImage->resource != 0) { if (cursor.currentCursor == nativeCursorHandle && cursor.isVisible) { DISPMANX_UPDATE_HANDLE_T update; update = vc_dispmanx_update_start(0); vc_dispmanx_element_change_source(update, cursor.element, 0 /* resource*/); vc_dispmanx_update_submit_sync(update); } vc_dispmanx_resource_delete(cursorImage->resource); } free(cursorImage); if (cursor.currentCursor == nativeCursorHandle) { cursor.currentCursor = 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; } } }
void flush_screen () { //SDL_UnlockSurface (prSDLScreen); if (show_inputmode) { inputmode_redraw(); } if (savestate_state == STATE_DOSAVE) { if(delay_savestate_frame > 0) --delay_savestate_frame; else { CreateScreenshot(); save_thumb(screenshot_filename); savestate_state = 0; } } unsigned long start = read_processor_time(); //if(start < next_synctime && next_synctime - start > time_per_frame - 1000) // usleep((next_synctime - start) - 1000); //SDL_Flip(prSDLScreen); if (current_resource_amigafb == 1) { current_resource_amigafb = 0; vc_dispmanx_resource_write_data( dispmanxresource_amigafb_1, VC_IMAGE_RGB565, gfxvidinfo.width * 2, gfxvidinfo.bufmem, &blit_rect ); dispmanxupdate = vc_dispmanx_update_start( 10 ); vc_dispmanx_element_change_source(dispmanxupdate,dispmanxelement,dispmanxresource_amigafb_1); vc_dispmanx_update_submit(dispmanxupdate,vsync_callback,NULL); //vc_dispmanx_update_submit_sync(dispmanxupdate); } else { current_resource_amigafb = 1; vc_dispmanx_resource_write_data( dispmanxresource_amigafb_2, VC_IMAGE_RGB565, gfxvidinfo.width * 2, gfxvidinfo.bufmem, &blit_rect ); dispmanxupdate = vc_dispmanx_update_start( 10 ); vc_dispmanx_element_change_source(dispmanxupdate,dispmanxelement,dispmanxresource_amigafb_2); vc_dispmanx_update_submit(dispmanxupdate,vsync_callback,NULL); } last_synctime = read_processor_time(); if(last_synctime - next_synctime > time_per_frame - 1000) adjust_idletime(0); else adjust_idletime(next_synctime - start); if(last_synctime - next_synctime > time_per_frame - 5000) next_synctime = last_synctime + time_per_frame * (1 + currprefs.gfx_framerate); else next_synctime = next_synctime + time_per_frame * (1 + currprefs.gfx_framerate); init_row_map(); }
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 ; }