용이원이 블로그

OpenGL과 Vulkan에 대해 본문

기술 이야기

OpenGL과 Vulkan에 대해

용이원이 2025. 7. 13. 11:49

OpenGL과 Vulkan에 대해 훨씬 더 깊이 있고 자세하게 설명해 드리겠습니다. 두 API의 철학적 차이부터 구조적인 특징, 그리고 실제 개발에 미치는 영향까지 심층적으로 살펴보겠습니다.


## OpenGL: 편리함을 추구하는 베테랑 🎨

**OpenGL (Open Graphics Library)**은 "개발자에게 편리한 그래픽 개발 환경을 제공하자"는 철학에서 출발했습니다. 복잡한 그래픽 하드웨어(GPU)의 작동 방식을 개발자가 일일이 알 필요 없이, 추상화된 높은 수준의 명령어를 통해 그래픽을 제어할 수 있도록 설계되었습니다.

핵심 아키텍처: '상태 머신 (State Machine)'

OpenGL의 가장 큰 특징은 상태 머신 모델을 기반으로 한다는 점입니다. 이는 마치 그림을 그리기 전에 팔레트에 물감을 짜고, 붓을 고르고, 캔버스의 특정 위치를 정하는 것과 같습니다.

  1. 상태 설정: 개발자는 "이제부터 그릴 도형의 색상은 파란색(glColor)"이라거나 "도형을 오른쪽으로 5만큼 이동시켜라(glTranslate)" 와 같은 명령으로 '현재 상태'를 계속해서 변경합니다.
  2. 그리기 명령: 상태 설정이 끝나면, "이 상태로 삼각형을 그려라(glDrawArrays)" 와 같은 그리기 명령을 내립니다. GPU는 설정된 현재 상태 값을 바탕으로 도형을 렌더링합니다.

이 방식은 직관적이고 배우기 쉽다는 큰 장점이 있습니다. 하지만, 프로그램이 복잡해질수록 수많은 상태를 계속 추적하고 변경해야 하므로, 예상치 못한 오류가 발생하거나 코드가 지저분해질 수 있습니다.

'똑똑하지만 비밀스러운' 그래픽 드라이버

OpenGL은 그래픽 드라이버에 많은 권한과 책임을 위임합니다. 개발자가 내린 간단한 명령을 드라이버가 해석해서, 실제 GPU가 가장 효율적으로 작업할 수 있도록 최적화하고 자원을 관리합니다.

  • 장점: 개발자는 하드웨어의 복잡성에서 해방되어 그래픽 구현 자체에 집중할 수 있습니다.
  • 단점: 드라이버는 일종의 '블랙박스'처럼 작동합니다. 개발자는 드라이버 내부에서 어떤 최적화가 일어나는지 정확히 알 수 없으며, 이로 인해 예측 불가능한 성능 저하가 발생할 수 있습니다. 특히, 드라이버가 작업을 처리하는 과정에서 CPU의 한 코어에만 부담이 집중되는 CPU 병목 현상이 발생하기 쉽습니다. 이는 최신 멀티코어 CPU의 성능을 제대로 활용하지 못하는 결과로 이어집니다.

## Vulkan: 성능을 향한 하드코어 제어 🚀

Vulkan은 OpenGL의 한계를 극복하고, 최신 하드웨어의 성능을 한계까지 끌어내기 위해 탄생했습니다. "개발자에게 GPU에 대한 거의 모든 제어 권한을 주겠다"는 철학을 가지고 있습니다. AMD의 Mantle API에서 큰 영향을 받아 설계되었습니다.

핵심 아키텍처: '명시적 제어 (Explicit Control)'

Vulkan은 OpenGL의 상태 머신 모델을 버리고, 개발자가 모든 것을 명시적으로 제어하도록 요구합니다. 드라이버의 역할을 최소화하고, 그 책임을 개발자에게 넘깁니다.

  1. 커맨드 버퍼 (Command Buffers): Vulkan에서는 모든 그리기 명령을 GPU에 직접 보내는 것이 아니라, **'커맨드 버퍼'**라는 작업 목록에 미리 기록합니다. "삼각형 A를 그리고, 텍스처 B를 입히고, 조명 C를 적용하라"와 같은 일련의 작업들을 버퍼에 차곡차곡 쌓아둡니다.
  2. 큐 제출 (Queue Submission): 작업 기록이 끝난 커맨드 버퍼를 개발자가 원하는 시점에 한꺼번에 GPU의 작업 큐(Queue)에 제출합니다. GPU는 이 작업 묶음을 받아서 순차적으로 처리합니다.

