2013-10-06 7 views
6

जैसे ही ऐप पृष्ठभूमि में जाता है, इसे ओपनजीएल कार्यों को कॉल करना बंद करना होगा। लेकिन किसी भी तरह ओपनजीएल को रोकने के सभी प्रयास विफल हो जाते हैं और जब उपयोगकर्ता होम बटन दबाता है तो मेरा ऐप अक्सर (लेकिन हमेशा नहीं) दुर्घटनाग्रस्त हो जाता है। 0x1 libGPUSupportMercury.dylib gpus_ReturnNotPermittedKillClientऐप पृष्ठभूमि के दौरान समवर्ती ओपनजीएल ड्राइंग को कैसे रोकें?

पर अग्रभूमि में नहीं KERN_INVALID_ADDRESS मेरी समझ करने के लिए यदि आप ऐप्लिकेशन के बाद ओपन कार्यों फोन है अब ऐप्स का होगा:

यह साथ

अपवाद का प्रकार दुर्घटनाओं: EXC_BAD_ACCESS कोड दुर्घटना क्योंकि जीपीयू ऐप के लिए उपलब्ध नहीं है।

राय यह है कि ओपन के साथ renders एक प्रेषण कतार

self.drawingQueue = dispatch_queue_create("openglRenderQueue", DISPATCH_QUEUE_SERIAL); 

यह UIScrollView के साथ समानांतर में प्रस्तुत करने के लिए है है। इसलिए UCcrollView के लिए कतार प्रतीक्षा करने के लिए एक GCD semaphore है।

CADisplayLink *dl = [[UIScreen mainScreen] displayLinkWithTarget:self selector:@selector(update)]; 
[dl addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; 
self.displayLink = displayLink; 

अद्यतन विधि ड्राइंग निष्पादित करता गणना async धारावाहिक पर कतार प्रस्तुत करना और सेमाफोर UIScrollView के लिए प्रतीक्षा करने का उपयोग करता है:

self.renderSemaphore = dispatch_semaphore_create(1); 

मैं runloop अद्यतन करने के लिए एक CADisplayLink पैदा करते हैं। यह अंत में मुख्य धागे पर सिंक करता है।

- (void)update { 
    dispatch_async(drawingQueue, ^{ 
    if (dispatch_semaphore_wait(renderSemaphore, DISPATCH_TIME_NOW) != 0) { 
     return; 
    } 

    @autoreleasepool { 
     [EAGLContext setCurrentContext:context]; 

     glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer); 
     glViewport(0, 0, width, height); 
     glMatrixMode(GL_MODELVIEW); 
     glClear(GL_COLOR_BUFFER_BIT); 
     glLoadIdentity(); 

     // Quickly grab the target game state for rendering 
     GameState state = targetState; 

     [sprite drawState:state]; 

     dispatch_sync(dispatch_get_main_queue(), ^{ 
      if ([self canRender]) { 

       BOOL isAnimating = [self isAnimating]; 
       if (isAnimating && displayLink) { 
        [EAGLContext setCurrentContext:context]; 

        glBindRenderbufferOES(GL_RENDERBUFFER_OES, renderbuffer); 

        if (displayLink != nil) { 
         [context presentRenderbuffer:GL_RENDERBUFFER_OES]; 
        } 
       } 

      } 
     }); 
    } 

    dispatch_semaphore_signal(renderSemaphore); 
    }); 
} 

अद्यतन विधि मुख्य थ्रेड पर जांचता है यदि यह प्रस्तुत कर सकता है। चेक इस तरह दिखता है:

- (BOOL)canRender { 
    UIApplicationState appState = [[UIApplication sharedApplication] applicationState]; 
    return (appState != UIApplicationStateBackground && appState != UIApplicationStateInactive); 
} 

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

तो मुझे लगता है क्या याद आ रही है कि मैं भी -canRender जांच करना चाहिए इससे पहले कि मैं इस async ब्लॉक में किसी भी ओपन समारोह कहते हैं:

__block BOOL canRender = YES; 
dispatch_sync(dispatch_get_main_queue(), ^{ 
    canRender = [self canRender]; 
}); 
if (!canRender) { 
    return; 
} 

ठीक है, लेकिन अब सोच भी मैं रन प्रस्तुत करना की शुरुआत में इस चेक बनाने पाश। -canRender हाँ कहते हैं। फिर मैं [sprite drawState:state]; पर कॉल करता हूं। यह विधि बहुत सारे ग्लो फ़ंक्शन को कॉल करती है। मुझे लगता है कि यह मूल समस्या है। क्योंकि अगर मेरा एसिंक ब्लॉक मुख्य थ्रेड पर जांच करता है, यदि ऐप अभी भी अग्रभूमि में है, तो जब मैं जटिल ड्राइंग करने के लिए एसिंक जारी रखता हूं तो 3 नैनोसेकंड बाद में ऐप पृष्ठभूमि स्थिति और सीआरएएसएच में हो सकता है।

तो यहां तक ​​कि अगर मैं प्रत्येक एकल ग्लो फंक्शन कॉल से पहले मुख्य थ्रेड पर चेक-कैनरेंडर चेक करता हूं तो यह हो सकता है कि एक विभाजित नैनोसेकंद बाद में ऐप पृष्ठभूमि और क्रैश में हो।

क्या ओपनजीएल को अंदर से बंद करने का कोई तरीका है, इसलिए यह अपने कार्यों में कॉल को अनदेखा करता है। मैंने एक परिष्करण विधि के बारे में सुना था। मुझे इसे बंद करना होगा। पर कैसे?

उत्तर

1

आप अपने आवेदन को पृष्ठभूमि में जाने की अनुमति देने से पहले glFinish (...) पर विचार कर सकते हैं। यह तब तक अवरुद्ध होगा जब तक कि पाइपलाइन में हर कमांड समाप्त न हो जाए। हालांकि इसमें कुछ समय लग सकता है, संभावित रूप से कई एमएस।

उसी टोकन द्वारा, यदि आप वास्तव में करना चाहते हैं तो ओपनजीएल एपीआई कॉल को अनदेखा कर देता है जब तक कि कुछ शर्त पूरी नहीं होती है (इस मामले में, जब तक कि आपका एप्लिकेशन पृष्ठभूमि में नहीं है) ऐसा करने का सबसे आसान तरीका है किसी दिए गए थ्रेड के लिए सक्रिय संदर्भ को पूर्ण पर सेट करें। यह प्रत्येक कॉल को नो-ऑप बना देगा, इतना है कि जब आप इस स्थिति में कोई जीएल एपीआई कॉल करते हैं तो कोई त्रुटि उत्पन्न नहीं होगी। जब आपका एप्लिकेशन अग्रभूमि में वापस लाया जाता है तो आप सक्रिय संदर्भ को पुनर्स्थापित कर सकते हैं।

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

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