2019年12月9日 星期一

考慮 Direct3D12 的 Fence 會溢位的問題

考慮 Direct3D12 的 Fence 會溢位的問題

前言

  在 [ GitHub ] Direct3D12 的教學範例 中, Fence 在使用時沒考慮"溢位"的問題,本以為是"溢位"也能自動處理,但如果把 Fence 的初始值改成即將"溢位"的數值會發現 Debug mode 會回報錯誤,表示"溢位"並不會自動處理,這次就來研究一下"溢位"的問題,在此做個紀錄。

內容

  關於 Fence 的說明在搜尋後發現都用很簡短的方式說明它的用處,加上我剛學習 Direct3D12 ,所以我至今都不太了解這個元件。我對 Fence 的認知是它其實就是個計數器,型別是 UINT64 ,每當 CommandQueue 執行完一個 CommandList 後,它就會計數一次,這個計數的量是不能控制的,只能是每個 CommandList 都"+1",最多能控制計數器的初始值, ID3D12CommandQueue::Signal() 的時候的第二個參數是設定一個期望在計數到計數到的數值,然後 ID3D12Fence::GetCompletedValue() 取得的是目前計數器的數值,如果計數器的值尚未達到期望值就透過 ID3D12Fence::SetEventOnCompletion() 來等待數值達到期望值,在 [ GitHub ] Direct3D12 的教學範例 的範例程式碼如下
 
const UINT64 fence = m_fenceValue;
ThrowIfFailed(m_commandQueue->Signal(m_fence.Get(), fence));
m_fenceValue++;

if (m_fence->GetCompletedValue() < fence)
{
 ThrowIfFailed(m_fence->SetEventOnCompletion(fence, m_fenceEvent));
 WaitForSingleObject(m_fenceEvent, INFINITE);
}

這個範例其實沒考慮 Fence 的數值如果發生"溢位"的狀況,該如何解決呢?很直覺,重製計數器的數值,透過 ID3D12Fence::Signal() 可以重製計數器的數值,修改的範例如下
const UINT64 fence = m_fenceValue;
if(m_fenceValue == UINT64_MAX)
{
    //Reset fence value
    m_fence->Signal(0);
    m_fenceValue = 0;
}
ThrowIfFailed(m_commandQueue->Signal(m_fence.Get(), fence));
m_fenceValue++;

if (m_fence->GetCompletedValue() < fence)
{
 ThrowIfFailed(m_fence->SetEventOnCompletion(fence, m_fenceEvent));
 WaitForSingleObject(m_fenceEvent, INFINITE);
}

當數值到達"溢位"的數值後執行重製,很簡單。雖然我沒實驗過,但根據 [ MSDN ] ID3D12Fence interface 的說法,Fence 是一個 CPU 與 GPU 都會存取的數值, Fence 的計數是由 GPU 來存取數值,而 ID3D12Fence::Signal() 是由 CPU 來存取數值,所以重製動作不應該常常執行(每個 Frame )。

參考資料

[ GitHub ] Direct3D12 的教學範例
[ MSDN ] ID3D12Fence interface

沒有留言:

張貼留言