3D그래픽2011. 10. 22. 10:07
onDrawFrame은 Android에서 OpenGL ES를 이용할 때 사용해야하는 GLSurfaceView.Renderer interface의 한 method이다.
매 프레임이 그려질 때 호출 되는 method 이므로, 이 method를 어떻게 구성하느냐에 따라 성능에 영향을 준다.

OpenGL ES 2.0를 이용하면서 한동안 고민했던 것들 중 하나가, uniform이나 attribute의 reference index를 관리하는 방법이었다. 보통 일반적인 예제에서는 onSurfaceCreated에서 glGetUniformLocation API를 이용해서 미리 저장을 해 두고 활용하게된다.

그런데, shader program이 runtime에 변경되는 경우 어떻게 해야 할지가 고민이었다. 이러한 경우에 여러개의 program들을 미리 생성해서 reference index를 미리 저장해 둔다는게 적절한지 의문이 들었기 때문이다.
그렇다고, 매 프레임을 그리면서 매번 glGetUniformLocation을 이용해 ref. index를 획득한다면 성능에 문제가 있지 않을까 라는 고민도 있었다.

그런데, 인터넷에서 몇몇 예제들을 확인 해 보니, runtime에 glGetUniformLocation을 이용하는 것이었다. 그래서 이렇게 해도괜찮은가보다 라고 생각하고 코드를 수정했고 정상적으로 잘 동작했다.

한동안 잊고 있다가, 어제 LogCat에서 log를 확인하고 있는데, 아무런 interaction이 없는데 계속 garbage collection이 일어나는게 아닌가! 이클립스에서 Allocation Tracker를 실행 해 봐야겠다고 맘먹고 분석을 시작! 의외의 결과를 확인하게 되었다.

glGetUniformLocation을 사용하는 부분에서 계속 memory allocation이 발생하고 있었다. 바로 glGetUniformLocation에서 문자열을 동적으로 생성(+ operator 사용)하는 과정에서 String 생성관련 memory allocation 이었다.

어디선가 들었던 "StringBuffer를 사용하세요"라는 얘기가 떠올라 StringBuffer를 사용하도록 코드를 변경 해 보았으나, 줄어들긴 했지만 계속 memory allocation은 발생했다.

결국, index에 따라 동적으로 생성되던 uniform string을 final static으로 변경. memory allocation이 사라졌다!

매 프레임마다 메모리가 할당되는 다른 한 부분이 있는데, 그건 바로 android.opengl.Matrix.invertM method.
호출 할 때마다 80bytes 씩 할당이 된다. inverse matrix 계산은 좀 복잡해서 그냥 android에서 제공하는 method를 사용하고 있는데, 이 마져도 직접 구현을 해야 할까보다.
Posted by 세월의돌