2012-05-08 15 views
9

मैं ऊर्ध्वाधर सिंक रेंडर करने की कोशिश कर रहा हूं ताकि किसी भी फ्रेम को छोड़ने या दोहराने के बिना प्रति वर्टिकल सिंक प्रति ठीक किया जा सके। मुझे विंडोज 7 और (भविष्य में) विंडोज 8 के तहत काम करने की आवश्यकता होगी।प्रति वर्टिकल सिंक (बिल्कुल दोहराना, कोई छोड़ना नहीं) प्रतिपादन कैसे करें?

यह मूल रूप से QUADS का अनुक्रम चित्रित करने वाला होगा जो स्क्रीन के अनुरूप होगा ताकि मूल छवियों से एक पिक्सेल 1: 1 ए से मेल खा सके। स्क्रीन पर पिक्सेल। प्रतिपादन भाग ओपनजीएल या डायरेक्टएक्स के साथ कोई समस्या नहीं है। समस्या सही सिंकिंग है।

मैं पहले, ओपन का उपयोग कर, WGL_EXT_swap_control विस्तार के साथ करने की कोशिश की ड्राइंग और फिर बुला

SwapBuffers(g_hDC); 
glFinish(); 

मैं glFlush (के साथ-साथ सभी संयोजनों और इन दो निर्देशों के क्रमचय की कोशिश की) द्वारा, और यह विश्वसनीय नहीं था।

मैं तो, Direct3D 10 के साथ की कोशिश की ड्राइंग और फिर बुला

g_pSwapChain->Present(1, 0); 
pOutput->WaitForVBlank(); 

जहां g_pSwapChain एक IDXGISwapChain* और pOutputIDXGIOutput* कि SwapChain से जुड़े है से।

दोनों संस्करण, ओपनजीएल और डायरेक्ट 3 डी, इसके परिणामस्वरूप: 60 फ्रेम के पहले अनुक्रम, यह क्या नहीं होना चाहिए (60hz पर 1000ms के बजाय, 1030 या 1050ms की तरह कुछ रहता है), निम्नलिखित लोग ठीक काम करते हैं (लगभग 1000.40ms), लेकिन हर अब और फिर यह एक फ्रेम छोड़ने लगता है। मैं माप QueryPerformanceCounter के साथ करता हूं।

डायरेक्ट 3 डी पर, केवल वेटफॉरवीब्लैंक की लूप की कोशिश कर रहा है, 1000 पुनरावृत्तियों की अवधि लगातार भिन्नता के साथ 1000.40 है।

तो यहां की परेशानी बिल्कुल नहीं जानती है जब प्रत्येक कार्य को वापस बुलाया जाता है, और क्या स्वैप लंबवत सिंक के दौरान किया जाता है (पहले नहीं, फाड़ने से बचने के लिए)।

आदर्श रूप से (यदि मुझे गलत नहीं है), जो मैं चाहता हूं उसे प्राप्त करने के लिए, यह एक रेंडर करने के लिए होगा, सिंक शुरू होने तक प्रतीक्षा करें, सिंक के दौरान स्वैप करें, फिर सिंक पूरा होने तक प्रतीक्षा करें। ओपनजीएल या डायरेक्टएक्स के साथ ऐसा कैसे करें?

संपादित करें: सिर्फ WaitForVSync 60x का एक परीक्षण पाश लगातार 1000.30ms से 1000.50ms पर ले जाता है। Present(1,0) से पहले एक ही लूप, कुछ भी नहीं, कोई प्रतिपादन नहीं, एक ही समय लेता है, लेकिन कभी-कभी यह विफल रहता है और 1017ms लेता है, जैसे कि फ्रेम को दोहराया जाता है। कोई प्रतिपादन नहीं है, इसलिए यहां कुछ गड़बड़ है।

उत्तर

0

एक Direct3D उपकरण बनाते समय, D3DPRESENT_INTERVAL_DEFAULT करने के लिए D3DPRESENT_PARAMETERS संरचना के PresentationInterval पैरामीटर सेट।

+0

क्या यह डीएक्स 10 में भी उपलब्ध है? मैं 'D3D10CreateDeviceAndSwapChain' के साथ डिवाइस बना रहा हूं, जहां तक ​​मैं कह सकता हूं कि कोई वर्तमान पैरामीटर नहीं है। – slazaro

