在打开多个其他窗口时使用全屏窗口时帧速率非常低

Very low framerate when using full-screen window while multiple other windows are open

本文关键字:窗口 帧速率 非常低 其他      更新时间:2023-10-16

很抱歉标题太长,但我有一个非常具体的问题,无法更简洁地表达。我正在编写一个游戏引擎(GitHub链接:这里(,我试图让客户端在应用程序自动提供的主窗口顶部创建窗口。

我已经完全设法让它工作,但是当主窗口进入全屏模式时(初始化时或用户按 alt+enter 时(,我对主窗口的帧速率感到困扰。我还没有对性能进行基准测试,但它明显很糟糕(所以可能在 20-30 FPS 左右(,并且当用户创建另一个窗口时,性能只会下降(它甚至不必显示(。

由于用户创建的所有窗口都是主窗口的子窗口,因此在进入全屏模式之前,我必须隐藏它们。

我的 window 类中有很多代码(超过 1000 行(,所以给你一个最小的示例将非常困难。如果您必须查看代码,请访问 GitHub 存储库(在平台/窗口下,您将找到我引用的代码(。我想知道这是否是在同一进程中打开多个窗口的奇怪工件,或者我只是缺少一些代码。

话虽如此,这里有一些实际的客户端代码:

沙盒应用.h

#pragma once
#include<Infinity.h>
class SandboxApp : public Infinity::Application
{
private:
Infinity::Window *m_popup_window;
Infinity::Rasterizer *m_rasterizer;
Infinity::OrthoCamera m_camera;
Infinity::Renderer2D m_renderer;
Infinity::Texture2D *m_texture;
float m_aspect_ratio;
public:
SandboxApp();
~SandboxApp();
void OnApplicationEntered(Infinity::ApplicationEnteredEvent *event) override;
void OnUserCreate(Infinity::UserCreateEvent *event) override;
void OnUserUpdate(Infinity::UserUpdateEvent *event) override;
void OnUserRender(Infinity::UserRenderEvent *event) override;
void OnUserDestroy(Infinity::UserDestroyEvent *event) override;
void OnWindowResized(Infinity::WindowResizedEvent *event) override;
void Exit(const char *message);
};

三宝盒应用.cpp

#define INFINITY_ENTRY_POINT
#include"SandboxApp.h"
SandboxApp::SandboxApp():
m_popup_window(nullptr),
m_rasterizer(nullptr),
m_renderer(),
m_texture(),
m_aspect_ratio(),
m_camera()
{}
SandboxApp::~SandboxApp()
{}
void SandboxApp::Exit(const char *message)
{
INFINITY_CLIENT_ERROR(message);
RequestExit();
}
void SandboxApp::OnApplicationEntered(Infinity::ApplicationEnteredEvent *event)
{
Infinity::Window::WindowParams &params = event->GetMainWindowParams();
params.fullscreen = true;
params.auto_show = false;
}
void SandboxApp::OnUserCreate(Infinity::UserCreateEvent *event)
{
Infinity::Window *window = GetMainWindow();
m_popup_window = Infinity::Window::CreateWindow();
Infinity::Window::WindowParams window_params;
window_params.width = 300;
window_params.height = 300;
window_params.title = "Popup window!";
if (!m_popup_window->Init(window_params))
{
Exit("Error initializing popup window");
return;
}
// Set clear color
Infinity::Context *context = Infinity::Window::GetContext();
context->SetClearColor(0.0f, 0.0f, 0.0f, 1.0f);
m_popup_window->MakeContextCurrent();
context = Infinity::Window::GetContext();
context->SetClearColor(0.0f, 0.0f, 1.0f, 1.0f);
window->MakeContextCurrent();
// Initialize other resources
m_rasterizer = Infinity::Rasterizer::CreateRasterizer();
if (!m_rasterizer->Init(Infinity::Rasterizer::CullMode::NONE, true))
{
Exit("Error initializing rasterizer");
return;
}
m_rasterizer->Bind();
if (!m_renderer.Init())
{
Exit("Error initializing Renderer2D");
return;
}
m_texture = Infinity::Texture2D::CreateTexture();
if (!m_texture->Init("assets/image.png"))
{
Exit("Error initializing texture");
return;
}
INFINITY_CLIENT_INFO("Client created");
window->Show();
m_popup_window->Show();
event->Consume();
}
void SandboxApp::OnUserUpdate(Infinity::UserUpdateEvent *event)
{
Infinity::Window *window = GetMainWindow();
if (KeyPressed(Infinity::KeyCode::Escape))
{
if (window->CursorEnabled())
{
window->DisableCursor();
}
else
{
window->EnableCursor();
}
}
if (window->CursorEnabled())
{
event->Consume();
return;
}
float speed = (float)(3.0 * event->GetDT());
float r_speed = (float)(2.0 * event->GetDT());
float z_speed = (float)(1.0 * event->GetDT());
if (KeyDown(Infinity::KeyCode::Left)) { m_camera.MoveLeft(speed); }
if (KeyDown(Infinity::KeyCode::Right)) { m_camera.MoveRight(speed); }
if (KeyDown(Infinity::KeyCode::Down)) { m_camera.MoveBackward(speed); }
if (KeyDown(Infinity::KeyCode::Up)) { m_camera.MoveForward(speed); }
if (KeyDown(Infinity::KeyCode::W)) { m_camera.zoom += z_speed; }
if (KeyDown(Infinity::KeyCode::S)) { m_camera.zoom -= z_speed; }
if (KeyDown(Infinity::KeyCode::A)) { m_camera.roll -= r_speed; }
if (KeyDown(Infinity::KeyCode::D)) { m_camera.roll += r_speed; }
m_camera.Update(m_aspect_ratio);
event->Consume();
}
void SandboxApp::OnUserRender(Infinity::UserRenderEvent *event)
{
Infinity::Window *window = GetMainWindow();
window->MakeContextCurrent();
Infinity::Context *context = Infinity::Window::GetContext();
context->Clear();
m_renderer.StartScene(&m_camera);
Infinity::Renderer2D::QuadParams quad;
quad.position = { 0.0f, 0.0f };
quad.size = { 1.0f, 1.0f };
quad.color = { 1.0f, 0.0f, 0.0f, 1.0f };
m_renderer.DrawQuad(quad);
m_renderer.EndScene();
m_popup_window->MakeContextCurrent();
context = Infinity::Window::GetContext();
context->Clear();
window->MakeContextCurrent();
event->Consume();
}
void SandboxApp::OnUserDestroy(Infinity::UserDestroyEvent *event)
{
m_renderer.Destroy();
if (m_rasterizer)
{
m_rasterizer->Destroy();
delete m_rasterizer;
}
if (m_texture)
{
m_texture->Destroy();
delete m_texture;
}
if (m_popup_window)
{
m_popup_window->Destroy();
delete m_popup_window;
}
INFINITY_CLIENT_INFO("Client destroyed");
event->Consume();
}
void SandboxApp::OnWindowResized(Infinity::WindowResizedEvent *event)
{
if (event->GetWindow() == GetMainWindow())
{
m_aspect_ratio = (float)event->GetWidth() / (float)event->GetHeight();
m_camera.Update(m_aspect_ratio);
event->Consume();
}
}
Infinity::Application *Infinity::CreateApplication()
{
return new SandboxApp;
}

如果您需要任何其他信息,请发表评论。
提前感谢! :)

更新
我尝试将可执行文件添加到图形性能选项列表,但它没有改变全屏窗口的低帧速率。

我做了更多的测试,发现我只需要创建子窗口即可发生这些低效率。即使我不显示、更新或渲染到窗口,简单地创建它也会减慢全屏主窗口的帧速率。

尝试进行更多研究时,我意识到 MSDN 没有任何关于使用多个 DXGI 交换链的文档。我的预感是,将一个交换链的全屏状态设置为 true 会以某种方式干扰另一个交换链,导致效率低下(尽管我的 ID3D11Device 调试输出在任何地方都没有提到效率低下(

Windows 中有 2 种全屏。

真正的全屏可能是你正在做的事情,调用IDXGISwapChain::SetFullscreenState。在此模式下,Windows 桌面合成器 dwm.exe 处于禁用状态,从而为应用提供对监视器的独占访问权限。但是,正如您发现的那样,它有并发症。顺便说一句,它们更多:alt+tab 可能很慢,来自其他应用程序的弹出窗口可能会出现故障,而且正确实现也很棘手,我认为您必须重新创建交换链和所有渲染目标。从好的方面来说,在极少数情况下,它可能会将 FPS 提高个位数。

无边框窗口是您应该做的,因为您希望多个 Win32 窗口与您的全屏内容一起运行。在此模式下,桌面合成器已启动并运行,并更新您的窗口以及其他窗口。切换该模式也更容易,下面的示例。

HRESULT WindowImpl::maximizeBorderless( bool max )
{
// https://devblogs.microsoft.com/oldnewthing/20100412-00/?p=14353
DWORD dwStyle = GetWindowLong( GWL_STYLE );
if( max )
{
MONITORINFO mi = { sizeof( mi ) };
if( GetWindowPlacement( &m_wpPrev ) && GetMonitorInfo( MonitorFromWindow( m_hWnd, MONITOR_DEFAULTTOPRIMARY ), &mi ) )
{
SetWindowLong( GWL_STYLE, dwStyle & ~WS_OVERLAPPEDWINDOW );
SetWindowPos( HWND_TOP,
mi.rcMonitor.left, mi.rcMonitor.top,
mi.rcMonitor.right - mi.rcMonitor.left,
mi.rcMonitor.bottom - mi.rcMonitor.top,
SWP_NOOWNERZORDER | SWP_FRAMECHANGED );
}
}
else
{
SetWindowLong( GWL_STYLE, dwStyle | WS_OVERLAPPEDWINDOW );
SetWindowPlacement( &m_wpPrev );
SetWindowPos( NULL, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
SWP_NOOWNERZORDER | SWP_FRAMECHANGED );
}
return S_OK;
}