iOS OpenGL ES Crash多次加载同一个对象

时间:2013-09-10 15:31:35

标签: ios opengl-es crash

基本上,在我的iOS应用程序中,我有一个模态屏幕,我在其中显示一些OpenGL ES图形。在应用程序崩溃之前,我能够进入和退出此模态屏幕6次。我假设这是一个内存问题,但我被困在什么和/或在哪里。

对此事的任何帮助都非常感激。

在我的OGLViewController中:

#define OPENGL_ERROR_CHECK {GLuint error = glGetError(); ((error == GL_NO_ERROR) ? :  NSLog(@"GL Error: %d", (error)));}

@interface OGLItemViewController : GLKViewController

@property (nonatomic) GLuint program;

// item ogl arrays + buffers
@property (nonatomic) NSInteger numOGLBuffers;
@property (nonatomic) GLuint* vertexArrays;
@property (nonatomic) GLuint* vertexBuffers;

// index buffer for ogl item vertices
@property (nonatomic) GLuint* indexBuffers;

@property (strong, nonatomic) EAGLContext *context;
@property (strong, nonatomic) GLKBaseEffect *effect;

@end

@implementation

- (void)viewDidLoad
{
  [super viewDidLoad];

  self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];

  OPENGL_ERROR_CHECK
  glFinish(); // put this in here to make sure all previous calls have been finished
  OPENGL_ERROR_CHECK

  if (!self.context)
  {
    NSLog(@"Failed to create ES context");
  }

  GLKView *view = (GLKView *) self.view;
  view.context = self.context;
  view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
  view.opaque = NO;

  self.numOGLBuffers = 0;

  self.vertexArrays = nil;
  self.vertexBuffers = nil;
  self.indexBuffers = nil;
}

- (void)setupGL
{
  OPENGL_ERROR_CHECK
  [EAGLContext setCurrentContext:self.context];
  OPENGL_ERROR_CHECK

  [self loadShaders];    
  OPENGL_ERROR_CHECK

  self.effect = [[GLKBaseEffect alloc] init];
  OPENGL_ERROR_CHECK
  self.effect.light0.enabled = GL_TRUE;
  OPENGL_ERROR_CHECK

  self.effect.colorMaterialEnabled = GL_TRUE;
  OPENGL_ERROR_CHECK

  self.effect.lightModelTwoSided = GL_FALSE;
  OPENGL_ERROR_CHECK

  self.effect.light0.diffuseColor = GLKVector4Make(0.69f, 0.69f, 0.69f, 0.5f);
  OPENGL_ERROR_CHECK

  glEnable(GL_DEPTH_TEST);
  OPENGL_ERROR_CHECK

  Item *item = [GlobalStore sharedInstance].item

  NSMutableArray *shells = item.geometry;

  if (shells.count > 0)
  {    
    _vertexArrays = malloc(shells.count * sizeof(GLuint));
    _vertexBuffers = malloc(shells.count * sizeof(GLuint));
    _indexBuffers = malloc(shells.count * sizeof(GLuint));
    self.numOGLBuffers = shells.count;

    for (int i = 0; i < shells.count; i++)
    {
        Geometry *geom = [shells objectAtIndex:i];
        if (geom.vertexCount > 0)
        {
            GLuint vao = 0;
            OPENGL_ERROR_CHECK
            glGenVertexArraysOES(1, &vao);

            OPENGL_ERROR_CHECK
            glBindVertexArrayOES(vao);
            OPENGL_ERROR_CHECK

            _vertexArrays[i] = vao;

            if (!geom.vertices)
            {
                [self displayError:-998];  // generic error codes that i've just canned in to see if any problems with these pointers
            }
            if (!geom.indices)
            {
                [self displayError:-997];
            }

            // create vertice buffer
            GLuint vbo = 0;
            glGenBuffers(1, &vbo);
            OPENGL_ERROR_CHECK
            glBindBuffer(GL_ARRAY_BUFFER, vbo);
            OPENGL_ERROR_CHECK
            glBufferData(GL_ARRAY_BUFFER, geom.vertexCount * sizeof(OGLVertices), geom.vertices, GL_STATIC_DRAW);
            OPENGL_ERROR_CHECK

            _vertexBuffers[i] = vbo;

            // create index by buffer
            GLuint ibo = 0;
            glGenBuffers(1, &ibo);
            OPENGL_ERROR_CHECK
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
            OPENGL_ERROR_CHECK
            glBufferData(GL_ELEMENT_ARRAY_BUFFER, geom.indexCount * sizeof(GLuint), geom.indices, GL_STATIC_DRAW);
            OPENGL_ERROR_CHECK

            _indexBuffers[i] = ibo;

            // enable position, normal and colour attributes
            glEnableVertexAttribArray(GLKVertexAttribPosition);
            OPENGL_ERROR_CHECK
            glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(OGLVertices), (const GLvoid *) offsetof(OGLVertices, Position));
            OPENGL_ERROR_CHECK
            glEnableVertexAttribArray(GLKVertexAttribNormal);
            OPENGL_ERROR_CHECK
            glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, sizeof(OGLVertices), (const GLvoid *) offsetof(OGLVertices, Normal));
            OPENGL_ERROR_CHECK
            glEnableVertexAttribArray(GLKVertexAttribColor);
            OPENGL_ERROR_CHECK
            glVertexAttribPointer(GLKVertexAttribColor, 4, GL_FLOAT, GL_FALSE, sizeof(OGLVertices), (const GLvoid *) offsetof(OGLVertices, Colour));
            OPENGL_ERROR_CHECK
        }
      }

      glBindVertexArrayOES(0);
      OPENGL_ERROR_CHECK
  }
}

