• 검색 결과가 없습니다.

vjVTK의 오류와 수정

switch(mCommand) {

// Both ACTOR and VOLUME are wrappers for the AddViewProp // command in the renderer... so all handled the same

case ADD_PROP:

case ADD_ACTOR:

case ADD_VOLUME:

renderer->AddViewProp(mProp);

break;

// Actor and Volume do more than Prop...

// so we have to call them individually case REMOVE_PROP:

renderer->RemoveViewProp(mProp);

break;

case REMOVE_ACTOR:

renderer->RemoveActor(mProp);

break;

case REMOVE_VOLUME:

renderer->RemoveVolume(mProp);

break;

} }

[소스 1-5 Render Command Conversion ]

3. vjVTK의 오류와 수정

vjVTK는 2005년에 개발되어 0.8까지의 버전을 내놓는 동안 VTK 5.0 과 Windo ws 시스템을 지원하게 되었다. 그러나, vjVTK의 0.8 버전을 VTK 5.2.2에 적용 하면서, vjVTK에는 compile time 오류부터, run time 오류, 논리적 오류까지 많 은 오류들이 발견되었다. 여기서는 run time 오류와 논리적 버그 수정에 대한 부 분만 다루기로 한다.

가. Runtime 오류와 해결책

VTK 5.2.2 와 함께 vjVTK로 작성한 프로그램을 실행하면, Segmentation fault

에러가 나면서 프로그램이 종료된다. 이는 vjVTK에서 vtkOpenGLRenderer와 vt kOpengLRenderWindow 클래스의 대체 클래스만을 구현하고 vtkOpenGLActor나 vtkOpenGLProperty 등을 구현하지 않아 OpenGL 용 클래스를 그대로 가져다 쓰 기 때문에 발생한 문제이다. 실제로 gdb를 이용해서 프로그램을 trace했을 때 에 러가 발생하는 부분은 다음과 같다.

1 void vtkOpenGLProperty::Render(vtkActor *anActor, 2 vtkRenderer *ren) 3 {

4 int i;

5 GLenum method;

6 float Info[4];

7 GLenum Face;

8 double color[4];

9

10 // unbind any textures for starters

11 vtkOpenGLRenderer *oRenderer=static_cast<vtkOpenGLRenderer *>(ren);

12

13 if(oRenderer->GetDepthPeelingHigherLayer()) 14 {

15 GLint uUseTexture=-1;

16 uUseTexture=oRenderer->GetUseTextureUniformVariable();

17 vtkgl::Uniform1i(uUseTexture,0);

18 }

[소스 2-1 Code that cause Segmentation Fault]

여기서 Render() 함수에 인자로 들어오는 vtkRenderer *ren의 실제 type은 vtk VJOpenGLRenderer 이다. 그런데, 11번째 라인에서 이것을 vtkOpenGLRenderer 로 강제 type casting한다. 이는 실제 이 클래스가 vtkOpenGLProperty이기 때문 에 받아오는 renderer도 vtkOpenGLRenderer라고 가정하였기 때문이다. 그러나, vjVTK에서 vtkVJOpenGLProperty를 구현하지 않고 vtkOpenGLProperty를 빌려 사용한다. 코드에서 강제 casting한 renderer가 GetDepthPeelingHigherLayer() 함수를 호출하면 그 리턴 값에 따라 조건문의 분기가 결정된다. 이 함수는 vtkO penGLRenderer의 멤버 변수인 DepthPeelingHigherLayer 값을 돌려주는 함수로 vtkOpenGLRenderer를 처음 생성할 때 0으로 초기화 된다. 그러나 실제 rendere r인 vtkVJOpenGLRenderer는 이 값을 초기화하지 않으므로 실행할 때 어떤 값이 들어가 있을지 알 수 없다. (vtkVJOpenGLRenderer에는 이 변수가 정의되어 있

지도 않기 때문에 어떤 값을 access할 지 알 수 없다.) 따라서 우연히 이 값이 0 인 경우는 조건문 안으로 들어가지 않게 되고 0이 아닌 경우는 조건문 안으로 들어가게 된다. 조건문 안으로 들어가게 되면, vtkOpenGLRenderer에서는 depth peeling을 위한 shader를 생성한다. 이 조건문 안에서는 shader의 UseTexture라 는 uniform variable을 접근한다. 그런데 vtkVJOpenGLRenderer에서는 이러한 s hader와 관련된 어떤 정의도 존재하지 않으므로, 접근할 shader가 없기 때문에 s egmentation fault 에러가 발생하게 된다.

이러한 문제를 해결하기 위한 가장 간단한 방법은 소스 코드 중 13번째 라인부 터 18번째 라인을 코멘트 처리하는 것이다. 그러나, 이럴 경우 depth peeling 기 능을 수행할 수 없게 된다. 따라서, 추가된 기능인 depth peeling을 vjVTK에서 만, 사용하지 않도록 type cast 전에 class name을 check해서 vtkVJOpenGLRen derer 일 경우, 13~18 라인을 수행하지 않도록 수정하였다.

나. vjRenderer의 논리적 오류와 해결책

2절에서 이미 기술한 바와 같이, vjVTK는 vjRenderer와 vtkRender를 함께 가지 고 있다가, contextPreDraw() 함수를 호출할 때 vjRenderer에 등록된 내용을 vt kRenderer에 반영한다. 다시 한 번 updateRender() 함수를 살펴보면, updateRen derer() 함수의 논리적 오류를 바로 발견할 수 있다.

void vjRenderer::updateRenderer(vtkRenderer* renderer) {

for(std::vector<RendererCommand*>::iterator it = mCommandList.begin();

it != mCommandList.end(); it++) {

(*it)->execute(renderer);

} }

[소스 2-2 vjRenderer::updateRenderer()]

updateRenderer() 함수가 최초에 수행되었을 때는 별 문제가 없다. 그러나, 두 번 수행되었다고 생각해 보자. 이 코드의 어디에도 실행한 명령어를 지우는 부분 은 존재 하지 않는다. 즉 두 번째 updateRenderer 함수를 실행하면, 이전의 명령 어를 그대로 다시 한 번 더 실행하게 되는 것이다. 만일 명령어 중에 AddActor 존재 한다면, 이것은 시스템의 메모리가 충분할 때까지 vtkRenderer에 계속 vtk Actor가 추가되어 메모리가 증가할 것이다. 또한, DeleteActor가 추가되면, 이미 존재하지 않는 vtkActor를 한 번 더 지우게 된다. 이 때문에, DeleteActor()로 v

tkActor를 지울 때 마다 segmentation fault가 발생한다. 이것은 매우 간단하게 해결할 수 있다. 아래와 같이 명령을 다 수행한 후 이들을 command list를 비우 면 된다.

void vjRenderer::updateRenderer(vtkRenderer* renderer) {

for(std::vector<RendererCommand*>::iterator it = mCommandList.begin();

it != mCommandList.end(); it++) {

(*it)->execute(renderer);

}

// delete commads that already was performed mCommandList.clear();

}

[소스 2-3 Modified vjRenderer::updateRenderer()]

관련 문서