如何使用 WinAPI 每帧仅重绘一次 child window?

How to repaint a child window only once every frame using WinAPI?

我正在使用 Direct3D 和 WinAPI 在客户区创建 windows 和渲染 3D objects。我使用标准 Windows 消息循环使渲染 window 的矩形无效,并且在渲染 window 的消息处理程序中,我在处理 [= 时在 Direct3D 中执行渲染调用13=] 消息:

BOOL bRet; 
HWND mainWnd; // Main window
HWND renderWnd; // Child of mainWnd, takes up a portion of the client area 
                // to be used as a Direct3D render target

MSG msg = {};
while ((bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
    if(bRet != -1)
    {
        TranslateMessage(&msg); 
        DispatchMessage(&msg);
        InvalidateRect(renderWnd, nullptr, false);
    }
} 

// ...

// Window procedure used by renderWnd
LRESULT renderWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        // ...
        case WM_PAINT:
        {
            // Perform Direct3D rendering
            // ...
        }
        break;
        // ...
    }
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

只要我的应用程序只有一个 window,此设置似乎就可以正常工作,因为每个帧都会调用 InvalidateRect 并确保需要重绘客户区,而这又会导致 Direct3D 绘图调用。虽然感觉不是很优雅,尤其是当我尝试创建多个 windows 时,因为我必须在同一段代码中使它们的矩形无效,即使 windows 提供的功能也是如此否则彼此无关(某些 windows 甚至可能在任何时候都不存在)。

就是说,我的问题是:是否可以让 window 使其客户区的一部分在每一帧 恰好一次 无效(假设它当前未最小化) , ETC。)?也许通过使用消息队列?回顾上面的代码段:我想要一些方法让 mainWnd(也许在它自己的 window 过程中)在每帧恰好在 renderWnd 上调用 InvalidateRect 一次。

提前致谢!

编辑:代码示例中的小错误

所以在对原始 post 的评论的帮助下,我发现最好的选择是使用 WinAPI 提供的 Timers 来安排渲染的重绘 window 以所需的帧速率。将其标记为已解决。

请注意,'standard' 处理此问题的方法更像是这样:

    // Main message loop
    MSG msg = {};
    while (WM_QUIT != msg.message)
    {
        if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            // Update your simulation/animation/etc. based on elapsed time
            //   -or-
            // multiple fixed time-steps.
            //
            // Then render one frame.
        }
    }

…

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;

    switch (message)
    {
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        EndPaint(hWnd, &ps);
        break;

此模型是一个 'flat-out' 渲染模型,您将在其中尽可能快地渲染系统,如果您有 3 个或更多帧,则受 Present 刷新率和自动节流等细节的限制准备好了。

You should take a look at GitHub for some more details like implementing WM_ENTERSIZEMOVE / WM_EXITSIZEMOVE.

你唯一需要实现 WM_PAINT / InvalidateRect 渲染的情况是你正在做一个编辑器或一些 'mixed' UI 和 Direct3D 应用程序。