상세 컨텐츠

본문 제목

FT_Newton: Vulkan 공부 및 리팩토링 - (1)

Computer Graphics/FT_Newton

by Banjosh 2025. 1. 6. 12:46

본문

이번 프로젝트부터는 Vulkan API를 사용하기로 했다. OpenGL과 Vulkan을 비교하며 어떤 차이가 있는지, 그리고 실제로 사용하면서 느낀 점들을 정리해본다.

 

Vulkan과 OpenGL

둘의 차이를 쉽게 말하면, Vulkan은 개발자가 직접 해야 할 일이 많은 대신 성능에서 이득을 볼 수 있고, OpenGL은 자동으로 처리해주는 부분이 많아 개발 편의성이 높지만 그만큼 오버헤드가 있다. 아래의 간단한 비교를 통해 이를 확인해보자.

OpenGL

  • Vulkan에 비해 고수준 API로, 드라이버 내부에서 작업을 자동으로 처리한다.
  • 기본적으로 단일 스레드로 설계되어 있다.
  • 드라이버가 많은 작업을 자동 처리하기 때문에 오버헤드가 높을 수 있다.
  • 메모리 관리를 자동으로 처리한다.

Vulkan

  • OpenGL에 비해 저수준 API로, 개발자가 하드웨어에 더 직접적으로 접근할 수 있어 메모리 관리, 동기화, 멀티스레딩 등을 제어할 수 있다.
  • 멀티스레딩에 최적화되어 있다.
  • 모든 것을 개발자가 직접 관리해야 해서 오버헤드를 줄일 수 있다.
  • 메모리 관리는 개발자의 책임으로, 직접 관리해야 하지만 그만큼 최적화가 가능하다.

게임 엔진에서 성능은 매우 중요한 요소다. 그래서 우리는 자연스럽게 Vulkan을 선택하게 되었고, 이에 따른 공부를 진행해 Vulkan 튜토리얼을 완수했다. 그런데 여기서 또 다른 문제가 발생했다.

 

Vulkan 리팩토링

Vulkan의 장점에도 불구하고, 각 객체 간의 의존성이 너무 강해서 기능별 분리가 어렵다는 단점이 있다. 그래서 Vulkan 튜토리얼 코드도 한 파일에 2000줄이 넘는 경우가 많았다. 그대로 작업하기엔 불가능에 가까웠기 때문에, 코드를 정리하고 리팩토링을 진행했다.

최대한 기능별로 클래스를 나누려고 노력한 결과, 아래와 같은 구조를 만들었다.

 

클래스 구조

class App
렌더링 컨텍스트를 관리하며 관련된 모든 객체들의 초기화와 렌더링 루프를 담당.

  • VulkanInstance : Vulkan을 사용하기 위한 기본 객체들을 관리
  • DeviceManager : GPU 작업 관리를 위한 객체들을 모아둔 클래스
  • SwapChainManager : 렌더링 작업에 필요한 스왑 체인과 이미지들을 관리
  • CommandManager : GPU 명령 작업을 기록하는 데 필요한 클래스
  • DescriptorPool : Descriptor Set을 할당하고 관리하는 클래스
  • SyncObject : 멀티스레딩을 위한 동기화 도구 관리
  • Renderer : 렌더링 관련 설정 관리
  • Model : 렌더링 대상 정보 관리

class VulkanInstance

  • VkInstance : Vulkan 객체들을 생성하기 위한 기본 객체
  • VkDebugUtilsMessengerEXT : 오류 발생 시 디버그 메시지를 전달
  • VkSurfaceKHR : 윈도우와 상호작용하기 위한 객체

class DeviceManager

  • VkPhysicalDevice : Vulkan API와 상호작용할 수 있는 물리 GPU
  • VkDevice : 논리 장치
  • VkQueue : GPU 작업 큐

class SwapChainManager

  • VkSwapchainKHR : 렌더링 작업이 완료된 이미지를 화면에 띄우는 객체
  • VkImage : GPU 메모리에 저장된 이미지 리소스
  • VkImageView : VkImage 접근 방식을 정의
  • VkFramebuffer : Attachment들을 묶은 객체

class CommandManager

  • VkCommandPool : 커맨드 버퍼 관리
  • VkCommandBuffer : GPU가 수행할 명령 기록

class DescriptorPool

  • VkDescriptorPool : Descriptor Set 관리

class SyncObject

  • VkSemaphore : GPU 간 작업 동기화
  • VkFence : CPU와 GPU 간 작업 동기화

class Renderer

  • VkRenderPass : 렌더링 작업 관리
  • VkDescriptorSetLayout : Descriptor Set 구조 정의
  • VkPipeline : 그래픽스 파이프라인 관리

class Model

  • Mesh : 오브젝트 렌더링 정보
  • Material : 빛 처리 정보

class Mesh

  • VertexBuffer : 정점 정보
  • IndexBuffer : 인덱싱 정보
  • UniformBuffer : 유니폼 변수 정보
  • Material : 빛 처리 정보
  • VkDescriptorSet : 유니폼 변수와 샘플러 관리

리팩토링의 문제점

비슷한 기능의 객체를 묶어 기능별로 나눈 덕분에 코드가 꽤 정돈되어 보였다. 하지만 작업을 진행하면서 몇 가지 한계가 보였다.

  1. 초기화 함수의 매개변수 폭발
    각 클래스의 의존성이 너무 크다 보니 초기화 함수에 전달해야 할 매개변수가 너무 많아졌다.
  2. 확장성 부족
    렌더 패스나 서브패스를 추가하거나 다양한 셰이더를 사용하는 데 적합하지 않았다.

결론적으로, 보기에는 깔끔하지만 실사용에는 한계가 있는 리팩토링이었다. FT_Newton에서는 이 정도로도 충분했지만, 렌더링 엔진 파트를 담당하는 팀원 입장에서는 확장성이 더 중요하기 때문에 이 구조를 기반으로 다시 리팩토링 작업을 진행하고 있다.

앞으로의 방향

이번 과제에서는 현재 리팩토링된 코드를 사용해 작업을 이어가고 있지만, 물리 엔진을 완성하고 렌더링 엔진과 합칠 때는 팀원이 새로 리팩토링한 Vulkan 코드를 사용할 예정이다.

'Computer Graphics > FT_Newton' 카테고리의 다른 글

FT_Newton: 나만의 물리 엔진 제작 - (0)  (0) 2025.01.06

관련글 더보기