使用 full-screen window 而多个其他 windows 打开时帧率非常低
Very low framerate when using full-screen window while multiple other windows are open
抱歉,标题太长了,但我有一个非常具体的问题,无法更简洁地表达。我正在编写一个游戏引擎 (GitHub link: here),我试图让客户端在主 window 之上创建 windows应用程序自动提供。
我已经完全设法让它工作了,但我对主 window 进入 full-screen 模式时的帧率感到困扰(无论是在初始化时还是当用户按下 alt 时+输入)。我没有对性能进行基准测试,但它明显很差(所以可能大约 20-30 FPS)并且性能仅在用户创建另一个 window 时下降(甚至不必显示)。
由于用户创建的所有 windows 都是主要 window 的 children,我必须在进入 full-screen 模式之前隐藏它们。
我的 window class 中有很多代码(超过 1000 行),因此给您一个最小的示例将非常困难。如果您必须查看代码,请访问 GitHub 存储库(在 platform/windows 下您会找到我引用的代码)。我想知道这是否是在同一进程中打开多个 windows 的奇怪产物,或者我是否只是缺少一些代码。
也就是说,这是一些实际的客户端代码:
SandboxApp.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);
};
SanboxApp.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 ¶ms = 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;
}
如果您需要任何其他信息,请发表评论。
提前致谢! :)
更新
我尝试将我的可执行文件添加到图形性能选项列表,但它并没有改变 full-screen window.
的低帧率
我做了一些更多的测试,发现我只需要创建 sub-window 就可以使这些低效率发生。即使我不显示、更新或渲染 window,简单地创建它也会降低我的 full-screen 主 window.
的帧速率
尝试做更多研究后,我意识到 MSDN 没有任何关于使用多个 DXGI 交换链的文档。我的直觉是,将一个交换链的 full-screen 状态设置为 true 会以某种方式干扰另一个交换链,导致效率低下(尽管我的 ID3D11Device 调试输出没有在任何地方提到效率低下)
Windows有2种全屏。
真正的全屏可能就是你正在做的,调用 IDXGISwapChain::SetFullscreenState。在此模式下,windows 桌面合成器 dwm.exe 被禁用,让您的应用独占访问监视器。但是,正如您发现的那样,它有并发症。还有更多 顺便说一句:alt+tab 可能会很慢,来自其他应用程序的弹出窗口可能会出现故障,而且正确实施也很棘手,我认为您必须重新创建交换链和所有渲染目标。从好的方面来说,在极少数情况下,它可能会将 FPS 提高一位数。
Borderless windowed 是您应该做的,因为您需要多个 Win32 windows 运行 以及全屏内容。在此模式下,桌面合成器启动并 运行,与其他人一起更新您的 window。进入和退出该模式也更容易,示例如下。
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;
}
抱歉,标题太长了,但我有一个非常具体的问题,无法更简洁地表达。我正在编写一个游戏引擎 (GitHub link: here),我试图让客户端在主 window 之上创建 windows应用程序自动提供。
我已经完全设法让它工作了,但我对主 window 进入 full-screen 模式时的帧率感到困扰(无论是在初始化时还是当用户按下 alt 时+输入)。我没有对性能进行基准测试,但它明显很差(所以可能大约 20-30 FPS)并且性能仅在用户创建另一个 window 时下降(甚至不必显示)。
由于用户创建的所有 windows 都是主要 window 的 children,我必须在进入 full-screen 模式之前隐藏它们。
我的 window class 中有很多代码(超过 1000 行),因此给您一个最小的示例将非常困难。如果您必须查看代码,请访问 GitHub 存储库(在 platform/windows 下您会找到我引用的代码)。我想知道这是否是在同一进程中打开多个 windows 的奇怪产物,或者我是否只是缺少一些代码。
也就是说,这是一些实际的客户端代码:
SandboxApp.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);
};
SanboxApp.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 ¶ms = 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;
}
如果您需要任何其他信息,请发表评论。
提前致谢! :)
更新
我尝试将我的可执行文件添加到图形性能选项列表,但它并没有改变 full-screen window.
我做了一些更多的测试,发现我只需要创建 sub-window 就可以使这些低效率发生。即使我不显示、更新或渲染 window,简单地创建它也会降低我的 full-screen 主 window.
的帧速率尝试做更多研究后,我意识到 MSDN 没有任何关于使用多个 DXGI 交换链的文档。我的直觉是,将一个交换链的 full-screen 状态设置为 true 会以某种方式干扰另一个交换链,导致效率低下(尽管我的 ID3D11Device 调试输出没有在任何地方提到效率低下)
Windows有2种全屏。
真正的全屏可能就是你正在做的,调用 IDXGISwapChain::SetFullscreenState。在此模式下,windows 桌面合成器 dwm.exe 被禁用,让您的应用独占访问监视器。但是,正如您发现的那样,它有并发症。还有更多 顺便说一句:alt+tab 可能会很慢,来自其他应用程序的弹出窗口可能会出现故障,而且正确实施也很棘手,我认为您必须重新创建交换链和所有渲染目标。从好的方面来说,在极少数情况下,它可能会将 FPS 提高一位数。
Borderless windowed 是您应该做的,因为您需要多个 Win32 windows 运行 以及全屏内容。在此模式下,桌面合成器启动并 运行,与其他人一起更新您的 window。进入和退出该模式也更容易,示例如下。
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;
}