जैसे ही ऐप पृष्ठभूमि में जाता है, इसे ओपनजीएल कार्यों को कॉल करना बंद करना होगा। लेकिन किसी भी तरह ओपनजीएल को रोकने के सभी प्रयास विफल हो जाते हैं और जब उपयोगकर्ता होम बटन दबाता है तो मेरा ऐप अक्सर (लेकिन हमेशा नहीं) दुर्घटनाग्रस्त हो जाता है। 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 नैनोसेकंड बाद में ऐप पृष्ठभूमि स्थिति और सीआरएएसएच में हो सकता है।तो यहां तक कि अगर मैं प्रत्येक एकल ग्लो फंक्शन कॉल से पहले मुख्य थ्रेड पर चेक-कैनरेंडर चेक करता हूं तो यह हो सकता है कि एक विभाजित नैनोसेकंद बाद में ऐप पृष्ठभूमि और क्रैश में हो।
क्या ओपनजीएल को अंदर से बंद करने का कोई तरीका है, इसलिए यह अपने कार्यों में कॉल को अनदेखा करता है। मैंने एक परिष्करण विधि के बारे में सुना था। मुझे इसे बंद करना होगा। पर कैसे?