2012-01-03 19 views
11

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

जिस ऐप पर मैं काम कर रहा हूं वह कैमरा फ्रेम प्राप्त करने के लिए डिज़ाइन किया गया है और उन्हें ओपनजीएल ईएस के माध्यम से स्क्रीन पर प्रदर्शित किया गया है (ग्राफिक लोग इस पर ले लेंगे और वास्तविक ओपनजीएल ड्राइंग जोड़ देंगे जिसके बारे में मुझे बहुत कम पता है)। एप्लिकेशन एक्सकोड 4 विकसित किया गया है, और लक्ष्य आईफोन 4 आईओएस चल रहा है। इस पल के लिए, मैंने एआरसी और जीएलकिट कार्यक्षमता का उपयोग किया और सभी छवियों को बनावट के रूप में लोड करने में स्मृति रिसाव को छोड़कर ठीक काम कर रहे हैं। ऐप को जल्द ही "स्मृति चेतावनी" प्राप्त होती है।

विशेष रूप से, मैं कैसे द्वारा

@property(retain) GLKTextureInfo *texture; 

-(void)setTextureCGImage:(CGImageRef)image 
{ 
    NSError *error; 

    self.texture = [GLKTextureLoader textureWithCGImage:image options:nil error:&error]; 

    if (error) 
    { 
     NSLog(@"Error loading texture from image: %@",error); 
    } 
} 

image बनावट आवंटित जारी करने के लिए पूछना चाहूँगा एक क्वार्ट्ज कैमरा फ्रेम (सेब से नमूना कोड) से बनाया गया छवि है। मुझे पता है कि कोड कोड के उस हिस्से में नहीं है क्योंकि अगर मैं असाइनमेंट अक्षम करता हूं, तो ऐप को चेतावनी नहीं मिलती है।

उत्तर

22

सुपर Hacky समाधान मेरा मानना ​​है कि है, लेकिन यह काम करने के लिए लगता है:

काम करने से पहले निम्न जोड़ें:

GLuint name = self.texture.name; 
glDeleteTextures(1, &name); 

यदि कोई अधिक सरकारी तरीका है (या अगर यह आधिकारिक तरीका है), अगर कोई मुझे बता सके तो मैं सराहना करता हूं।

+1

हम्म। अब तक कोई प्रतिक्रिया नहीं है, इसलिए यह इस समय आधिकारिक है क्योंकि यह इस समय मेरे लिए मिलता है। :-) मेरी सोच यह होगी कि 'जीएलकेटेक्चरइन्फो' इसका प्रबंधन करेगा (यानी बनावट को जारी करने के लिए इसे इंगित करने वाले हैंडल को संभालने में संभाल लें) लेकिन स्पष्ट रूप से यह मामला नहीं है। – alokoko

+5

मुझे विश्वास है कि यह करने का यह सही तरीका है। मुद्दा यह है कि जब आप जीएल में बनावट को बांधते हैं तो आपके बनावट इंफो को बनाया जाता है, जीएल के बाद मेमोरी का मालिक होता है, इसलिए आपको स्मृति –

+0

मेमोरी हटाने के लिए जीएल का उपयोग करने की आवश्यकता है, एंथॉयज स्पष्टीकरण मुझे समझ में आता है। +1। – Soup

5

कोई सीधा जवाब नहीं है, लेकिन मैंने देखा कुछ और यह वास्तव में एक टिप्पणी में फिट नहीं होगा।

यदि आप किसी मौजूदा बनावट को प्रतिस्थापित करने के लिए पृष्ठभूमि में बनावट लोड करने के लिए GLKTextureLoader का उपयोग कर रहे हैं, तो आपको मुख्य थ्रेड पर मौजूदा बनावट को हटाना होगा। पूरा होने वाले हैंडलर में एक बनावट को हटाने काम नहीं करेगा।

  1. हर आईओएस धागा अपनी ही EAGLContext आवश्यकता है, इसलिए पृष्ठभूमि कतार उसके अपने संदर्भ के साथ अपने स्वयं धागा है:

    AFAIK इस वजह से है।

  2. पूरा होल्डर आपके द्वारा पारित कतार पर चलाया जाता है, जो संभवतः मुख्य कतार नहीं है। (वरना आप पृष्ठभूमि में लोड हो रहा है कर रही हैं नहीं किया जा ...)

है, इस स्मृति रिसाव हो जाएगा।

NSDictionary *options = @{GLKTextureLoaderOriginBottomLeft:@YES}; 
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
[self.asyncTextureLoader textureWithContentsOfFile:@"my_texture_path.png" 
              options:options 
              queue:queue 
           completionHandler:^(GLKTextureInfo *texture, NSError *e){ 
            GLuint name = self.myTexture.name; 
            // 
            // This delete textures call has no effect!!! 
            // 
            glDeleteTextures(1, &name); 
            self.myTexture = texture; 
            }]; 

इस मुद्दे आप या तो चारों ओर पाने के लिए:

  1. बनावट हटाएं से पहले अपलोड होता है। आपके जीएल आर्किटेक्टेड के आधार पर संभावित रूप से स्केची।
  2. पूरा होने वाले हैंडलर में मुख्य कतार पर बनावट हटाएं।

तो, रिसाव को ठीक करने के आप ऐसा करने की जरूरत है:

// 
// Method #1, delete before upload happens. 
// Executed on the main thread so it works as expected. 
// Potentially leaves some GL content untextured if you're still drawing it 
// while the texture is being loaded in. 
// 

// Done on the main thread so it works as expected 
GLuint name = self.myTexture.name; 
glDeleteTextures(1, &name) 

NSDictionary *options = @{GLKTextureLoaderOriginBottomLeft:@YES}; 
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
[self.asyncTextureLoader textureWithContentsOfFile:@"my_texture_path.png" 
              options:options 
              queue:queue 
           completionHandler:^(GLKTextureInfo *texture, NSError *e){ 
            // no delete required, done previously. 
            self.myTexture = texture; 
            }]; 

या

// 
// Method #2, delete in completion handler but do it on the main thread. 
// 
NSDictionary *options = @{GLKTextureLoaderOriginBottomLeft:@YES}; 
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
[self.asyncTextureLoader textureWithContentsOfFile:@"my_texture_path.png" 
              options:options 
              queue:queue 
           completionHandler:^(GLKTextureInfo *texture, NSError *e){ 
            // you could potentially do non-gl related work here, still in the background 
            // ... 

            // Force the actual texture delete and re-assignment to happen on the main thread. 
            dispatch_sync(dispatch_get_main_queue(), ^{ 
             GLuint name = self.myTexture.name; 
             glDeleteTextures(1, &name); 
             self.myTexture = texture; 
            }); 
            }]; 
0

वहाँ एक रास्ता बस एक ही GLKTextureInfo को बनावट की सामग्री बदलने के है। नाम हैंडल? Glgentextures का उपयोग करते समय आप glteximage2d का उपयोग कर नए टेक्स्ट्यूशन डेटा को लोड करने के लिए लौटा बनावट हैंडल का उपयोग कर सकते हैं। लेकिन GLKTextureLoader के साथ ऐसा लगता है कि हर बार नए बनावट डेटा लोड होने पर glgentextures कहा जा रहा है ...