2

私は単純な iOS ゲームに取り組んでおり、UINavigationController と EAGL-View に問題があります。状況は次のとおりです。1 つの 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 に答える