微软的大坑

微软的文章里说了从dx11开始不推荐使用 DXGI_SWAP_EFFECT_DISCARD 和 DXGI_SWAP_EFFECT_SEQUENTIAL 这两种交换模式,取而代之的则是 DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL 和 DXGI_SWAP_EFFECT_FLIP_DISCARD 这两种新的模式,称之为DXGI Flip Model。

踩坑之一

新的Flip Model要求swapchain的buffer count必须大于等于2,开始没注意,连续报参数错误都没反应过来。这个要求相当于默认开启了两重帧缓冲。还挺好。

踩坑之二

欢天喜地的换上新的,一看好嘛,帧率锁死60了,这根本不符合我的要求啊。微软信誓旦旦的说新的模型更符合现代游戏要求,效率更高,更省电。

我看他就是冲着省电去的╭(╯^╰)╮。那咋办,开始翻微软的文档也死活找不到,资料少的可怜等于没有资料。官方文档也不给个样例什么的。

微软为什么会有限制

按照微软的技术博客说的,以前是DirectX11时代直接和显卡通信,由显卡直接更新应用程序的画面,由于伟大的UWP战略,所以Win32App的画面更新也被DWM接管了,新的Flip模式就是交给DWM桌面显示管理器来更新画面的,DWM检测显示器的帧率来锁定。所以启用 DXGI Flip Model 后显卡更新就降低了,并且可以只更新脏区域(应该是给那种用Dx绘图的App用的,但是对游戏没有用啊)。

解决

说真的相信DirectX资料国外多的我真的傻了,最后还是在知乎上查到的方案噗。指路链接

话不多说,解除锁帧需要新设置两个参数,第一个在创建交换链,上代码。

DXGI_SWAP_CHAIN_DESC1 sd;
ZeroMemory(&sd, sizeof(sd));
......
sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;

/* 检测是否支持帧率无限制 */
auto                  allowTearing = FALSE;
ComPtr<IDXGIFactory5> dxgiFactory5;
DxDebug(hr = dxgiFactory.As(&dxgiFactory5));
if (SUCCEEDED(hr)) {
	hr = dxgiFactory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing));
	_allowTearing = allowTearing;
}

if (FAILED(hr) || !allowTearing) {
	OutputDebugStringA("WARNING: Variable refresh rate displays are not supported.\n");
	_allowTearing = false;
}

sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.BufferCount = 2;
sd.SwapEffect  = DXGI_SWAP_EFFECT_FLIP_DISCARD;
sd.Flags       = _allowTearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;

第二个需要改动的地方在Present的时候,代码:

swapChain->Present(0, _allowTearing ? DXGI_PRESENT_ALLOW_TEARING : 0)

//注意如果有Resize操作,同样要更新Resize的Flags
swapChain->ResizeBuffers(2, _clientWidth, _clientHeight, DXGI_FORMAT_R8G8B8A8_UNORM,	_allowTearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0)

问题

窗口模式下确实可以解除限制了,但是帧率没有传统模式下那么高,然而一旦全屏,甚至能比传统模式还要快。这个问题目前还是没搞明白为什么。

说点什么
支持Markdown语法
好耶,沙发还空着ヾ(≧▽≦*)o
Loading...