opengl: glFlush () बनाम glFinish ()


105

मुझे कॉल करने glFlush()और के बीच के व्यावहारिक अंतर को समझने में परेशानी हो रही है glFinish()

डॉक्स का कहना है कि glFlush()और glFinish()सभी बफ़र किए गए ऑपरेशन्स को ओएनजीसीएल में धकेल देगा, ताकि किसी को भरोसा दिलाया जा सके कि वे सभी को मार दिया जाएगा, फ़र्क यह जा रहा है कि सभी ऑपरेशन्स पूरे होने तक glFlush()फ़ौरन glFinish()ब्लॉक हो जाते हैं।

परिभाषाओं को पढ़ने के बाद, मुझे लगा कि अगर मैं इसका उपयोग glFlush()करूं तो शायद मैं ओएनजीसीएल को अधिक परिचालन प्रस्तुत करने की समस्या में चला जाऊंगा, जितना कि वह निष्पादित कर सकता है। तो, बस कोशिश करने के लिए, मैंने अपने glFinish()लिए एक glFlush()और लो और निहारना की अदला-बदली की , मेरा कार्यक्रम चला (जहाँ तक मैं बता सकता था), ठीक उसी; फ्रेम दर, संसाधन उपयोग, सब कुछ समान था।

इसलिए मैं सोच रहा था कि क्या दोनों कॉल के बीच बहुत अंतर है, या यदि मेरा कोड उन्हें अलग नहीं चलाता है। या जहां एक का उपयोग दूसरे के विरुद्ध किया जाना चाहिए। मुझे यह भी पता चला कि ओपनजीएल के पास कुछ कॉल glIsDone()करने के लिए जाँच होगी कि क्या सभी बफ़र कमांड glFlush()पूरी तरह से हैं या नहीं (इसलिए कोई भी ओपेनगेल के संचालन को तेजी से नहीं भेज सकता है जितना कि उन्हें निष्पादित किया जा सकता है), लेकिन मुझे ऐसा कोई फ़ंक्शन नहीं मिला ।

मेरा कोड विशिष्ट गेम लूप है:

while (running) {
    process_stuff();
    render_stuff();
}

जवाबों:


93

ध्यान रखें कि OpenGL के शुरुआती दिनों से ये कमांड मौजूद हैं। glFlush सुनिश्चित करता है कि पिछले OpenGL कमांड्स को परिमित समय ( OpenGL 2.1 चश्मा , पृष्ठ 245) में पूरा करना होगा । यदि आप सीधे सामने वाले बफ़र पर जाते हैं, तो यह सुनिश्चित करेगा कि ओपनजीएल ड्राइवर बहुत अधिक देरी के बिना ड्राइंग शुरू कर दें। आप एक जटिल दृश्य के बारे में सोच सकते हैं जो स्क्रीन पर ऑब्जेक्ट के बाद ऑब्जेक्ट दिखाई देता है, जब आप प्रत्येक ऑब्जेक्ट के बाद glFlush कहते हैं। हालांकि, डबल बफरिंग का उपयोग करते समय, glFlush का व्यावहारिक रूप से कोई प्रभाव नहीं पड़ता है, क्योंकि जब तक आप बफ़र्स को स्वैप नहीं करते तब तक परिवर्तन दिखाई नहीं देगा।

glFinish तब तक वापस नहीं आता है जब तक कि पहले जारी किए गए कमांड से सभी प्रभाव [...] पूरी तरह से महसूस नहीं किए जाते हैं । इसका मतलब यह है कि आपके प्रोग्राम का निष्पादन तब तक इंतजार करता है जब तक कि हर आखिरी पिक्सेल न खींचा जाए और ओपनजीएल के पास करने के लिए अधिक कुछ न हो। यदि आप सीधे सामने बफर को रेंडर करते हैं, तो स्क्रीनशॉट लेने के लिए ऑपरेटिंग सिस्टम कॉल का उपयोग करने से पहले glFinish कॉल करना है। यह डबल बफरिंग के लिए बहुत कम उपयोगी है, क्योंकि आप उन परिवर्तनों को नहीं देखते हैं जिन्हें आपने पूरा करने के लिए मजबूर किया है।

