2010-09-23 42 views
2

我正在開發一個科學應用程序,它必須估計(儘可能最佳)在視頻緩衝區中繪製的對象與該對象實際上在屏幕上變得可見。換句話說,Windows XP +上的DirectX如何處理顯示器的垂直刷新週期。瞭解IDirect3DDevice9 ::當它阻止vsync時的行爲

我首先說我的視頻例程基於SDL 1.3庫。因此,我無法立即訪問DirectX API,但如有必要,可以對其進行更改。在全屏模式下,DirectX正在使用D3DSWAPEFFECT_DISCARD,D3DPRESENT_INTERVAL_ONE和BackBufferCount = 1進行初始化。這些似乎是最關鍵的參數,但如果需要更多信息,我很樂意深入其他SDL代碼。

D3DPRESENT_INTERVAL_ONE標誌確保後端和前端緩衝區在每個刷新週期內交換不超過一次,並且從不在刷新過程中(基本上啓用vsync)。事實上,如果我有一個簡單的循環,只是不斷調用IDirect3DDevice9 :: Present(在我的情況下爲SDL_RenderPresent),該函數將阻塞兩個刷新週期之間的毫秒數(60Hz爲16.67ms,100Hz爲10ms等) 。

這是我的問題......假設我在後臺緩衝區中繪製一個白色正方形,並調用SDL_RenderPresent,它將阻塞16.67毫秒(假設刷新60Hz)。當對SDL_RenderPresent的調用返回時,我可以得出有關監視器上可見圖像狀態的結論嗎?以下是可能的,因爲我看到它:

  1. 白色方塊是只是繪製的監視器上。
  2. 白色正方形是要繪製(小於1毫秒)。
  3. 上一個前臺緩衝區剛繪製完畢;它會在我的白色方塊出現之前花費另一個刷新週期(16.67 ms)(再次調用SDL_RenderPresent會使我處於情況1)。
  4. 上一個前緩衝區是在最後的16.67 ms中繪製的,我的白色方塊是下一個,但直到下一次刷新的確切時間未知。

從我所做的所有閱讀中,我傾向於選項3,但我無法找到針對4的任何保證。在我的配置中,Present函數應該僅在被調用在兩個刷新週期之間的暫停期間第二次。由於目標是交換前後緩衝區,所以第二次調用可以完成的最早點就是刷新監視器之後(之前的前端緩衝區剛剛繪製完畢)。正是在這一點上,包含我的白方塊的後臺緩衝區可以移動到前端,但它必須等待(最多)16.67毫秒,然後顯示器纔會真正讀取並顯示緩衝區內容。理想情況下,我希望聽到該函數應該在前一個刷新週期結束後立即返回。

任何對DirectX更有經驗的人都可以提供關於此主題的任何見解嗎?我的假設是正確的還是我錯過了什麼?對於任何具有DirectX支持的系統,這些假設是否總是正確的?或者邏輯是否會根據視頻卡,顯示器或其他因素而改變?作爲最後一個小問題,回到剛剛調用SDL_RenderPresent的循環中,我注意到前3或4個調用會立即返回,而所有後續的調用將等待刷新週期。我是否正確地認爲D3DPRESENT_INTERVAL_ONE限制在第一次刷新之前簡單地被忽略(而不是某種排隊發生在我期望擁有的超過2個緩衝區的地方)?

換句話說,假設循環進入〜8ms直到下一個刷新週期。在此期間,它可能會交換正面和背面緩衝區4次。在第一次刷新發生之前,SDL_RenderPresent將立即返回(因爲我們在技術上目前沒有任何前端緩衝區,只有2個後端緩衝區),但只要其中一個緩衝區顯示在屏幕上,阻塞就會開始發生。這是否是一個有效的解釋?

基於下面的回覆[編輯]

,它在使用VSYNC和現在不工作,我的辦法很清楚。我想我找到了另一種達到預期結果的方式,所以我在這裏發佈它,以防有人發現我的想法中的錯誤,或者僅僅是爲了解決類似問題的其他人的信息。

