Android रुकने पर OpenGL संदर्भ खोने के लिए समाधान?


40

Android प्रलेखन कहता है:

ऐसी परिस्थितियां हैं जहां ईजीएल प्रतिपादन संदर्भ खो जाएगा। यह आमतौर पर तब होता है जब डिवाइस सोने के बाद उठता है। जब ईजीएल संदर्भ खो जाता है, तो उस संदर्भ से जुड़े सभी ओपनजीएल संसाधन (जैसे बनावट) स्वचालित रूप से हटा दिए जाएंगे। रेंडरिंग को सही ढंग से रखने के लिए, एक रेंडरर को किसी भी खोए हुए संसाधनों को फिर से बनाना होगा जो उसे अभी भी चाहिए। OnSurfaceCreated (GL10, EGLConfig) विधि ऐसा करने के लिए एक सुविधाजनक स्थान है।

लेकिन OpenGL संदर्भ में सभी बनावट को फिर से लोड करने के लिए दोनों एक दर्द है और एक ठहराव के बाद एप्लिकेशन को पुन: प्रस्तुत करते समय उपयोगकर्ता के लिए खेल के अनुभव को नुकसान पहुंचाता है। मुझे पता है कि "एंग्री बर्ड्स" किसी तरह से इससे बचता है, मैं सुझाव दे रहा हूं कि इसे कैसे पूरा किया जाए?

मैं एंड्रॉइड NDK r5 (CrystaX संस्करण) के साथ काम कर रहा हूं। मुझे यह समस्या के लिए संभव हैक मिल गया, लेकिन मैं एक संपूर्ण कस्टम एसडीके संस्करण बनाने से बचने की कोशिश कर रहा हूं।


सोते और जागते समय डिवाइस को संदर्भित किया जाता है, जबकि उपयोगकर्ता केवल आपके गेम को रोकते हैं या स्विच की प्रक्रिया करते हैं, इसे किसी भी ईजीएल संदर्भ को ढीला करना चाहिए।
अली

जवाबों:


22

प्रतिकृति द्वीप में GLSurfaceView का एक संशोधित संस्करण है जो इस मुद्दे से संबंधित है (और पहले के एंड्रॉइड संस्करणों के साथ काम करता है)। क्रिस प्रुइट के अनुसार :

मूल रूप से, मैंने एक बहुत ही विशिष्ट समस्या को हल करने के लिए मूल GLSurfaceView को हैक किया: मैं अपने सभी OpenGL राज्य को फेंक दिए बिना अपने ऐप के भीतर विभिन्न गतिविधियों में जाना चाहता था। मुख्य परिवर्तन ईजीएलसर्फ़ को ईजीएलसीनेट से अलग करना, और पूर्व को ऑनपॉज़ () से दूर फेंकना था, लेकिन बाद को संरक्षित करें जब तक कि संदर्भ स्पष्ट रूप से खो न जाए। GLSurfaceView का डिफ़ॉल्ट कार्यान्वयन (जो मैंने नहीं लिखा था), गतिविधि के रुकने पर सभी GL स्थिति को दूर फेंक देता है, और जब इसे फिर से शुरू किया जाता है, तो onSurfaceCreated () को कॉल करता है। इसका मतलब है कि, जब एक डायलॉग बॉक्स मेरे खेल में पॉप अप हुआ, तो इसे बंद करने में देरी हुई क्योंकि सभी बनावटों को फिर से लोड करना पड़ा।

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

संपादित करें: मुझे अभी पता चला है कि आप पहले ही इसी तरह के हैक के लिंक को पोस्ट कर चुके हैं। मुझे नहीं लगता कि मधुकोश से पहले कोई अंतर्निहित समाधान है। रेप्लिका द्वीप एक लोकप्रिय गेम है जो कई उपकरणों पर काम कर रहा है और आपको क्रिस के कार्यान्वयन और टिप्पणियों में मदद मिल सकती है।


1
इसे दरकिनार करने के लिए विभिन्न तरीकों की कोशिश करने के बाद, मैंने निर्णय लिया है कि संदर्भ को फिर से बनाने के लिए ऐप को फिर से बनाना है। यह इतना बेकार दृष्टिकोण है, लेकिन ऐसा नहीं लगता है कि कोई अच्छा समाधान कोड है। Googlep/android/issues/detail
id=

9

मैं इस पर एक और उत्तर जोड़ना चाहूंगा जो कि क्रिस प्रुइट (रेप्लिका द्वीप, विंड-अप नाइट, इत्यादि) द्वारा एक या दो साल पहले मुझे दिया गया था। यह 2013 में विशेष रूप से उपयोगी है क्योंकि setPreserveEglContextOnPause (सच) 4.3 पर काम नहीं करता है। (मैं इसके बारे में गलत हो सकता है, लेकिन यह है कि यह मुझे अभी कैसा दिखता है क्योंकि मैं 2011 में गेम कोड को अंतिम रूप से अपडेट किया गया था)।

मूल रूप से चाल अपनी गतिविधि के onPause () से पदानुक्रम से अपने GLSurfaceView को अलग करने के लिए है। चूंकि यह ऑनपॉइंट () रन पर व्यू पदानुक्रम में नहीं है, इसलिए संदर्भ कभी नष्ट नहीं होता है।

तो आपकी गतिविधि की शुरुआत () इस तरह दिखनी चाहिए:

@Override
public void onPause() {
    view.setVisibility(View.GONE);
    super.onPause();
    ...
}

और आप अपने GLSurfaceView को पदानुक्रम पर पुनर्स्थापित नहीं करते हैं onResume () से लेकिन onWindowFocusChanged () से:

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus && view.getVisibility() == View.GONE) {
         view.setVisibility(View.VISIBLE);
    }
    ...
}

