无论如何,是否知道屏幕何时已更新/刷新(也许是OpenGL或DirectX?) [英] Is there anyway to know when the screen has been updated/refreshed (OpenGL or DirectX maybe?)

查看:101
本文介绍了无论如何,是否知道屏幕何时已更新/刷新(也许是OpenGL或DirectX?)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前有一个正在用C#(使用.NET)编写的应用程序,要求用户一看到屏幕上的图像,便立即启动计时器,直到他们用按键响应为止.

现在我意识到,鉴于监视器的输入滞后和响应时间,键盘实际发送消息所花费的时间,操作系统进行处理等,这实际上很难实现.

但是我正在尽最大努力将其减少到一个恒定错误(响应时间结果将用于将一个用户与下一个用户进行比较,因此恒定错误并不是真正的问题).但是,烦人的障碍是由监视器刷新率引起的变量,正如我在调用onPaint消息并完成处理时收集的那样,这并不意味着图像已实际上已从图形缓冲区中处理并发送. ?

不幸的是,时间限制和其他承诺实际上会限制我在Windows的c#中继续执行此任务.

所以我想知道的是,是否可以在更新屏幕时仅使用OpenGL或DirectX来创建事件?

先前给我的另一个建议是关于V-Sync,如果我将其关闭,是否在绘制图像后立即发送图像?而不是以与显示器刷新率同步的设定速率发送图像?

解决方案

您必须在单独的线程中渲染图形,以便:

  • 使用垂直同步来准确显示图像的有效时间.
  • 获取用户输入的准确时间(因为用户界面与渲染循环不在同一个线程上.

初始化Direct3D以在渲染过程中启用VSync:

// DirectX example
presentParams.SwapEffect = SwapEffect.Discard;
presentParams.BackBufferCount = 1;
presentParams.PresentationInterval = PresentInterval.One;

device = new Device(...

在单独的线程中执行渲染:

Thread renderThread = new Thread(RenderLoop);
renderThread.Start();

shouldDisplayImageEvent = new AutoResetEvent();

然后使用以下渲染循环:

void RenderLoop()
{
    while(applicationActive)
    {
          device.BeginScene();

        // Other rendering task

        if (shouldDisplayImageEvent.WaitOne(0))
        {
            // Render image
            // ...

            userResponseStopwatch = new Stopwatch();
            userResponseStopwatch.Start();
        }

        device.EndScene();

        device.Present();
    }
}

然后处理用户输入:

void OnUserInput(object sender, EventArgs e)
{
    if (userResponseStopwatch != null)
    {
        userResponseStopwatch.Stop();

        float userResponseDuration = userResponseStopwatch.ElapsedMillisecond - 1000 / device.DisplayMode.RefreshRate - displayDeviceDelayConstant;
        userResponseStopwatch = null;
    }
}

现在,您可以使用 shouldDisplayImageEvent.Set()事件触发器根据需要显示图像并启动秒表.

I currently have an application I'm writing in c# (using .NET) that requires me to start a timer as soon as a user sees an image on screen up until they respond with a key press.

Now I realise that practically this is very difficult given the monitor input lag and response time, the time the keyboard takes to physically send the message, the OS to process it, etc.

But I'm trying my best to reduce it down to mostly a constant error (the response time results will be used to compare one user to the next so a constant error isn't really an issue). However annoying hurdle is the variable caused by the monitor refresh rate, as I gather when my onPaint message is called and done with, it doesn't mean the image has actually been processed and sent from the graphics buffer?

Unfortunately time restrictions and other commitments would realistically restrict me to continuing this task in c# for windows.

So what I was wondering was if either handling all the drawing in OpenGL or DirectX or better still for me if it is possible to just using either OpenGL or DirectX to create an event when the screen is updated?

Another suggestion given to me previously was regarding V-Sync, if I switch this off is the image sent as soon as it is drawn? as opposed to sending images at a set rate synchronised to the monitor refresh rate?

解决方案

You must render your graphic in a separate thread in order to:

  • Use vertical synchronisation to have a precise timing of the effective display of your image.
  • Get the precise timing of your user input (since user interface is not on the same thread than the render loop.

Initialise Direct3D to enable the VSync during render :

// DirectX example
presentParams.SwapEffect = SwapEffect.Discard;
presentParams.BackBufferCount = 1;
presentParams.PresentationInterval = PresentInterval.One;

device = new Device(...

Perform the render in a separate thread:

Thread renderThread = new Thread(RenderLoop);
renderThread.Start();

shouldDisplayImageEvent = new AutoResetEvent();

Then use the following render loop:

void RenderLoop()
{
    while(applicationActive)
    {
          device.BeginScene();

        // Other rendering task

        if (shouldDisplayImageEvent.WaitOne(0))
        {
            // Render image
            // ...

            userResponseStopwatch = new Stopwatch();
            userResponseStopwatch.Start();
        }

        device.EndScene();

        device.Present();
    }
}

Then handle the user input :

void OnUserInput(object sender, EventArgs e)
{
    if (userResponseStopwatch != null)
    {
        userResponseStopwatch.Stop();

        float userResponseDuration = userResponseStopwatch.ElapsedMillisecond - 1000 / device.DisplayMode.RefreshRate - displayDeviceDelayConstant;
        userResponseStopwatch = null;
    }
}

You now use the shouldDisplayImageEvent.Set() event trigger to display the image as needed and start the stop watch.

这篇关于无论如何,是否知道屏幕何时已更新/刷新(也许是OpenGL或DirectX?)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