C++ std::chrono::高分辨率时钟和屏幕刷新率的精度(非精度)
我正在使用visual studio 2012,希望了解高分辨率时钟的精度 基本上,我正在编写一些代码来显示声音和图像,但我需要它们非常好地同步,并且图像必须是无撕裂的。我使用directX提供无泪图像,并使用高分辨率时钟定时屏幕刷新。显示器声称为60 fps,但是,高分辨率时钟的计时给出了60.035 fps的刷新率,平均超过10000次屏幕刷新。根据哪一个是正确的,我的音频将在一秒钟后结束0.5毫秒,也就是大约一小时后2秒。我希望任何一个时钟都比这更精确——更像是一年中的1秒漂移,而不是一小时 以前有人看过这种东西吗。我应该期待我的声卡时钟再次不同吗 编辑 这是我的计时代码。这个while循环在我的渲染线程中运行。m_renderData是一个结构数组,包含渲染场景所需的数据,每个屏幕有一个元素。对于测试,我只在一个屏幕上运行,所以它只有一个元素C++ std::chrono::高分辨率时钟和屏幕刷新率的精度(非精度),c++,time,directx,monitor,C++,Time,Directx,Monitor,我正在使用visual studio 2012,希望了解高分辨率时钟的精度 基本上,我正在编写一些代码来显示声音和图像,但我需要它们非常好地同步,并且图像必须是无撕裂的。我使用directX提供无泪图像,并使用高分辨率时钟定时屏幕刷新。显示器声称为60 fps,但是,高分辨率时钟的计时给出了60.035 fps的刷新率,平均超过10000次屏幕刷新。根据哪一个是正确的,我的音频将在一秒钟后结束0.5毫秒,也就是大约一小时后2秒。我希望任何一个时钟都比这更精确——更像是一年中的1秒漂移,而不是一小
while(!TestDestroy())
{
for(size_t i=0; i<m_renderData.size(); ++i)
{
//work out where in the vsync cycle we are and increment the render cycle
//as needed until we need to actually render
D3DRASTER_STATUS rStatus;
m_renderData[i].deviceD3D9->GetRasterStatus(0, &rStatus);
if(m_renderData[i].renderStage==inVBlankRenderingComplete)
{
if(!rStatus.InVBlank)
m_renderData[i].renderStage=notInVBlank;
}
else if(m_renderData[i].renderStage==notInVBlank)
{
if(rStatus.InVBlank)
m_renderData[i].renderStage=inVBlankReadyToRender;
}
//check for missing the vsync for rendering
bool timeOut=false;
if(m_renderData[i].durations.size()>0)
{
double timeSinceLastRender=std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now()-m_renderData[i].durations.back()).count();
if (timeSinceLastRender>expectedUpdatePeriod*1.2)
timeOut=true;
}
if(m_renderData[i].renderStage==inVBlankReadyToRender || timeOut)
{
//We have reached the time to render
//record the time and increment the number of renders that have been performed
m_renderData[i].durations.push_back(std::chrono::high_resolution_clock::now());
++m_renderData[i].nRenders;
//we calculate the fps using 10001 times - i.e. an interval of 10000 frames
size_t fpsUpdatePeriod=10001;
if(m_renderData[i].nRenders<fpsUpdatePeriod)
{
//if we don't have enough times then display a message
m_renderData[i].fpsString = "FPS: Calculating";
}
else
{
//we have enough timing info, calculate the fps
double meanFrameTime = std::chrono::duration_cast<std::chrono::microseconds>(m_renderData[i].durations.back()-*(m_renderData[i].durations.end()-fpsUpdatePeriod)).count()/double(fpsUpdatePeriod-1);
double fps = 1000000.0/meanFrameTime;
saveFps(fps);
}
//render to the back buffer for this screen
renderToBackBuffer(i);
//display the back buffer
if(!TestDestroy())
m_renderData[i].deviceD3D9->Present(NULL, NULL, NULL, NULL);
//make sure we render to the correct back buffer next time
m_renderData[i].bufferToRender--;
//update the render cycle
m_renderData[i].renderStage=inVBlankRenderingComplete;
}
}
}
while(!TestDestroy())
{
对于(大小i=0;iGetRasterStatus(0,&rStatus);
if(m_renderData[i].renderStage==inVBlankRenderingComplete)
{
如果(!rStatus.InVBlank)
m_renderData[i].renderStage=notInVBlank;
}
else if(m_renderData[i].renderStage==notInVBlank)
{
如果(rStatus.InVBlank)
m_renderData[i].renderStage=inVBlankReadyToRender;
}
//检查是否缺少用于渲染的vsync
bool timeOut=false;
if(m_renderData[i].durations.size()>0)
{
double TimesInclastRender=std::chrono::duration_cast(std::chrono::high_resolution_clock::now()-m_renderData[i]。durations.back()).count();
如果(TimesInclastRender>expectedUpdatePeriod*1.2)
超时=真;
}
if(m_renderData[i].renderStage==inVBlankReadyToRender | | |超时)
{
//我们已经到了渲染的时间
//记录时间并增加已执行的渲染数
m_renderData[i]。持续时间。向后推(std::chrono::high_resolution_clock::now());
++m_renderData[i].nRenders;
//我们使用10001次计算fps,即10000帧的间隔
大小\u t fpsUpdatePeriod=10001;
if(m_renderData[i].nRenders不幸的是,在VS 2012和2013中,chrono::high_resolution_clock
没有使用RDTSC。这在VS.See的未来版本中是固定的。同时,使用QPC。您是否补偿了时钟漂移?(即,确保您将截止日期设置为相对于最后一个截止日期,而不是当前时间)另请参阅:和(第二个问题的公认答案是关于MSVS2012的)大多数SO和其他帖子暗示C++11 chrono::high_resolution_clock正在使用RDTSC/RDTSCP指令(未确认)。MS对高分辨率计时器的指导是使用QPC API(例如)无论如何,向我们展示你用于同步化的代码。感谢响应SDTSC是一种不可靠的时间测量方法,因此不应用于正确使用RDTSC的目的。这就是为什么我说使用QPC的原因。QPC唯一不可靠的时间是在Athlon 64 X2系统上,没有更新的处理器驱动程序。好吧,没有“正确”使用RDTSC的方法对于计时。您将受CPU节流和可能的HW线程交换的影响。尽管QPC很好。正如VS connect bug status中所述,chrono::high_resolution_clock
将在将来的版本中使用QPC来处理所有这些不同的问题。请注意,RDTSC的“HW线程交换”问题始终特定于和i这对于任何其他x86/x64处理器来说都不是问题。当然,在Windows RT上,ARM的\rdpmccntr64
指令也有完全相同的问题。无论如何,不要在VS 2012或VS 2013中使用chrono::high_resolution\u clock
。改用QPC。HW线程交换不是AMD Athlon特有的。计时线程可能会出现这样的问题操作系统(如果您不强制特定的硬件线程)将其指定给具有自己TSC的不同硬件线程。需要了解的是,RDTSC返回处理器周期,但每个硬件线程可以自由更改其运行频率,因此,即使您的线程在同一硬件线程上运行,您也无法通过测量运行周期来了解运行时间。