ध्यान दें कि आप GLSurfaceView के ऑनपॉज़ () और onResume () को कभी भी कॉल नहीं करते हैं और यह आधिकारिक एसडीके GLSurfaceView है, कोई हैक-अप वैकल्पिक संस्करण की आवश्यकता नहीं है।


वास्तव में यह दृष्टिकोण काम नहीं करता है। क्रिस प्रुइट ने एकता के साथ संयोजन में इसका उपयोग किया, क्या यह संभव है कि यह वर्कअराउंड मूल परियोजनाओं में काम नहीं कर रहा है? लेकिन केवल GLView.onPause () काम नहीं लगता है! क्या ऐसे अन्य लोग हैं जो इसकी पुष्टि कर सकते हैं?
sjkm

यह मेरे लिए एंड्रॉइड 2.2 ओपनग्ल ईएस 2 पर लक्षित है। यकीन नहीं होता कि यह अन्य उपकरणों पर कैसा प्रदर्शन करता है। मेरे पास LG G2 D802 फोन है। क्या किसी को पता है कि यह एक सामान्य समाधान है?
Pixel

7

<rant> मैंने इस समस्या पर एक बड़ी मात्रा में समय बिताया, मैंने कई अलग-अलग समाधानों की कोशिश की और आज तक कोई भी काम नहीं किया, मुझे लगता है कि यह सबसे भयानक डिजाइन निर्णय में से एक है जिसे मैंने भी देखा था, लेकिन एंड्रॉइड टीम से नहीं आ रहा हूं। वास्तव में आश्चर्य हुआ। </ शेखर>

तो, समाधान यह है कि ईगलकोटेक्स्ट सदस्य को ऊपर की ओर ले जाएं और इसे स्थिर (वैश्विक) बनाएं ताकि यह नष्ट न हो, तो आपको बस यह जांचना होगा कि इसे फिर से बनाने से पहले यह शून्य है या नहीं।

अब तक यह समाधान हमारे लिए काम करता है, और अगर यह 2005 के उपकरणों पर टूटता है, तो हमें कोई परवाह नहीं है।


4

छत्ते एपीआई का उपयोग करें। आपके ओजीएल संदर्भ को संरक्षित करने का एक विकल्प है। अन्यथा, आपको अपना संदर्भ पुनः लोड करने की आवश्यकता है। यह मुश्किल नहीं है और न ही दर्दनाक है।

आपको यह समझने की आवश्यकता है कि दो मामले हैं (Android 2.1):

  • स्क्रीन पॉज: आपका एप्लिकेशन हमेशा सामने वाला एक => हैक उपलब्ध है
  • आवेदन विराम: एक और सामने अनुप्रयोग है => कोई समाधान नहीं

नोट: पुराने Android gpus बहु संदर्भ का समर्थन नहीं करते हैं। जब आप किसी अन्य एप्लिकेशन पर स्विच करते हैं तो ओपेंग्ल संदर्भ खो जाता है => कोई समाधान उपलब्ध नहीं होता है (आप स्क्रीन के ठहराव पर अपने संदर्भ को संरक्षित करने के लिए हैक कर सकते हैं)।

नोट 2: हनीकोम्ब फ़ंक्शन सेटपेसरसेग्लसकोटेक्स्टऑनपाउज़ है


1
मैं एंड्रॉइड NDK के लिए एक C ++ गेम पोर्ट कर रहा हूं जो कि संदर्भ को आसानी से लोड करने के लिए डिज़ाइन नहीं किया गया है, इसलिए कम से कम मेरे लिए यह कुछ मुश्किल है। एक तरफ कठिनाइयों को पुन: लोड करने में देरी एक विलंब का परिचय देगी जो हमारे अन्य उपकरणों (आईफोन, पीएसपी, डीएस, आदि ..) पर मौजूद नहीं है। सुहागरात सुनने के लिए खुशी यह ठीक करती है लेकिन दुर्भाग्य से हमें 2.1+ का समर्थन करने की आवश्यकता है
निक गोच

1
यह उसके सवाल का जवाब नहीं देता है।
notlesh

1
यदि आप नहीं समझते हैं, तो आप ऐसा नहीं कर सकते।
एलिस

2

यहाँ कुछ उत्तर Android पर OpenGL ES के शुरुआती उपयोग के लिए उचित हैं। पहले GLES उपकरणों ने केवल एक ही संदर्भ का समर्थन किया, इसलिए GLSurfaceView को आक्रामक रूप से राज्य छोड़ने के लिए डिज़ाइन किया गया था। GLSurfaceView को करना अन्यथा आसान नहीं है।

Android के अधिक हाल के संस्करणों के लिए (शायद GLES 2.x का उपयोग करके कुछ भी), सबसे अच्छा उत्तर यह है कि एक सादा भूतल का उपयोग करें और अपना खुद का ईजीएल और थ्रेड प्रबंधन करें। आप GLES के कई उदाहरण में एक सादे SurfaceView के साथ प्रयोग किया पा सकते हैं ग्राफिक्स , बनाने और EGL संदर्भों को नष्ट करने के लिए सरल वर्गों में से एक पुस्तकालय भी शामिल है।

जब कोई ऐप बैकग्राउंड में जाता है, तो स्टेट को अनलोड करना अच्छा होता है, लेकिन क्रिस प्रुइट से उदाहरण के लिए - जहां ऐप अभी भी अग्रभूमि में था, लेकिन GLSurfaceView को होस्ट करने वाली एक्टिविटी को इससे दूर कर दिया गया था - फाड़ने में कोई मूल्य नहीं है संदर्भ नीचे।

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