+0

मुझे डर है कि डीएक्स 10 में यह विकल्प नहीं है। क्षमा करें, मैं डीएक्स 10 में ज्यादा नहीं हूं। – miloszmaki

+1

असल में आप इसे भी सेट करना चाहते हैं: D3DPRESENT_INTERVAL_ONE ... और D3D10 अपनी वर्तमान विधि 'swapChain-> वर्तमान (vSync, 0) के माध्यम से बनाम बना देता है;' – zezba9000

2

मैं पहले, ओपन का उपयोग कर, WGL_EXT_swap_control विस्तार के साथ करने की कोशिश की ड्राइंग और फिर बुला

SwapBuffers(g_hDC); 
glFinish(); 

कि glFinish() या glFlush ज़रूरत से ज़्यादा है द्वारा। SwapBuffers एक glfinish का तात्पर्य है।

क्या यह हो सकता है कि आपके ग्राफिक्स ड्राइवर सेटिंग्स में आप "बल वी-ब्लैंक/वी-सिंक ऑफ" सेट करते हैं?

+0

यह प्रत्येक एप्लिकेशन को चुनने के लिए सेट है। मेरे प्रस्तुतकर्ता ऊर्ध्वाधर खाली करने के लिए कम या कम सिंक करते हैं, लेकिन समस्या यह है कि यह लगातार नहीं है (यहां तक ​​कि) खाली रेंडर के साथ भी। – slazaro

+0

@ स्लजारो: आप इसे कैसे मापते हैं? मेरा मतलब है कि एक खाली रेंडर के साथ कोई संकेतक नहीं है जिसका आप उपयोग कर सकते हैं। यदि आप सिस्टम टाइमर का उपयोग कर रहे हैं, तो आपको अवगत होना चाहिए कि यह हमेशा वी-सिंक अंतराल के आसपास झटकेदार होगा, इसे कभी भी – datenwolf

+0

डायरेक्टएक्स के साथ मारने पर, जब मेरे पास 'WaitForVBlank' का सिर्फ एक लूप है, तो यह लगातार चिह्नित करता है एक ही समय के साथ, एक छोटे से भिन्नता के साथ, 1ms से कम। दूसरी तरफ, बनाम और सक्रिय रूप से बनाम swapbuffers के साथ, प्रत्येक रेंडर लगभग 16.6ms लेता है, कुछ को छोड़कर जो दो फ्रेम (~ 33.3ms) लेते हैं। यह देखते हुए कि मैं उस लंबे प्रतिपादन को खर्च नहीं करता (बनाम 60x लूप बनाम बनाम 30 एमएमएस की तरह लेता है), कुछ अविश्वसनीयता है, और मुझे लगता है कि टाइमर की परिशुद्धता पर इसे दोषी ठहराया जा सकता है। – slazaro

3

मुझे DX11 में एक ही समस्या है। मैं गारंटी देना चाहता हूं कि बहु-बफरिंग विलंबता से बचने के लिए, मेरा फ्रेम प्रतिपादन कोड मॉनीटर की रीफ्रेश दर का सटीक एकाधिक लेता है।

बस pSwapChain->present(1,0) पर कॉल करना पर्याप्त नहीं है। इससे फुलस्क्रीन मोड में फाड़ने से रोका जा सकता है, लेकिन यह vblank होने की प्रतीक्षा नहीं करता है। वर्तमान कॉल असीमित है और अगर फ्रेम बफर भरने के लिए शेष हैं तो यह तुरंत वापस आ जाता है। तो यदि आपका रेंडर कोड बहुत तेज़ी से एक नया फ्रेम तैयार कर रहा है (सबकुछ प्रस्तुत करने के लिए 10ms कहें) और उपयोगकर्ता ने ड्राइवर को "अधिकतम प्री-रेंडर फ्रेम" 4 पर सेट किया है, तो आप उपयोगकर्ता को देखे जाने से पहले चार फ्रेम प्रस्तुत करेंगे। इसका मतलब है माउस एक्शन और स्क्रीन प्रतिक्रिया के बीच विलंबता के 4 * 16.7 = 67 एमएमएस, जो अस्वीकार्य है। ध्यान दें कि ड्राइवर की सेटिंग जीतती है - भले ही आपके ऐप ने pOutput->setMaximumFrameLatency(1) के लिए पूछा हो, फिर भी आपको 4 फ्रेम मिलेंगे। इसलिए चालक सेटिंग के बावजूद माउस-लैग की गारंटी देने का एकमात्र तरीका आपके रेंडर लूप के लिए अगले लंबवत रीफ्रेश अंतराल तक स्वेच्छा से प्रतीक्षा करने के लिए है, ताकि आप उन अतिरिक्त फ्रेमबफर का कभी भी उपयोग न करें।