- (void)tearDownGL
{
  [EAGLContext setCurrentContext:self.context];
  self.effect = nil;

  [self deleteOGLData];
}

- (void)dealloc
{
  [self tearDownGL];

  if ([EAGLContext currentContext] == self.context)
  {
    [EAGLContext setCurrentContext:nil];
  }
}

- (void) viewDidDisappear:(BOOL)animated
{
  [self tearDownGL];
}

- (void)deleteOGLData
{
    // delete ogl buffers and arrays
    if (self.numOGLBuffers > 0)
  {
    if (_vertexBuffers)
    {
        OPENGL_ERROR_CHECK
        glDeleteBuffers(self.numOGLBuffers, _vertexBuffers);

        OPENGL_ERROR_CHECK
        free(_vertexBuffers);
        _vertexBuffers = nil;
    }
    if (_vertexArrays)
    {
        glDeleteVertexArraysOES(self.numOGLBuffers, _vertexArrays);
        OPENGL_ERROR_CHECK
        free(_vertexArrays);
        _vertexArrays = nil;
    }
    if (_indexBuffers)
    {
        glDeleteBuffers(self.numOGLBuffers, _indexBuffers);
        OPENGL_ERROR_CHECK
        free(_indexBuffers);
        _indexBuffers = nil;
    }
  }


  self.numOGLBuffers = 0;

  glDeleteProgram(self.program);
  OPENGL_ERROR_CHECK

  self.program = 0;

  glFinish(); // again, just put this in here to check everything has finished
  OPENGL_ERROR_CHECK
}

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{ 
    OPENGL_ERROR_CHECK
    glClearColor(1.0, 1.0, 1.0, 0.0);
    OPENGL_ERROR_CHECK
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    OPENGL_ERROR_CHECK

    // Render the object with GLKit
    [self.effect prepareToDraw];
    OPENGL_ERROR_CHECK


    NSMutableArray *shells = [GlobalStore sharedInstance].item.geometry;
    if (shells && _vertexArrays && _vertexBuffers)
    {          
        for (int i = 0; i < shells.count; i++)
        {
            Geometry *geom = [shells objectAtIndex:i];

            if (geom.vertexCount > 0)
            {
                GLuint vao = self.vertexArrays[i];
                glBindVertexArrayOES(vao);
                OPENGL_ERROR_CHECK

                if(geom.indexCount == 0)
                    [self displayError:-996];

                glDrawElements(GL_TRIANGLES, geom.indexCount, GL_UNSIGNED_INT, 0);
                OPENGL_ERROR_CHECK
                self.initialised = YES;
            }
        }        
    }
}

