You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DX9 GetMessage帧率下降求助:游戏透明Overlay帧率异常

解决游戏Overlay的帧率异常问题

伙计,咱们来一步步拆解你遇到的两个帧率问题,先从最明显的坑开始挖:


问题1:帧率显示超200但游戏仍卡顿

你的窗口过程(WinProc)里藏了个致命操作:Sleep(17);。这行代码会阻塞所有消息的处理——不管是WM_PAINT、WM_SIZE还是其他系统消息,每处理一个都要等17ms。

这会导致两个后果:

  • Overlay自身的消息响应严重延迟,哪怕Render函数跑的帧率很高,实际画面更新的时机被强行拖慢,主观上就会觉得卡顿;
  • 系统消息队列堆积,间接抢占游戏的CPU资源,拖慢游戏本身的运行。

修复方案:

直接删掉WinProc里的Sleep(17);,帧率控制应该放在Render循环里,而不是消息处理的关键路径上:

LRESULT CALLBACK WinProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam){
 // 移除这行阻塞代码!
 // Sleep(17);
 switch (Message) {
 case WM_PAINT:
 Render();
 break;
 case WM_CREATE:
 DwmExtendFrameIntoClientArea(hWnd, &Margin);
 break;
 case WM_DESTROY:
 PostQuitMessage(1);
 return 0;
 default:
 return DefWindowProc(hWnd, Message, wParam, lParam);
 break;
 }
 return 0;
}

另外,你可以给Render函数加合理的帧率控制,比如开启垂直同步避免GPU空转,同时在游戏非前台时降低渲染频率:

int Render(){
 if(tWnd != GetForegroundWindow()){
 // 游戏不在前台时,减少渲染频率,节省资源
 Sleep(100);
 return 0;
 }
 p_Device->Clear(0, 0, D3DCLEAR_TARGET, 0, 1.0f, 0);
 p_Device->BeginScene();
 g_vCenterScreen.x = Width / 2.f;
 g_vCenterScreen.y = Height / 2.f;
 //draw stuff
 p_Device->EndScene();
 // 开启垂直同步,让帧率和显示器刷新率同步
 p_Device->PresentEx(0, D3DPRESENT_INTERVAL_ONE, 0, 0, 0);
 return 0;
}

问题2:SetWindowToTarget导致每10秒帧率骤降

你的窗口调整线程存在两个问题:

  1. 每5秒无条件执行MoveWindow,哪怕窗口位置/大小根本没变化;
  2. MoveWindow最后一个参数设为true,会立即触发WM_PAINT,瞬间产生大量消息,导致帧率波动。

修复方案:

缓存目标窗口的状态,只在实际变化时才更新Overlay,同时避免强制立即重绘:

void SetWindowToTarget(){
 HWND cachedWnd = nullptr;
 RECT cachedRect = {0};
 // 降低线程优先级,避免抢占游戏资源
 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
 while(true){
 HWND currentWnd = FindWindow(0, tWindowName);
 if (currentWnd) {
 RECT currentSize;
 GetWindowRect(currentWnd, &currentSize);
 // 只有当窗口句柄、位置或大小变化时,才更新Overlay
 if (currentWnd != cachedWnd || 
 currentSize.left != cachedRect.left || 
 currentSize.top != cachedRect.top || 
 currentSize.right != cachedRect.right || 
 currentSize.bottom != cachedRect.bottom) {
 cachedWnd = currentWnd;
 cachedRect = currentSize;
 Width = currentSize.right - currentSize.left;
 Height = currentSize.bottom - currentSize.top;
 // 用GetWindowLongPtr适配64位系统,替代过时的GetWindowLong
 DWORD dwStyle = GetWindowLongPtr(currentWnd, GWL_STYLE);
 if(dwStyle & WS_BORDER) {
 currentSize.top += 23;
 Height -= 23;
 }
 // 最后一个参数设为false,避免立即重绘
 MoveWindow(hWnd, currentSize.left, currentSize.top, Width, Height, false);
 // 手动触发一次重绘,让系统在合适时机处理
 InvalidateRect(hWnd, nullptr, true);
 }
 } else {
 // 目标窗口消失时重置缓存
 cachedWnd = nullptr;
 }
 Sleep(5000);
 }
}

额外优化建议

  • 确保Overlay的窗口属性设置正确,比如使用WS_EX_TRANSPARENT和WS_EX_LAYERED来减少系统绘制开销;
  • 避免在Render函数里执行不必要的计算(比如你现在的g_vCenterScreen计算,可以放在窗口大小变化时执行,而不是每次渲染都算)。

内容的提问来源于stack exchange,提问作者Cow Nation

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:53:47