इसलिए यदि आप डबल बफरिंग का उपयोग करते हैं, तो आपको शायद glFlush और glFinish की आवश्यकता नहीं होगी। SwapBuffers स्पष्ट रूप से OpenGL कॉल को सही बफर में निर्देशित करते हैं, पहले glFlush को कॉल करने की कोई आवश्यकता नहीं है । और OpenGL के ड्राइवर पर जोर देने से गुरेज न करें: glFlush बहुत सारे कमांड पर चोक नहीं करेगा। यह गारंटी नहीं है कि यह कॉल तुरंत वापस आती है (जो भी इसका मतलब है), इसलिए इसे आपके आदेशों को संसाधित करने में किसी भी समय लग सकता है।


1
आपका क्या मतलब है कि glFlush "को अंतिम समय में पूरा करना होगा" और फिर बाद में कहेंगे, कि glFlush चोक नहीं करेगा क्योंकि "इसे आपकी आज्ञाओं को संसाधित करने में किसी भी समय लग सकता है"? (कैप्स मेरा) उन परस्पर अनन्य नहीं हैं?
प्रैक्सिटेल

1
जब तक यह किसी बिंदु पर समाप्त होता है तब तक यह परिमित समय के मानदंडों को पूरा करता है। कुछ ड्राइवर इस कॉल को पूरी तरह से नहीं कहते हैं।
क्रिस्वर्नज़

SwapBuffers संदर्भ विशिष्ट है और केवल कॉलिंग थ्रेड संदर्भ को फ्लश करने की आवश्यकता है। यदि कई संदर्भों को प्रस्तुत करना प्रत्येक को मैन्युअल रूप से फ्लश किया जाना चाहिए क्योंकि यह किसी अन्य संदर्भ के माध्यम से बफ़र्स को स्वैप करते समय होने के लिए guearanteed नहीं है।
एंड्रियास

22

जैसा कि अन्य उत्तरों ने संकेत दिया है, वास्तव में कल्पना के अनुसार कोई अच्छा जवाब नहीं है। सामान्य अभिप्राय glFlush()यह है कि इसे कॉल करने के बाद, होस्ट सीपीयू के पास ओपन-संबंधित कार्य करने के लिए नहीं होगा - आदेशों को ग्राफिक्स हार्डवेयर में धकेल दिया जाएगा। सामान्य अभिप्राय glFinish()यह है कि इसके वापस आने के बाद, कोई भी कार्य शेष नहीं रहता है, और परिणाम सभी उपयुक्त गैर-ओपनजीएल एपीआई (जैसे कि फ्रेमबफ़र, स्क्रीनशॉट, आदि ... से पढ़ता है) उपलब्ध होना चाहिए। कि क्या वास्तव में क्या होता है ड्राइवर पर निर्भर है। विनिर्देश एक टन अक्षांश को अनुमति देता है जो कि कानूनी है।


18

मैं हमेशा उन दो आदेशों के बारे में भी उलझन में था, लेकिन इस छवि ने मुझे यह सब स्पष्ट कर दिया: फ्लश बनाम खत्म जाहिर तौर पर कुछ जीपीयू चालक जारी किए गए आदेशों को हार्डवेयर तक नहीं भेजते हैं जब तक कि कुछ निश्चित संख्याओं को जमा नहीं किया गया हो। इस उदाहरण में वह संख्या 5 है
छवि विभिन्न OpenGL कमांड (A, B, C, D, E ...) जारी की गई है। जैसा कि हम शीर्ष पर देख सकते हैं, आदेश अभी तक जारी नहीं किए गए हैं, क्योंकि कतार अभी तक भरी नहीं है।

बीच में हम देखते हैं कि glFlush()कतारबद्ध आदेशों को कैसे प्रभावित करता है। यह ड्राइवर को सभी कतारबद्ध कमांड को हार्डवेयर में भेजने के लिए कहता है (भले ही कतार अभी तक पूर्ण न हो)। यह कॉलिंग थ्रेड को ब्लॉक नहीं करता है। यह केवल ड्राइवर को संकेत देता है कि हम कोई अतिरिक्त कमांड नहीं भेज रहे हैं। इसलिए कतार को भरने के लिए इंतजार करना समय की बर्बादी होगी।

