C++ std::chrono::高分辨率时钟和屏幕刷新率的精度(非精度)

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秒漂移,而不是一小

我正在使用visual studio 2012,希望了解高分辨率时钟的精度

基本上,我正在编写一些代码来显示声音和图像,但我需要它们非常好地同步,并且图像必须是无撕裂的。我使用directX提供无泪图像,并使用高分辨率时钟定时屏幕刷新。显示器声称为60 fps,但是,高分辨率时钟的计时给出了60.035 fps的刷新率,平均超过10000次屏幕刷新。根据哪一个是正确的,我的音频将在一秒钟后结束0.5毫秒,也就是大约一小时后2秒。我希望任何一个时钟都比这更精确——更像是一年中的1秒漂移,而不是一小时

以前有人看过这种东西吗。我应该期待我的声卡时钟再次不同吗

编辑 这是我的计时代码。这个while循环在我的渲染线程中运行。m_renderData是一个结构数组,包含渲染场景所需的数据,每个屏幕有一个元素。对于测试,我只在一个屏幕上运行,所以它只有一个元素

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返回处理器周期,但每个硬件线程可以自由更改其运行频率,因此,即使您的线程在同一硬件线程上运行,您也无法通过测量运行周期来了解运行时间。