我正在尝试通过使用Windows计时器队列在Windows GDI上实现高每秒帧数。相关接口为CreateTimerQueue, DeleteTimerQueueEx, CreateTimerQueueTimer,和DeleteTimerQueueTimer。
定时器是使用CreateTimerQueueTimer(&m_timer, m_timer_queue, TimerCallback, this, 0, 20, WT_EXECUTEINTIMERTHREAD);创建的,以实现约50fps的速度。GDI操作(后端存储中的一些绘制,加上InvalidateRect)不能是异步的,因此我不能选择除WT_EXECUTEINTIMERTHREAD之外的其他标志,以便在绘图代码上不需要额外的同步操作。我们的想法是在可能的情况下达到50fps,当它不是的时候,以最大可能的速度显示每一帧。
在动画结束时(达到总帧数),将调用DeleteTimerQueueTimer来销毁计时器。
问题是DeleteTimerQueueTimer没有立即关闭回调函数的调用。当无法达到50fps的要求时,定时器会将呼叫放入队列中。在回调函数中调用DeleteTimerQueueTimer不会破坏队列。因此,即使决定关闭计时器,回调仍会被调用。
我该如何处理这个问题?
timeSetEvent / timeKillEvent多媒体API似乎没有这个问题。没有队列,当我调用timeKillEvent时,回调函数的调用立即停止。是否有可能在计时器队列中实现相同的行为?发布于 2010-05-28 23:01:54
您可以将WT_EXECUTEONLYONCE标志传递给CreateTimerQueueTimer函数。这将导致计时器仅触发一次,而不是周期性地触发。
然后,您可以使用ChangeTimerQueueTimer方法重新安排计时器。
要覆盖在帧中绘制花费的时间太长太完整的时间,可以在TimerHandler方法的开头添加一个CriticalSection,这将导致第二个计时器等待第一个计时器完成。
发布于 2009-11-06 05:28:52
如果你想在50fps+上运行一些东西,你最好只有一个绘制循环,它计算帧之间的时间量,并相应地缩放动画。计时器实际上并不是经常触发的。因此(这可能在您的Idle处理程序中)。例如,这段伪代码(忽略错误处理的缺失):
static longlong last_frame;
while(1) {
longlong current_frame = QueryPerformanceCounter();
long delta = current_frame - last_frame;
// Do drawing here, scale amount to move by how much time has elapsed
last_frame = current_frame;
}发布于 2011-11-08 06:01:26
如果尚未安排计时器,DeleteTimerQueueTimer将取消计时器。(当您使用WT_EXECUTEINTIMERTHREAD时,我相信它们是在定时器队列和工作线程共享的线程池中的线程上作为APC排队的。)如果它已经被调度(不仅仅是运行)-它将被运行,并且DeleteTimerQueueTimer调用将被阻塞,直到完成。
如果我没理解错你的问题,我可以建议你这样做吗? 1.在调用DeleteTimerQueueTimer之前,设置一个标志abortAllTimers为true。2.在每个定时器回调函数中,检查abortAllTimers是否为真。如果它是真的-那么立即返回,不做任何绘图。
最后,不应该从计时器回调中调用- DeleteTimerQueueTimer。相反,我建议您应该从任何其他线程调用它-比方说您用来启动计时器的线程。
希望这能有所帮助。
https://stackoverflow.com/questions/1680162
复制相似问题