नीचे हम एक उदाहरण का उपयोग करते हुए देखते हैं glFinish()। यह लगभग वही काम करता है glFlush(), सिवाय इसके कि यह कॉलिंग थ्रेड को तब तक प्रतीक्षा करता है जब तक कि सभी कमांड हार्डवेयर द्वारा संसाधित नहीं हो जाते।

पुस्तक "ओपन ग्राफिक्स का उपयोग करके उन्नत ग्राफिक्स से ली गई छवि"।


मैं वास्तव में क्या जानते हैं glFlushऔर glFinishकरते हैं, और मैं नहीं बता सकता कि उस छवि को कह रहा है। बाईं ओर और दाईं ओर क्या है? इसके अलावा, वह छवि सार्वजनिक डोमेन में जारी की गई थी या कुछ लाइसेंस के तहत जो आपको इसे इंटरनेट पर पोस्ट करने की अनुमति देती है?
निकोल बोलस जूला

मुझे थोड़ा विस्तार करना चाहिए था। लाइसेंस के बारे में: मैं वास्तव में काफी निश्चित नहीं हूं। मैंने शोध करते हुए, Google पर PDF को ठोकर मार दी।
तारा

7

यदि आपने कोई प्रदर्शन अंतर नहीं देखा है, तो इसका मतलब है कि आप कुछ गलत कर रहे हैं। जैसा कि कुछ अन्य ने उल्लेख किया है, आपको या तो कॉल करने की आवश्यकता नहीं है, लेकिन यदि आप कॉल करते हैं glFinish, तो आप स्वचालित रूप से उस समानता को खो रहे हैं जिसे GPU और CPU प्राप्त कर सकते हैं। मुझे और गहरा डुबाने दो:

व्यवहार में, ड्राइवर को आपके द्वारा सबमिट किए गए सभी काम को बैच दिया जाता है, और बाद में संभावित रूप से हार्डवेयर पर भेज दिया जाता है (जैसे कि स्वैगफ्लू समय)।

इसलिए, अगर आप glFinish कह रहे हैं, तो आप अनिवार्य रूप से ड्राइवर को कमांड को GPU पर धकेलने के लिए मजबूर कर रहे हैं (कि यह तब तक बैचेन था, और कभी भी GPU को काम करने के लिए नहीं कहा था), और CPU को तब तक स्टाल करें जब तक कि कमांड पूरी तरह से धकेल न दें। मार डाला। तो पूरे समय के दौरान GPU काम करता है, CPU (कम से कम इस थ्रेड पर) नहीं करता है। और हर समय सीपीयू अपना काम करता है (ज्यादातर बैचिंग कमांड), GPU कुछ भी नहीं करता है। तो हाँ, glFinish आपके प्रदर्शन को चोट पहुँचानी चाहिए। (यह एक सन्निकटन है, क्योंकि ड्राइवर कुछ कमांड पर GPU का काम करना शुरू कर सकते हैं यदि उनमें से बहुत पहले से ही बैचेन थे। हालांकि यह विशिष्ट नहीं है, क्योंकि कमांड बफ़र काफी बड़ी संख्या में कमांड रखने के लिए काफी बड़ा है)।

अब, आप glFinish को आखिर क्यों कहेंगे? केवल बार मैंने इसका उपयोग किया है जब मेरे पास ड्राइवर बग थे। वास्तव में, यदि आप नीचे भेजे गए कमांडों में से एक को GPU को क्रैश कर देते हैं, तो यह पहचानने का आपका सबसे सरल विकल्प है कि प्रत्येक ड्रॉ के बाद कौन सा कमांड अपराधी को glFinish कॉल करना है। इस तरह, आप दुर्घटना को ठीक से कम कर सकते हैं

एक साइड नोट के रूप में, Direct3D जैसे API एक खत्म अवधारणा का समर्थन नहीं करते हैं।


5
"अब, आप ग्लिफ़िश को आखिर क्यों कहेंगे"। यदि आप एक थ्रेड पर संसाधन (जैसे: बनावट) लोड कर रहे हैं और दूसरे पर रेंडर करने के लिए उनका उपयोग कर रहे हैं, तो wglShareLists या similars के माध्यम से साझा करने के साथ, आपको रेंडरिंग थ्रेड को संकेत देने से पहले glFinish को कॉल करने की आवश्यकता है जो यह प्रस्तुत करने के लिए स्वतंत्र है कि अतुल्यकालिक रूप से लोड किया गया है।
मार्को एमपीपी

