void FrameControl_Remain( FrameControl ctx ) { int64_t current_time; unsigned int n_ms, lost_ms; if( ctx->state == STATE_QUIT ) { return; } lost_ms = 0; current_time = LCUI_GetTime(); LCUIMutex_Lock( &ctx->mutex ); n_ms = (unsigned int)(current_time - ctx->prev_frame_start_time); if( n_ms > ctx->one_frame_remain_time ) { goto normal_exit; } n_ms = ctx->one_frame_remain_time - n_ms; if( n_ms < 1 ) { goto normal_exit; } /* 睡眠一段时间 */ while( lost_ms < n_ms && ctx->state == STATE_RUN ) { LCUICond_TimedWait( &ctx->cond, &ctx->mutex, n_ms - lost_ms ); lost_ms = (unsigned int)LCUI_GetTimeDelta( current_time ); } /* 睡眠结束后,如果当前状态为 PAUSE,则说明睡眠是因为要暂停而终止的 */ if( ctx->state == STATE_PAUSE ) { current_time = LCUI_GetTime(); /* 等待状态改为“继续” */ while( ctx->state == STATE_PAUSE ) { LCUICond_Wait( &ctx->cond, &ctx->mutex ); } lost_ms = (unsigned int)LCUI_GetTimeDelta( current_time ); ctx->pause_time = lost_ms; ctx->prev_frame_start_time += lost_ms; LCUIMutex_Unlock( &ctx->mutex ); return; } normal_exit:; current_time = LCUI_GetTime(); if( current_time - ctx->prev_fps_update_time >= 1000 ) { ctx->current_fps = ctx->temp_fps; ctx->prev_fps_update_time = current_time; ctx->temp_fps = 0; } ctx->prev_frame_start_time = current_time; ++ctx->temp_fps; LCUIMutex_Unlock( &ctx->mutex ); }
/** 让当前帧停留一定时间 */ void FrameControl_Remain( FrameCtrlCtx ctx ) { unsigned int n_ms, lost_ms; int64_t current_time; if( ctx->state == FRAME_CTRL_STATE_QUIT ) { return; } current_time = LCUI_GetTickCount(); n_ms = (int)(current_time - ctx->prev_frame_start_time); if( n_ms > ctx->one_frame_remain_time ) { goto normal_exit; } n_ms = ctx->one_frame_remain_time - n_ms; if( n_ms < 1 ) { goto normal_exit; } /* 进行睡眠,直到需要暂停为止 */ LCUICond_TimedWait( &ctx->wait_pause, &ctx->mutex, n_ms ); /* 睡眠结束后,如果当前状态不为PAUSE,则说明睡眠不是因为要暂停而终止的 */ if( ctx->state != FRAME_CTRL_STATE_PAUSE ) { goto normal_exit; } current_time = LCUI_GetTickCount(); /* 需要暂停,进行睡眠,直到需要继续为止 */ LCUICond_Wait( &ctx->wait_continue, &ctx->mutex ); lost_ms = (unsigned int)LCUI_GetTicks( current_time ); ctx->pause_time = lost_ms; ctx->prev_frame_start_time += lost_ms; return; normal_exit:; current_time = LCUI_GetTickCount(); if( current_time - ctx->prev_fps_update_time >= 1000 ) { ctx->current_fps = ctx->temp_fps; ctx->prev_fps_update_time = current_time; ctx->temp_fps = 0; } ctx->prev_frame_start_time = current_time; ++ctx->temp_fps; }
/** 运行目标主循环 */ int LCUI_MainLoop_Run( LCUI_MainLoop loop ) { if( loop->state == STATE_RUNNING ) { _DEBUG_MSG("error: main-loop already running."); return -1; } DEBUG_MSG("loop: %p, enter\n", loop); loop->state = STATE_RUNNING; /* 将主循环记录插入至列表表头 */ LinkedList_Goto( &MainApp.loop_list, 0 ); LinkedList_Insert( &MainApp.loop_list, loop ); MainApp.loop = loop; LCUIMutex_Lock( &MainApp.loop_changed ); /* 广播,让其它线程交出主循环运行权 */ LCUICond_Broadcast( &MainApp.loop_cond ); /* 获取运行权 */ LCUIMutex_Lock( &MainApp.loop_mutex ); LCUIMutex_Unlock( &MainApp.loop_changed ); loop->tid = LCUIThread_SelfID(); while( loop->state != STATE_EXITED ) { if( LinkedList_GetTotal(&MainApp.task_list) <= 0 ) { DEBUG_MSG("loop: %p, sleeping...\n", loop); LCUICond_TimedWait( &MainApp.loop_cond, 1000 ); DEBUG_MSG("loop: %p, wakeup\n", loop); /** 如果当前运行的主循环不是自己 */ if( MainApp.loop != loop ) { loop->state = STATE_PAUSED; DEBUG_MSG("loop: %p, release control.\n", loop); LCUIMutex_Unlock( &MainApp.loop_mutex ); /* 等待其它线程获得主循环运行权 */ LCUIMutex_Lock( &MainApp.loop_changed ); LCUIMutex_Unlock( &MainApp.loop_changed ); DEBUG_MSG("loop: %p, waiting...\n", loop); /* 等待其它线程释放主循环运行权 */ LCUIMutex_Lock( &MainApp.loop_mutex ); } continue; } DEBUG_MSG("loop: %p, run task.\n", loop); LCUI_RunTask(); } loop->state = STATE_EXITED; LinkedList_Goto( &MainApp.loop_list, 0 ); LinkedList_Delete( &MainApp.loop_list ); /* 获取处于列表表头的主循环 */ loop = (LCUI_MainLoop)LinkedList_Get( &MainApp.loop_list ); if( loop ) { /* 改变当前运行的主循环 */ MainApp.loop = loop; LCUICond_Broadcast( &MainApp.loop_cond ); } /* 释放运行权 */ LCUIMutex_Unlock( &MainApp.loop_mutex ); /* 如果列表为空,一般意味着LCUI需要退出了 */ if( LinkedList_GetTotal( &MainApp.loop_list ) <= 0 ) { /** 广播,通知相关线程开始进行清理操作 */ LCUICond_Broadcast( &MainApp.loop_list_empty ); } DEBUG_MSG("loop: %p, exit\n", loop); return 0; }