2

我正在开发一个简单的 iOS 游戏,但我遇到了 UINavigationController 和 EAGL-View 的问题。情况如下:我使用一个 EAGL-View 与多个控制器配合使用。每当我推送 MainViewController(它执行所有自定义 openGL 绘图)时,我最终都会使用更多内存(每次推送大约 5MB!)。

问题似乎出在[eaglView_ setFramebuffer]- 或者至少几乎所有分配似乎都在那里(我已经通过 Instruments 检查了实时字节 - 在这个函数中分配了大约 70% 的内存)。

EAGLView::setFramebuffer:

- (void)setFramebuffer {
    if (context) {
        [EAGLContext setCurrentContext:context];

        if (!defaultFramebuffer)
             [self createFramebuffer];

        glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer);
        glBindFramebuffer(GL_FRAMEBUFFER, msaaFramebuffer);         
        glViewport(0, 0, framebufferWidth, framebufferHeight);
    }
}

和 EAGLView::createFramebuffer:

- (void)createFramebuffer
{
    if (context && !defaultFramebuffer) {
        [EAGLContext setCurrentContext:context];

        // Create default framebuffer object.
        glGenFramebuffers(1, &defaultFramebuffer);
        glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer);

        // Create color render buffer and allocate backing store.
        glGenRenderbuffers(1, &colorRenderbuffer);
        glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
        [context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)self.layer];
        glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &framebufferWidth);
        glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &framebufferHeight);

        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer);

        //MSAA stuff
        glGenFramebuffers(1, &msaaFramebuffer);
        glGenRenderbuffers(1, &msaaRenderBuffer);
        glBindFramebuffer(GL_FRAMEBUFFER, msaaFramebuffer);
        glBindRenderbuffer(GL_RENDERBUFFER, msaaRenderBuffer);

        glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_RGBA8_OES, framebufferWidth, framebufferHeight);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, msaaRenderBuffer);

        glGenRenderbuffers(1, &msaaDepthBuffer);      
        glBindRenderbuffer(GL_RENDERBUFFER, msaaDepthBuffer);
        glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, framebufferWidth, framebufferHeight);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, msaaDepthBuffer);

        if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
            NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));

    }
}

如您所见 - 没有什么特别的。我像这样切换我的 ViewController:(在 AppDelegate 中)

- (void) swichToViewController: (UIViewController*) newViewController overlapCurrentView: (bool) overlap {
  // get the viewController on top of the stack - popViewController doesn't do anything if it's the rootViewController.
  if(!overlap) {
    // clear everything that was on the eaglView before 
    [eaglView_ clearFramebuffer];
    [eaglView_ applyMSAA];
    [eaglView_ presentFramebuffer];         
  }

  UIViewController* oldViewController = [navController_ topViewController];
  // see if the view to be switched to is already the top controller:
  if(oldViewController == newViewController)
    return;
  // if the view is already on the stack, just remove all views on top of it:
  if([[navController_ viewControllers] containsObject:newViewController]) {
    [oldViewController setView:nil];
    [newViewController setView:eaglView_];
    [navController_ popToViewController:newViewController animated:!overlap];
    return;
  }
  // else push the new controller
  [navController_ popViewControllerAnimated:NO];
  [oldViewController setView:nil];
  [newViewController setView:eaglView_];
  [navController_ pushViewController:newViewController animated:!overlap];
}

最后,我像这样渲染我的精灵:(在我的 MainViewController.mm 中):

- (void)drawFrame
{
  // When I delete this line, I just get a white screen, even if I have called setFramebuffer earlier(?!)
  [(EAGLView *)self.view setFramebuffer];

  glClearColor(1, 1, 1, 1);
  glClear(GL_COLOR_BUFFER_BIT); 

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();


  GLfloat screenWidth = [UIScreen mainScreen].bounds.size.width;
  GLfloat screenHeight = [UIScreen mainScreen].bounds.size.height;

  glOrthof(0, screenWidth, 0, screenHeight, -1.0, 1.0);
  glViewport(0, 0, screenWidth, screenHeight);

  [gameManager_ playGame];


  //MSAA stuff
  [(EAGLView *)self.view applyMSAA];

  [(EAGLView *)self.view presentFramebuffer];
  [(EAGLView *)self.view clearFramebuffer];
}

可能值得一提的是,我不会在每次推送视图时分配视图,我会一直引用它们直到游戏退出。

[gameManager_ playGame]将精灵绘制到屏幕上 - 但我在另一个项目中使用了这种方法,没有任何内存问题。

任何帮助将不胜感激,因为我已经坚持了 2 天:/

编辑:我已经能够将问题缩小到调用gldLoadFramebuffer. 每当我尝试使用 openGL 函数在屏幕上绘制某些东西时,都会调用它。当上下文发生变化时,它似乎会消耗更多的内存......但我该如何避免呢?

4

1 回答 1

1

我想我找到了问题所在。对于任何感兴趣的人:切换视图时没有正确删除 MSAA 缓冲区。这导致在几次推送后性能显着下降,并且也是内存使用量增加的原因。

于 2012-05-25T10:23:48.000 回答