जैसा कि मैंने नीचे कहा, यह ड्राइवर बग वर्कअराउंड की तरह दिखता है। मुझे इस आवश्यकता का कोई विशेष उल्लेख नहीं मिल रहा है। विंडोज़ पर ड्राइवर को एक ताला लेना चाहिए, मैक पर आपको सीजीएललॉक कॉन्टेक्स्ट करना होगा। लेकिन glFinish का उपयोग करना बहुत गलत लगता है। यह जानने के लिए कि कब बनावट मान्य है, आपको किसी भी स्थिति में अपना स्वयं का लॉक या ईवेंट करना होगा।
starmole

1
opencl opengl interop डॉक्स सिंक्रोनाइज़ेशन के लिए glFinish की सलाह देते हैं "clEnqueueAcquireGLObjects को कॉल करने से पहले, एप्लिकेशन को यह सुनिश्चित करना चाहिए कि कोई भी लंबित GL ऑपरेशंस जो mem_objecter में निर्दिष्ट ऑब्जेक्ट्स तक पहुंच चुके हैं, पूरा हो गया है। यह जारी करके और सभी पर glFinish कमांड के पूरा होने का इंतजार करके इसे आंशिक रूप से पूरा किया जा सकता है। GL इन वस्तुओं के लंबित संदर्भों के संदर्भ में है "
मार्क एस्सेल

1
आपको glFinish को कॉल करने के लिए "आवश्यकता" नहीं है, आप सिंक ऑब्जेक्ट्स का उपयोग कर सकते हैं।
क्रिसवर्जन

बस जोड़ने के लिए, मूल उत्तर के बाद से: कुछ जीएल कार्यान्वयन ने विभिन्न थ्रेड्स पर साझा संदर्भों के बीच फ्लश / फिनिश का उपयोग करने के लिए शुरू किया: डेवलपर .apple.com/library/ios/documentation/3DDrawing/… - सबसे उल्लेखनीय Apple IOS। मुझे लगता है कि यह मौलिक रूप से एपीआई का एक और दुरुपयोग है। लेकिन यह मेरे मूल जवाब के लिए एक चेतावनी है: कुछ कार्यान्वयन पर खत्म / फ्लश की आवश्यकता होती है। लेकिन कार्यान्वयन को कैसे और क्यों परिभाषित किया गया है, OpenGL युक्ति नहीं।
स्टॉर्मोल

7

glFlush वास्तव में एक क्लाइंट सर्वर मॉडल पर वापस आता है। आप सभी gl कमांड को एक पाइप से एक gl सर्वर पर भेजते हैं। वह पाइप बफर हो सकता है। किसी भी फाइल या नेटवर्क की तरह i / o बफर हो सकता है। glFlush केवल यह कहता है कि "अभी बफ़र भेजें, भले ही वह अभी पूरा न हो!"। एक स्थानीय प्रणाली पर यह लगभग कभी भी आवश्यक नहीं है क्योंकि एक स्थानीय ओपनजीएल एपीआई खुद को बफर करने की संभावना नहीं है और बस सीधे आदेश जारी करता है। इसके अलावा सभी कमांड जो वास्तविक रेंडरिंग का कारण बनते हैं, एक निहित फ्लश करेंगे।

दूसरी ओर glFinish प्रदर्शन माप के लिए बनाया गया था। जीएल सर्वर के लिए एक पिंग की तरह। यह एक कमांड को राउंडट्रीप करता है और तब तक इंतजार करता है जब तक सर्वर "आई एम आइडल" का जवाब नहीं देता।

आजकल के आधुनिक, स्थानीय ड्राइवरों में काफी रचनात्मक विचार हैं, हालांकि इसका निष्क्रिय होने का क्या मतलब है। क्या यह "सभी पिक्सेल तैयार हैं" या "मेरी कमांड कतार में जगह है"? इसके अलावा, क्योंकि कई पुराने कार्यक्रमों ने बिना किसी कारण के अपने पूरे कोड में glFlush और glFinish का छिड़काव किया, क्योंकि कई आधुनिक ड्राइवर कोडिंग करते हुए उन्हें "अनुकूलन" के रूप में अनदेखा करते हैं। वास्तव में इसके लिए उन्हें दोषी नहीं ठहरा सकते।