- (BOOL)loadShaders
{
  GLuint vertShader, fragShader;
  NSString *vertShaderPathname, *fragShaderPathname;

  // Create shader program.
  self.program = glCreateProgram();
  OPENGL_ERROR_CHECK

  // Create and compile vertex shader.
  vertShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"vsh"];
  if (![self compileShader:&vertShader type:GL_VERTEX_SHADER file:vertShaderPathname])
  {
    NSLog(@"Failed to compile vertex shader");
    return NO;
  }

  // Create and compile fragment shader.
  fragShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"fsh"];
  if (![self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:fragShaderPathname])
  {
    NSLog(@"Failed to compile fragment shader");
    return NO;
  }

  // Attach vertex shader to program.
  glAttachShader(_program, vertShader);
  OPENGL_ERROR_CHECK

  // Attach fragment shader to program.
  glAttachShader(_program, fragShader);
  OPENGL_ERROR_CHECK

  // Bind attribute locations.
  // This needs to be done prior to linking.
  glBindAttribLocation(_program, GLKVertexAttribPosition, "position");
  OPENGL_ERROR_CHECK

  glBindAttribLocation(_program, GLKVertexAttribNormal, "normal");
  OPENGL_ERROR_CHECK

  // Link program.
  if (![self linkProgram:_program])
  {
    NSLog(@"Failed to link program: %d", _program);

    if (vertShader)
    {
        glDeleteShader(vertShader);
        OPENGL_ERROR_CHECK
        vertShader = 0;
    }
    if (fragShader)
    {
        glDeleteShader(fragShader);
        OPENGL_ERROR_CHECK
        fragShader = 0;
    }
    if (_program)
    {
        glDeleteProgram(_program);
        OPENGL_ERROR_CHECK
        _program = 0;
    }

    return NO;
  }

  // Get uniform locations.
  uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX] = glGetUniformLocation(_program, "modelViewProjectionMatrix");
  uniforms[UNIFORM_NORMAL_MATRIX] = glGetUniformLocation(_program, "normalMatrix");

  // Release vertex and fragment shaders.
  if (vertShader)
  {
    glDetachShader(_program, vertShader);
    OPENGL_ERROR_CHECK
    glDeleteShader(vertShader);
    OPENGL_ERROR_CHECK
  }
  if (fragShader)
  {
    glDetachShader(_program, fragShader);
    OPENGL_ERROR_CHECK
    glDeleteShader(fragShader);
    OPENGL_ERROR_CHECK
  }

  return YES;
}

- (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file
{
  GLint status;
  const GLchar *source;

  source = (GLchar *)[[NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil] UTF8String];
  if (!source)
  {
    NSLog(@"Failed to load vertex shader");
    return NO;
  }

  *shader = glCreateShader(type);
  OPENGL_ERROR_CHECK
  glShaderSource(*shader, 1, &source, NULL);
  OPENGL_ERROR_CHECK
  glCompileShader(*shader);
  OPENGL_ERROR_CHECK

  glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
  OPENGL_ERROR_CHECK
  if (status == 0)
  {
    glDeleteShader(*shader);
    OPENGL_ERROR_CHECK
    return NO;
  }

  return YES;
}

- (BOOL)linkProgram:(GLuint)prog
{
  GLint status;
  glLinkProgram(prog);
  OPENGL_ERROR_CHECK

  glGetProgramiv(prog, GL_LINK_STATUS, &status);
  OPENGL_ERROR_CHECK
  if (status == 0)
  {
    return NO;
  }

  return YES;
}

- (BOOL)validateProgram:(GLuint)prog
{
  GLint logLength, status;

  glValidateProgram(prog);
  OPENGL_ERROR_CHECK
  glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
  OPENGL_ERROR_CHECK
  if (logLength > 0)
  {
    GLchar *log = (GLchar *)malloc(logLength);
    glGetProgramInfoLog(prog, logLength, &logLength, log);
    OPENGL_ERROR_CHECK
    NSLog(@"Program validate log:\n%s", log);
    free(log);
  }

  glGetProgramiv(prog, GL_VALIDATE_STATUS, &status);
  OPENGL_ERROR_CHECK
  if (status == 0)
  {
    return NO;
  }

  return YES;
}


-(void)displayError: (GLuint) err
{
  NSString *msg = [[NSString alloc] initWithFormat:@"OpenGL Error: %d", err];
  UIAlertView *alert = [[UIAlertView alloc] initWithTitle: @"Error"
                                                  message: msg
                                                 delegate:self
                                        cancelButtonTitle:@"OK"
                                        otherButtonTitles:nil];

  [alert show];
}


@end

现在 - 我不知道这是否是正确的方法,但在viewdiddisappear方法中,我确保删除所有的ogl数据。我想确保当我退出视图时,将从内存中删除ogl数据。

所以,如果我进入模态视图,退出并再重复5次,我将会出现黑屏崩溃,并将在以下屏幕中断开:

screen grab

我确保所有内容都在适当的单个线程中完成。我试图确保删除所有对象和缓冲区。

所以我想知道我到底做错了什么导致它突然崩溃.....在探查器中没有任何东西似乎表明任何东西。我似乎没有任何内存泄漏或任何太大而导致内存耗尽的内容。

(我知道我正在渲染每一帧,当我不需要时 - 我将在稍后解决这个问题。)

globalstore我拥有一些我使用的对象的实例。这些应该始终有效(我已经检查过)。

1 个答案:

答案 0 :(得分:1)

我需要做的是删除GLKView drawables。

在ViewDidDisappear方法中(可能不是正确的位置,但它有效)添加以下内容:

GLKView *view = (GLKView*) self.view;
[view deleteDrawable];