Gfxreconstruct replay Linux/Windows game trace

最近在研究vkd3d的性能, 在開始研究之前, 有一個前置任務(wù):
用gfxreconstruct去replay game trace, 同時要確保這個trace既能在windows上面運行, 又能在linux上面運行.
這樣可以方便我們比較linux和windows的差異.
本文記錄一下, 在enable replay trace的時候, 遇到的一些問題, 以及解決方案.

第一個嘗試是: 在windows上面用vkd3d運行dx12 game, 然后把trace抓下來, 再拿到linux上面去replay.
這樣的做法是保證: 游戲看到的vulkan extension在不同OS上是基本一致的(因為都要經(jīng)過vkd3d)

但是當(dāng)我試圖在linux上面replay這個trace的時候, 果不其然失敗了(事情總是沒有那么容易).
遇到了以下錯誤.

  1 [gfxrecon] WARNING - Mismatch:
  2 [gfxrecon] WARNING - Captured application name: Cyberpunk2077.exe
  3 [gfxrecon] WARNING - Replayer process name: gfxrecon-replay.exe
  4 [gfxrecon] WARNING - This can lead to diverging driver behavior between the replayer and captured application
  5 [gfxrecon] WARNING - Recommendation: Rename gfxrecon-replay.exe to match the application's executable name
  6 [gfxrecon] DEBUG - Match: replay-time GPU vs capture-time GPU
  7 [gfxrecon] WARNING - ID3D12Device_CreateComputePipelineState returned S_OK, which does not match the value returned at capture E_INVALIDARG.
  8 [gfxrecon] WARNING - ID3D12Device_CreateComputePipelineState returned S_OK, which does not match the value returned at capture E_INVALIDARG.
  9 [gfxrecon] WARNING - Requested window size (1920x1080) exceeds current screen size (1280x800); replay may fail due to inability to create a window of the a    ppropriate size.
 10 [gfxrecon] WARNING - ID3D12Device_CreatePlacedResource returned E_INVALIDARG, which does not match the value returned at capture S_OK.

關(guān)鍵的錯誤信息是"ID3D12Device_CreatePlacedResource"的失敗調(diào)用.

接下來, 我們打開log開關(guān)(VKD3D_DEBUG=trace, VKD3D_LOG_FILE=vkd3d_trace.log
), 然后在vkd3d里面發(fā)現(xiàn)了一句可疑log.

0128:err:d3d12_resource_create_placed: Heap too small for the texture (heap=3211264, res=3407872.

這個邏輯是對dx12 api - ID3D12Device::CreatePlacedResource的處理. 問題看起來比較清楚了: 當(dāng)它想要把一個texture image放進(jìn)heap的時候, 發(fā)現(xiàn)這個heap太小了, 于是就報錯了.

DX12里面關(guān)于這個API的用法是這樣的:

1. app調(diào)用getResourceAllocationInfo獲取texture image的大小
2. app根據(jù)返回值, 決定自己要創(chuàng)建多大的heap, 然后調(diào)用ID3D12Device::CreateHeap
3. app調(diào)用ID3D12Device::CreatePlacedResource, 把指定的texture放入指定的heap中.

另外, 這里還有一個問題是: 為什么同樣的trace在windows上面replay就不會遇到"heap too small"的情況呢.
通過以下的log, 可以發(fā)現(xiàn): 對于個別texture, 它們的size在windows和linux上面是不一樣的.


image.png

明白了root cause之后, 我做了一個簡單的workaround: 讓getResourceAllocationInfo返回一個原來6倍的值, 這樣的話, 抓下來的trace就能同時滿足windows和linux的size了.

--- a/libs/vkd3d/device.c
+++ b/libs/vkd3d/device.c
@@ -5440,7 +5440,7 @@ static D3D12_RESOURCE_ALLOCATION_INFO* 
 STDMETHODCALLTYPE d3d12_device_GetResourc
              resource_info.Alignment = max(resource_info.Alignment, requested_alignment);
         }

-        resource_info.SizeInBytes = align(resource_info.SizeInBytes, resource_info.Alignment);
+        resource_info.SizeInBytes = align(resource_info.SizeInBytes*6, resource_info.Alignment);
          resource_offset = align(info->SizeInBytes, resource_info.Alignment);

          if (resource_infos)

這個改動是發(fā)生在vkd3d里面的, 所以需要在windows + vkd3d的環(huán)境下, 才可以抓到正確的trace.
但是有些游戲在windows + vkd3d下面不能正確運行, 于是有另一個想法: 在d3d12.dll外面再包一層, 寫一個proxy dll, 游戲是先調(diào)用到proxy dll, 然后proxy dll再調(diào)用到系統(tǒng)的d3d12.dll. 在這個調(diào)用過程中, 我們可以修改getResourceAllocationInfo的返回值.

代碼在這里: https://github.com/Zhiwei-Lii/dx12Wrapper
可以導(dǎo)入到Visual studio里面編譯, 編出來的d3d12.dll是一個proxy dll, 它會調(diào)用d3d12_real.dll (需要把系統(tǒng)的dll重命名成d3d12_real.dll). 然后把d3d12.dll和d3d12_real.dll放到游戲目錄下, 即可運行.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容