तो सारांश में: दोनों glFinish और glFlush का व्यवहार करें क्योंकि जब तक आप एक प्राचीन दूरस्थ SGI OpenGL सर्वर के लिए कोडिंग नहीं करते हैं, तब तक कोई भी अभ्यास नहीं करता है।


4
गलत। जैसा कि टिप्पणी में मैंने ऊपर दिए गए उत्तर में छोड़ दिया है: यदि आप एक धागे पर संसाधन (जैसे: बनावट) लोड कर रहे हैं और दूसरे पर रेंडर करने के लिए उनका उपयोग कर रहे हैं, तो wglShareLists या similars के माध्यम से साझा करने के साथ, आपको रेंडरिंग थ्रेड को संकेत करने से पहले glFinish को कॉल करने की आवश्यकता है। यह कि अतुल्यकालिक लोड किया गया है रेंडर करने के लिए स्वतंत्र है। और यह कोई पसंद नहीं है जैसा आपने कहा।
मार्को एमपीपी

वास्तव में? क्या आप कुछ विशेष लिंक के साथ एक साझा वस्तु का उपयोग करने से पहले glFinish को कॉल करने की आवश्यकता को वापस कर सकते हैं? मैं पूरी तरह से एक छोटी गाड़ी चालक को देख सकता हूं जिसे इसकी आवश्यकता है। और उस तरह से जो मैंने कहा था वह वापस मिल जाता है। लोग छोटी गाड़ी चालकों के आसपास काम करने के लिए glFinish का उपयोग करते हैं। उसके कारण जो ड्राइवर ठीक से काम करते हैं, वे प्रदर्शन के लिए इसे अनदेखा कर देते हैं। प्रोफाइलिंग (और एकल बफ़र्ड रेंडरिंग) का मूल ऐनक उपयोग मामला अब काम नहीं करता है।
3

2
दूषित बनावट से निपटने के लिए व्यक्तिगत अनुभव, इसके अलावा: highorderfun.com/blog/2011/05/26/… यदि आप इसके बारे में सोचते हैं, तो यह समझ में आता है, हालांकि, यह म्यूटेक्स या अन्य सिंक होने से बहुत अलग नहीं है। थ्रेड्स के बीच एपी - एक संदर्भ से पहले एक साझा संसाधन का उपयोग कर सकते हैं दूसरे को उस संसाधन की लोडिंग को पूरा करना होगा, इस प्रकार बफर को खाली करने की आवश्यकता है। मुझे लगता है कि बग के चश्मे के कोने-मामले के अधिक, लेकिन मेरे पास इस कथन का कोई सबूत नहीं है :)
मार्को एमपीपी

बहुत बढ़िया जवाब, धन्यवाद। विशेष रूप से "कई पुराने कार्यक्रमों ने वूडू के रूप में बिना कारण के अपने पूरे कोड में ग्लफ्लश और ग्लिफ़िश छिड़का।"
एकुप्पी '

क्या यह वास्तव में कोई ऑप्स नहीं है? GlFinish और / या glFlush उच्च तीव्रता छवि प्रसंस्करण या GPU आधारित गणित सहसंसाधक के लिए अत्यधिक मूल्यवान नहीं हैं? उदाहरण के लिए, हम पिक्सेल बफ़र से सीपीयू में GPU गणना के परिणामों को नहीं पढ़ते हैं, जब तक कि सभी पिक्सेल संगणनाओं को लिखना सुनिश्चित करने के लिए glFinish कॉल करने के बाद । क्या हम कुछ याद कर रहे हैं?
प्रैक्सिटेल

5

यहाँ एक नज़र है । संक्षेप में, यह कहता है:

glFinish () का glFlush () के समान प्रभाव है, इसके अलावा glFinish () तब तक ब्लॉक रहेगा जब तक कि सभी कमांड्स निष्पादित नहीं हो जाते।

