3

基本上,在我的 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 次,我将出现黑屏崩溃,并且会中断,并显示以下屏幕:

屏幕抓取

我已经确保一切都在适当的地方在一个线程中完成。我试图确保删除所有对象和缓冲区。

所以我想知道我到底做错了什么导致它突然崩溃......分析器中似乎没有任何指示。我似乎没有任何内存泄漏或任何会导致内存耗尽的实质性内容。

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

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

4

1 回答 1

1

我需要做的是删除 GLKView 可绘制对象。

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

GLKView *view = (GLKView*) self.view;
[view deleteDrawable];
于 2013-09-11T10:55:26.030 回答