基本上,在我的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我拥有一些我使用的对象的实例。这些应该始终有效(我已经检查过)。
答案 0 :(得分:1)
我需要做的是删除GLKView drawables。
在ViewDidDisappear方法中(可能不是正确的位置,但它有效)添加以下内容:
GLKView *view = (GLKView*) self.view;
[view deleteDrawable];