एक अन्य लेख अन्य अंतरों का वर्णन करता है:

  • स्वैप फ़ंक्शंस (डबल-बफ़र एप्लिकेशन में प्रयुक्त) स्वचालित रूप से कमांड को फ्लश करते हैं, इसलिए कॉल करने की आवश्यकता नहीं होती है glFlush
  • glFinish OpenGL को बकाया कमांड्स करने के लिए मजबूर किया जाता है, जो एक बुरा विचार है (जैसे VSync के साथ)

संक्षेप में, इसका मतलब है कि आपको डबल बफ़रिंग का उपयोग करते समय इन कार्यों की आवश्यकता नहीं है, सिवाय इसके कि अगर आपके स्वैप-बफ़र्स कार्यान्वयन स्वचालित रूप से कमांड को फ्लश नहीं करते हैं।


हां सही है, लेकिन दस्तावेज़ का कहना है कि दोनों का एक ही प्रभाव है, उदाहरण के लिए, विंडो सिस्टम से संबंधित कुछ अंतर। लेकिन वैसे भी मैंने अपना जवाब संपादित किया;)
23

बारीकियों पर अच्छा कॉल आया। यह स्पष्ट करता है कि क्या glFlush () और THEN glFinish () को कॉल करना आवश्यक है - (एक प्रश्न जो हमने ऊपर सब कुछ पढ़ने के बाद किया था।)
प्रैक्सिटेलस

4

वहाँ बफर की स्थिति को क्वेरी करने का एक तरीका नहीं लगता है। यह Apple एक्सटेंशन है जो एक ही उद्देश्य को पूरा कर सकता है, लेकिन यह क्रॉस-प्लेटफ़ॉर्म नहीं लगता है (इसे आज़माया नहीं गया है।) यह त्वरित नज़र में, यह पहले लगता है कि flushआप बाड़ कमांड को धक्का देंगे; फिर आप उस बाड़ की स्थिति को क्वेरी कर सकते हैं क्योंकि यह बफर के माध्यम से चलती है।

मुझे आश्चर्य है कि यदि आप flushकमांड को बफर करने से पहले उपयोग कर सकते हैं , लेकिन अगले फ्रेम को कॉल करने के लिए शुरुआत करने से पहले finish। यह आपको अगला फ्रेम प्रसंस्करण शुरू करने की अनुमति देगा क्योंकि GPU काम करता है, लेकिन यदि यह आपके द्वारा वापस पाने के समय तक नहीं किया जाता है, तो यह finishसुनिश्चित करेगा कि सब कुछ एक ताजा स्थिति में हो।

मैंने यह कोशिश नहीं की है, लेकिन मैं शीघ्र ही करूँगा।

मैंने इसे एक पुराने एप्लिकेशन पर आज़माया है जिसमें सीपीयू और जीपीयू का भी उपयोग किया गया है। (यह मूल रूप से इस्तेमाल किया जाता है finish।)

जब मैंने इसे flushअंत में और finishशुरुआत में बदल दिया , तो तत्काल कोई समस्या नहीं थी। (सब कुछ ठीक लग रहा था!) ​​कार्यक्रम की जवाबदेही बढ़ गई, शायद इसलिए कि सीपीयू जीपीयू पर इंतजार नहीं कर रहा था। निश्चित रूप से एक बेहतर तरीका।

तुलना के लिए, मैंने finishedफ्रेम की शुरुआत से हटा दिया , छोड़ दिया flush, और इसने वही प्रदर्शन किया।

तो मैं कहूंगा कि उपयोग करें flushऔर finish, क्योंकि जब कॉल करने के लिए बफर खाली finishहोता है, तो कोई प्रदर्शन हिट नहीं होता है। और मैं अनुमान लगा रहा हूं कि क्या बफ़र भरा हुआ था, आपको finishवैसे भी चाहिए ।


0

सवाल यह है कि क्या आप चाहते हैं कि ओपनजीएल कमांड निष्पादित होने के बाद भी आपका कोड चालू रहे या आपके ओपनजीएल कमांड निष्पादित होने के बाद ही चले ।

यह मामलों में, नेटवर्क विलंब की तरह, केवल कुछ कंसोल आउटपुट के लिए ही मायने रख सकता है छवियों को खींचे जाने के बाद या इस तरह के होने के लिए।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.