directx中消息循环的基本概念

directx中消息循环的基本概念,directx,Directx,我发现了信息循环的奇怪点 首先,在下面锁定此代码 MSG msg = {0}; while( WM_QUIT != msg.message ) { if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } else { Render();

我发现了信息循环的奇怪点

首先,在下面锁定此代码

MSG msg = {0};
while( WM_QUIT != msg.message )
{
    if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
    {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }
    else
    {
        Render();  // Do some rendering
    }
}
这是directx的教程,这部分是消息循环的一部分

如果我单击鼠标,它将作为消息进入队列

所以像这样的输入应该是WinAPI的proc函数中的进程

现在peekMessage返回true,当我单击时将不会在帧中调用render

我认为当我单击时,渲染的代码应该更改为if~else到if~if


你能解释一下吗?

你的理解很接近,但不完全正确。循环不是每帧运行一次。相反,对于循环的每次迭代,要么处理单个消息,要么调用Render。实际上,这使得渲染优先级最低,但使应用程序保持响应性。根据要做的工作量,每个绘制的帧可以运行循环多次或几次


Render直接调用Present吗?还是会使窗口失效?如果它使窗口无效,您可能不希望更改为像您提到的那样始终调用Render,因为您有可能无法在渲染之间重新绘制窗口。

您的理解很接近,但并不完全正确。循环不是每帧运行一次。相反,对于循环的每次迭代,要么处理单个消息,要么调用Render。实际上,这使得渲染优先级最低,但使应用程序保持响应性。根据要做的工作量,每个绘制的帧可以运行循环多次或几次


Render直接调用Present吗?还是会使窗口失效?如果它使窗口无效,您将不希望更改为像您提到的那样始终调用Render,因为您有可能在渲染之间不重新绘制窗口。

else中的渲染基本上优先于处理队列中的消息而不是渲染。将鼠标移到directx渲染窗口上会将消息快速添加到消息队列,但速度不足以导致渲染延迟到您所看到的任何程度。使用每次迭代进行渲染没有任何好处,因为迭代的速度比swapchain中生成的每个帧快得多,也比新消息淹没队列的速度快得多。今天的大多数计算机会以每毫秒不止一次的速度运行这个循环,甚至鼠标悬停事件也不会像这样频繁发生。在每次迭代中进行渲染并没有错,只是没有必要。在示例运行时,尽可能快地在directx窗口上移动鼠标将导致此循环中处理消息和延迟渲染的迭代次数少于10%

此消息循环将尽快执行,并且无法检测swapchain何时准备好渲染。Peek消息检查队列中是否有消息。如果有,它会处理它,如果没有,它会渲染。您担心的是一系列窗口事件会导致渲染延迟,但这实际上是不可能的。无论消息发送到队列的速度有多快,swapchain的渲染速度都是60fps所需速度的10倍以上。此循环是CPU利用率高的原因。这样做的原因可能是为了简化教程,但因为它本身就是一个复杂的环境。如果担心消息队列延迟帧渲染,可以在单独的线程中修改交换链

为了提高示例程序的CPU效率,只需添加Sleep8;在渲染例程的底部。这将导致消息处理程序/渲染线程在处理消息和渲染的周期之间以大约每秒120次的速度暂停。您可以通过使用高分辨率计时器和基于模数的周期间睡眠来改进这一点


改进此示例的一个很好的信息源是。

else中的渲染基本上优先于处理队列中的消息而不是渲染。将鼠标移到directx渲染窗口上会将消息快速添加到消息队列,但速度不足以导致渲染延迟到您所看到的任何程度。使用每次迭代进行渲染没有任何好处,因为迭代的速度比swapchain中生成的每个帧快得多,也比新消息淹没队列的速度快得多。今天的大多数计算机会以每毫秒不止一次的速度运行这个循环,甚至鼠标悬停事件也不会像这样频繁发生。在每次迭代中进行渲染并没有错,只是没有必要。在示例运行时,尽可能快地在directx窗口上移动鼠标将导致此循环中处理消息和延迟渲染的迭代次数少于10%

此消息循环将尽快执行,并且无法检测swapchain何时准备好渲染。Peek消息检查queu中是否有消息 E如果有,它会处理它,如果没有,它会渲染。您担心的是一系列窗口事件会导致渲染延迟,但这实际上是不可能的。无论消息发送到队列的速度有多快,swapchain的渲染速度都是60fps所需速度的10倍以上。此循环是CPU利用率高的原因。这样做的原因可能是为了简化教程,但因为它本身就是一个复杂的环境。如果担心消息队列延迟帧渲染,可以在单独的线程中修改交换链

为了提高示例程序的CPU效率,只需添加Sleep8;在渲染例程的底部。这将导致消息处理程序/渲染线程在处理消息和渲染的周期之间以大约每秒120次的速度暂停。您可以通过使用高分辨率计时器和基于模数的周期间睡眠来改进这一点


改进此示例的一个很好的信息源是。

本质上,此循环将处理窗口中任何挂起的Win32消息,如果没有,则将呈现一个帧。如果它看到WM_退出消息,它将退出循环以退出应用程序

不需要“节流”,因为DirectX Present将阻止线程,即如果已经有3帧等待渲染,则暂停线程

此模型假设您在每个“渲染”调用中执行一帧“更新”,这对于游戏来说并不现实,但对于教程来说很简单。使用扩展教程循环类似于:

#include “StepTimer.h
DX::StepTimer g_timer;

StepTimer默认使用变量step updates,这意味着使用任何时间增量每帧调用一次Update,然后调用一次Render

您可以使用固定步骤更新,例如每秒60次,如下所示:

g_timer.SetFixedTimeStep(true);
g_timer.SetTargetElapsedSeconds(1.f / 60.f);

在此模式下,您将处理所有挂起的Win32消息,然后根据需要随时调用Update,以保持平均每秒60次固定步长更新,然后调用Render一次。

基本上,此循环将处理窗口的所有挂起的Win32消息,如果没有,它将渲染帧。如果它看到WM_退出消息,它将退出循环以退出应用程序

不需要“节流”,因为DirectX Present将阻止线程,即如果已经有3帧等待渲染,则暂停线程

此模型假设您在每个“渲染”调用中执行一帧“更新”,这对于游戏来说并不现实,但对于教程来说很简单。使用扩展教程循环类似于:

#include “StepTimer.h
DX::StepTimer g_timer;

StepTimer默认使用变量step updates,这意味着使用任何时间增量每帧调用一次Update,然后调用一次Render

您可以使用固定步骤更新,例如每秒60次,如下所示:

g_timer.SetFixedTimeStep(true);
g_timer.SetTargetElapsedSeconds(1.f / 60.f);

在此模式下,您将处理所有挂起的Win32消息,然后根据需要随时调用Update以保持平均每秒60次固定步长更新,然后调用一次Render。

我主要使用Render。同时使用窗口消息系统和directx是不好的。正如您所说,渲染的优先级低于消息。这是directx教程,所以我认为这段代码可能对directx无效。您对此有何看法?代码将按原样工作,并且对于教程来说非常简单。如果你最后写了一个游戏,你发现你不能保持帧速率,你可以做一些事情,比如把你的渲染切换到不同的线程,或者以用户的优先级发布消息来进行绘制,但是为了教程的缘故,这是可以的。我主要使用渲染。同时使用窗口消息系统和directx是不好的。正如您所说,渲染的优先级低于消息。这是directx教程,所以我认为这段代码可能对directx无效。您对此有何看法?代码将按原样工作,并且对于教程来说非常简单。如果你最后写了一个游戏,你发现你不能保持帧速率,你可以做一些事情,比如切换你的渲染到一个不同的线程,或者以用户的优先级发布消息来进行绘制,但是为了教程的缘故,这是可以的。请注意,这不会使用100%的核心。如果存在Direct3D 11,它将阻塞,即如果有3帧挂起,将线程置于睡眠状态。循环渲染速度尽可能快,但不会因此锁定CPU。奇怪。我看到在使用Windows 8.1的i7-2600K上有30%的cpu。在渲染例程中添加Sleep8会使其下降到远低于1%。我会留意的。感谢您,这不会使用100%的核心。如果存在Direct3D 11,它将阻塞,即如果有3帧挂起,将线程置于睡眠状态。循环渲染速度尽可能快,但不会因此锁定CPU。奇怪。我看到在使用Windows 8.1的i7-2600K上有30%的cpu。在渲染例程中添加Sleep8会使其下降到远低于1%。我会留意的。谢谢