IDXGIOutput::WaitForVBlank() इस उद्देश्य के लिए है। लेकिन यह काम नहीं करता है! जब मैं निम्नलिखित

<render something in ~10ms> 
pSwapChain->present(1,0); 
pOutput->waitForVBlank(); 

संपर्क करें, मैं समय यह waitForVBlank() कॉल वापस जाने के लिए के लिए ले जाता है को मापने, मैं इसे 6ms और 22ms के बीच वैकल्पिक देख रहा हूँ, मोटे तौर पर।

यह कैसे हो सकता है? waitForVBlank() को पूरा करने के लिए कभी भी 16.7ms से अधिक समय लग सकता है? डीएक्स 9 में हमने प्रतीक्षा करने के लिए getRasterState() का उपयोग करके इस समस्या को हल किया है, जो प्रतीक्षाफोरब्लैंक के अपने स्वयं के, अधिक सटीक संस्करण को लागू करने के लिए है। लेकिन उस कॉल को डीएक्स 11 में बहिष्कृत कर दिया गया था।

क्या यह गारंटी देने का कोई अन्य तरीका है कि मेरा फ्रेम मॉनीटर की रीफ्रेश दर के साथ बिल्कुल गठबंधन है? क्या मौजूदा स्कैनलाइन को जासूसी करने का कोई दूसरा तरीका है जैसे GetRasterState करने के लिए उपयोग किया जाता है?

-1

यदि आप कर्नेल-मोड या रिंग -0 में चलाते हैं, तो आप VGA input register (03bah, 03dah) से बिट 3 पढ़ने का प्रयास कर सकते हैं। जानकारी काफी पुरानी है लेकिन हालांकि यह hinted here थी कि बिट ने स्थान बदल दिया हो या विंडोज 2000 के बाद के संस्करण में अप्रचलित हो सकता है, मुझे वास्तव में संदेह है। दूसरे लिंक में कुछ पुराने स्रोत-कोड हैं जो पुराने विंडोज संस्करणों के लिए vblank सिग्नल का पर्दाफाश करने का प्रयास करते हैं। यह अब नहीं चलता है, लेकिन सिद्धांत में इसे नवीनतम विंडोज एसडीके के साथ पुनर्निर्माण करना इसे ठीक करना चाहिए।

कठिन हिस्सा एक डिवाइस ड्राइवर का निर्माण और पंजीकरण कर रहा है जो इस जानकारी को विश्वसनीय रूप से उजागर करता है और फिर इसे आपके आवेदन से लाता है।

1

हम वर्तमान में डीएक्स 9 का उपयोग करते हैं, और डीएक्स 11 पर स्विच करना चाहते हैं। हम स्क्रीन पर मैन्युअल रूप से सिंक करने के लिए वर्तमान में GetRasterState() का उपयोग करते हैं। यह DX11 में चला गया है, लेकिन मुझे पता चला है कि DirectDraw7 डिवाइस बनाना DX11 को बाधित नहीं करता है। तो बस इसे अपने कोड में जोड़ें और आपको स्कैनलाइन स्थिति प्राप्त करने में सक्षम होना चाहिए।

IDirectDraw7* ddraw = nullptr; 
DirectDrawCreateEx(NULL, reinterpret_cast<LPVOID*>(&ddraw), IID_IDirectDraw7, NULL); 
DWORD scanline = -1; 
ddraw->GetScanLine(&scanline); 
1

Windows 8.1 और Windows 10 पर, आप DXGI 1.3 DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT का उपयोग कर सकते। MSDN देखें। यहां नमूना विंडोज 8 स्टोर ऐप के लिए है, लेकिन यह कक्षा Win32 विंडोज़ स्वैपेंस के साथ भी अनुकूल होना चाहिए।

आपको यह video भी उपयोगी मिल सकता है।

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^