第一步是擺脫D3DPRESENT_INTERVAL_ONE。這將禁用vsync並確保任何對SDL_RenderPresent的調用將立即返回。接下來,您可以使用IDirect3DDevice9 :: GetRasterStatus獲取有關當前監視器狀態的信息。它提供了一個布爾字段,在兩個刷新週期之間的暫停期間設置爲true,另一個字段在活動刷新期間告訴您當前掃描行。使用這兩個信息可以實現自己的垂直同步例程,儘管通過運行一個不斷輪詢監視器狀態並因此消耗100%CPU的循環。這對我的需求是可以接受的。

還有緩衝的問題 - 我怎麼知道當我調用SDL_RenderPresent時在屏幕上繪製哪個幀?我想我找到了一種方法來確定這一點,這依賴於我能夠知道顯示器上當前正在繪製哪條線。基本邏輯如下:

  1. 等待新的刷新週期開始(pause = false,scanline = 0)。
  2. 用紅色填充下一個後臺緩衝區並調用Present。
  3. 等待掃描線達到32.
  4. 用綠色填充下一個後臺緩衝區並調用Present。

等等......在我的演示實現中,我使用了紅色,綠色,藍色,最後是黑色。這個想法是,如果GetRasterStatus提供有關刷新狀態的準確信息,並且在調用SDL_RenderPresent時立即翻轉前後緩衝區,則只會看到RGB顏色模式。如果這些條件中的任何一個都不符合,您可能看不到任何東西,顏色可能會交換或重疊,等等。另一方面,如果您在每個畫面的頂部看到一個固定的RGB圖案,那麼這個證明您可以直接控制繪製的圖像。

我應該補充一點,我在今天工作的幾臺電腦上測試了這個理論。大多數人都展示了這種模式,但至少有一個人把整個屏幕塗成了紅色。少數人會有顏色帶上下跳動,表明交換緩衝區時有些不一致。這通常發生在較舊的機器上。我認爲這是一個很好的校準測試,以確定硬件是否適合我們的測試目的。

回答

3

我強烈建議你看看微軟的GPUView。這裏是介紹該工具的one of the authors webpage

  • D3D通常會緩衝一幀以上的渲染命令(包括禮物)。例如,請參見幻燈片25,我們可以在BumpEarth設備隊列中看到〜3幀被緩衝。這解釋了3-4個呼叫立即返回(當前包是交叉的)。他們剛剛排隊。
  • 除非你做全屏渲染,操作系統需要做一些合成(同一幻燈片顯示了合成發生在垂直同步 - 藍色垂直線)

一些後果:

  • 目前的迴歸並不能保證你的剛剛發送的渲染命令在屏幕上更新。
  • 您的命令渲染幀的持續時間並不容易理解。我已經看到應用程序依賴於以前渲染的時序,進行了平滑處理(以防止乒乓渲染更改)。

作爲補充意見:在現實生活中的工作負載指令緩衝

  • 我目睹〜1.5框架的價值。
  • 即使發生vsync並且視頻卡更新前端緩衝區,監視器仍然可以在內部做一些緩衝(更重要的是,因爲我們將CRT放在後面)。

我必須問,爲什麼你需要準確地控制幀顯示在屏幕上?

+0

感謝您的解釋(儘管這是一個壞消息)。我正在編寫測量人類對科學研究反應時間的軟件。理想情況下,我希望誤差幅度降至1毫秒,但我懷疑如果沒有一些專門的硬件和實時操作系統,這將是可能的。它最終可能會達成。 如果無法控制DirectX如何緩衝幀,通過完全禁用緩衝區和vsync並使用IDirect3DDevice9 :: GetRasterStatus來確定何時可以安全地更新屏幕,是否可以獲得更好的結果? – VokinLoksar 2010-09-23 19:31:54

+0

您可以使用查詢來確保frmae已經被刷新到顯卡......儘管如此,您仍然無法百分之百地確信...一些TFT屏幕也有有趣的延遲。您最好使用高速相機,然後拍攝屏幕和用戶。然後對幀進行計數直到用戶作出反應。一個300fps的相機會給你3毫秒的精度,所以如果你可以得到一個1000fps的相機,你會有你的〜1ms ...在不知道更多關於你的系統的代碼的情況下做到這一點是不可能的,儘管... – Goz 2010-09-24 21:44:25

+0

鏈接已死。你能更新嗎? – 2015-11-17 20:22:17

相關問題