이 방식의 가장 큰 장점은 멀티스레딩에 극도로 유리하다는 것입니다. 여러 개의 CPU 코어가 각각 다른 커맨드 버퍼를 동시에 생성한 뒤, GPU에 제출할 수 있습니다. 이는 OpenGL의 단일 스레드 방식에서 발생하는 CPU 병목 현상을 획기적으로 해결해 줍니다.

개발자의 늘어난 책임

Vulkan은 강력한 제어권을 주는 대신, 개발자에게 더 많은 책임을 요구합니다.

  • 파이프라인 상태 객체 (PSO): OpenGL처럼 상태를 하나씩 바꾸는 대신, 렌더링에 필요한 모든 상태(셰이더, 블렌딩, 깊이 테스트 등)를 하나의 덩어리인 **파이프라인 상태 객체(PSO)**로 미리 구워놓고 재사용합니다. 이는 매우 효율적이지만, 사전에 모든 경우의 수를 고려하여 PSO를 만들어야 하므로 초기 설정이 복잡합니다.
  • 메모리 관리: GPU 메모리 할당과 해제를 개발자가 직접 관리해야 합니다. 이는 까다롭지만, 메모리 사용을 최적화할 수 있는 여지를 줍니다.
  • 오류 검사: 드라이버가 거의 아무것도 해주지 않기 때문에, 개발자의 실수를 잡아내기 어렵습니다. 이를 보완하기 위해 **'Validation Layers'**라는 디버깅 도구를 개발 중에만 활성화하여 오류를 검사해야 합니다.

## 쉬운 비유: 레스토랑 주문 vs 직접 요리 👨‍🍳

  • OpenGL고급 레스토랑에서 메뉴를 보고 주문하는 것과 같습니다. "스테이크 미디엄 레어로 주세요"라고 간단히 주문하면, 주방장(드라이버)이 알아서 최상의 결과물을 만들어 줍니다. 편리하지만, 주방 안에서 무슨 일이 일어나는지는 알 수 없고, 내 입맛에 100% 맞지 않을 수도 있습니다.
  • Vulkan레스토랑 주방 전체를 빌려서 직접 요리하는 것과 같습니다. 재료 손질부터 불 조절, 플레이팅까지 모든 것을 직접 제어해야 합니다. 과정은 매우 복잡하고 전문 지식이 필요하지만, 내 의도대로 완벽한 요리를 만들어낼 잠재력이 있습니다.

## 핵심 차이점 심층 비교

항목 OpenGL Vulkan
철학 높은 추상화, 개발 편의성 낮은 오버헤드, 하드웨어 직접 제어
아키텍처 상태 머신 (State Machine): 상태를 계속 변경하며 즉시 그림 명시적 제어 (Explicit Control): 커맨드 버퍼에 작업을 기록 후 일괄 제출
드라이버 역할 무거움 (Heavy): 많은 최적화와 자원 관리를 자동으로 수행 가벼움 (Thin): 단순한 명령어 전달 및 하드웨어 제어만 담당
CPU 활용 주로 단일 스레드에 의존, 병목 현상 발생 가능성 높음 멀티스레딩에 극도로 최적화, 여러 코어를 효율적으로 활용
메모리 관리 드라이버가 암묵적으로 관리 개발자가 명시적으로 할당 및 해제
오류 검사 드라이버가 어느 정도 오류를 감지하고 처리 Validation Layers라는 별도 도구를 통해 개발자가 직접 검사
코드 복잡성 상대적으로 간결하고 코드량이 적음 매우 장황하고(verbose) 초기 설정에 많은 코드가 필요
적합한 프로젝트 교육, 간단한 앱, CAD, 레거시 시스템 고사양 게임, 게임 엔진, 실시간 시뮬레이션

## 그래서, 무엇을 선택해야 할까요?

  • OpenGL을 선택하는 경우:
    • 컴퓨터 그래픽스를 처음 배울 때
    • 빠르게 프로토타입을 만들어야 할 때
    • 성능이 아주 중요하지 않은 과학 시각화나 간단한 2D/3D 애플리케이션을 만들 때
  • Vulkan을 선택하는 경우:
    • 최신 AAA급 게임이나 고성능 게임 엔진을 개발할 때
    • CPU 병목 현상 없이 GPU 성능을 극한까지 활용해야 할 때
    • 안드로이드와 같이 드라이버 품질이 파편화된 환경에서 일관된 성능을 내야 할 때

결론적으로, OpenGL은 사용하기 쉬운 길을 제공하는 대신 성능의 상한선이 명확하고, Vulkan은 어렵고 복잡한 길을 요구하는 대신 현존하는 최고의 성능을 이끌어낼 수 있는 잠재력을 제공합니다.