반응형
모던 Vulkan (C++ 버전) 시리즈의 일곱 번째 글입니다. 이제까지 인스턴스 생성, 디바이스/큐 확보, 커맨드 버퍼, 메모리 관리, 버퍼 생성, Compute 파이프라인 및 디스크립터 구성까지 모두 C++ RAII 패턴과 Vulkan-HPP를 활용해 재정비했습니다. 이제 드디어 실제 GPGPU 연산을 수행하는 벡터 덧셈 예제를 Modern C++ 스타일로 완성해봅시다.입문 시리즈에서 C 스타일로 구현했던 벡터 덧셈 과정(Host에서 A, B를 준비한 뒤 GPU로 올리고, Compute 셰이더로 A+B를 C에 기록, 다시 Host로 결과를 가져오는 과정)을 이제 Vulkan-HPP 기반 C++ RAII 패턴, 예외 처리, STL 컨테이너와 함께 사용해 깔끔하게 재작성하겠습니다.목표호스트에서 std::..
시리즈의 열 번째이자 마지막 글입니다. 지금까지 1편부터 9편에 걸쳐 Vulkan을 이용한 GPGPU 프로그래밍 기초를 다뤘습니다. CUDA에 익숙한 분들을 대상으로 Vulkan의 준비 과정, Compute 셰이더 파이프라인 구성, 메모리 및 디스크립터 관리, 디버깅 및 프로파일링 기법 등을 차근차근 설명했으며, 간단한 벡터 덧셈 예제를 통해 전체 흐름을 체험해보았습니다. 이제 이 입문 시리즈를 마무리하며, 이후 Intermediate/Advanced 주제로 나아갈 때 참고할 만한 자료와 도전 과제들을 간단히 정리하고자 합니다.입문 시리즈 마무리이 시리즈를 통해 다음과 같은 과정들을 이해하고 실습했습니다.Vulkan 환경 설정(Ubuntu/Windows), CMake를 통한 빌드인스턴스, 물리 디바이스,..
시리즈의 아홉 번째 글입니다. 지금까지 인스턴스 설정, 물리 디바이스 선택, 로지컬 디바이스와 큐 확보, 커맨드 버퍼 & 큐를 통한 명령 전달, 메모리 관리, Compute 파이프라인 & 디스크립터 설정, 그리고 벡터 덧셈 예제로 GPGPU 전체 흐름을 익혀보았습니다. 또한 디버깅과 프로파일링에 대해 간단히 살펴봤습니다. 이번 글에서는 지금까지 다룬 내용을 좀 더 실전적 관점에서 정리하고, 다음 단계(Intermediate/Advanced)로 넘어가기 전 고려할 만한 주제들을 언급하겠습니다.여기까지 다룬 내용 정리환경 설정 & 기본 예제:Vulkan SDK, 드라이버 설치가장 단순한 “Hello Vulkan!”로 인스턴스 생성 확인CMake를 통한 빌드 예제물리 디바이스 & 로지컬 디바이스 & 큐:GPU..
아래는 이 시리즈의 여덟 번째 글입니다. 지난 글(#7)에서는 벡터 덧셈 예제를 통해 Vulkan을 활용한 GPGPU 연산의 전체 흐름을 체험해보았습니다. 이제 어느 정도 기본 개념과 실전 예제를 익혔다면, 개발 과정에서 마주할 수 있는 문제들을 어떻게 디버깅하고, 성능을 프로파일링할 수 있는지 알아볼 차례입니다. 이번 글에서는 디버깅, 검증 레이어(Validation Layers)와 성능 프로파일링 기초를 살펴보며, 복잡한 Vulkan 생태계에서 발생할 수 있는 다양한 이슈를 어떻게 추적하고 최적화할 수 있을지 소개하겠습니다.왜 디버깅과 프로파일링이 중요한가?Vulkan은 로우레벨 API이기 때문에 초기화, 메모리 관리, 파이프라인 설정, 디스크립터 업데이트 등 다양한 단계에서 실수가 발생하기 쉽습니다..
지난 글(#6)에서는 Compute 셰이더를 SPIR-V로 컴파일하고, 이를 기반으로 Compute 파이프라인을 만들고, 디스크립터를 활용해 셰이더에 데이터를 연결하는 방법을 살펴봤습니다. 이제 이 모든 준비 과정을 종합해 실제로 GPGPU 연산을 수행하는 간단한 예제를 만들어보겠습니다. 이번 글에서는 벡터 덧셈(Vector Addition) 예제를 통해, 호스트에서 데이터를 준비하고 GPU로 전달한 뒤, Compute 셰이더를 통해 연산을 수행하고 결과를 다시 가져오는 전체 흐름을 정리해볼 것입니다.CUDA에서 벡터 덧셈은 대략 cudaMalloc, cudaMemcpy, kernel>>, cudaMemcpy라는 단순한 과정을 거치며, 커널 코드도 data[idx] = a[idx] + b[idx];처럼 ..
지난 글(#5)에서 우리는 Vulkan에서 GPU 메모리를 관리하고, 버퍼나 이미지를 생성하고, 이를 GPU 메모리에 할당하는 기초를 다뤘습니다. 이제는 GPGPU의 핵심인 Compute 셰이더(Compute Shader)를 사용하기 위한 준비 단계로 넘어가겠습니다. Vulkan에서 Compute 셰이더를 실행하려면, 셰이더 코드를 SPIR-V로 컴파일하고, 이를 Compute 파이프라인(Compute Pipeline)에 등록한 뒤, 디스크립터(Descriptor)를 통해 버퍼, 이미지 등 자원을 셰이더에 연결해야 합니다.CUDA에서는 .cu 파일에 커널 코드를 작성하고 nvcc로 컴파일한 뒤 >> 표기법으로 커널을 호출하는 방식에 익숙할 것입니다. 하지만 Vulkan에서는 셰이더를 GLSL/HLSL로 ..
지난 글(#4)에서는 큐(Queue)와 커맨드 버퍼(Command Buffer) 개념을 정리하며, Vulkan이 GPU에 명령을 전달하는 독특한 방식을 살펴봤습니다. 이제 GPU에게 할 일을 시킬 수 있는 준비는 되었지만, 정작 우리가 처리할 데이터(배열, 이미지 등)를 GPU 메모리에 올려놓는 과정은 아직 다루지 않았습니다. 이번 글에서는 Vulkan 메모리 관리의 기초인 메모리 할당, 버퍼(Buffer), 이미지(Image) 객체를 다뤄보겠습니다.CUDA를 사용해보신 분이라면 cudaMalloc과 cudaMemcpy 정도로 GPU 메모리 관리가 비교적 단순했다는 기억이 있을 겁니다. 반면 Vulkan에서는 메모리 할당이 좀 더 “수작업”에 가깝고, 어떤 메모리 타입을 쓸지 직접 결정하고, 버퍼나 이미..
지난 글(#3)에서는 물리 디바이스를 골라서 로지컬 디바이스를 만들고, 큐를 확보하는 단계까지 진행했습니다. 이제 GPU에 작업을 시키기 위해서는 명령(Commands)들을 모아둘 그릇이 필요한데, Vulkan에서는 이를 "커맨드 버퍼(Command Buffer)"라고 부릅니다. 이번 글에서는 커맨드 버퍼를 다루는 법과 큐에 이 버퍼를 제출(Submit)하는 과정을 살펴보겠습니다. 또한 CUDA의 스트림(Stream) 개념과 비교하여 Vulkan 방식이 어떤 점에서 다른지 이해해봅시다.왜 커맨드 버퍼인가?간단히 말해, 커맨드 버퍼는 GPU에 내릴 명령을 모아둔 리스트입니다. 이 리스트를 나중에 큐(Queue)에 제출하면, GPU가 순서대로 실행하게 됩니다. 이런 구조는 단순히 함수 호출로 GPU를 동작시..
왜 이렇게 복잡할까?CUDA에 익숙한 분이라면 cudaSetDevice() 하나로 GPU를 선택하고, 바로 커널을 실행했던 기억이 있을 겁니다. 하지만 Vulkan은 조금 다릅니다. Vulkan은 다소 “하드코어”한 API라 할 수 있습니다. CUDA가 “GPU는 NVIDIA 것이고, 나머지는 다 내가 알아서 할게”라고 말해주는 친절한 셰프라면, Vulkan은 “냉장고는 저쪽, 칼은 여기, 조리대는 저기 있으니 필요한 걸 직접 꺼내서 써”라고 말하는 요리학원 선생님 같은 느낌이에요. 초반에 해야 할 준비가 많지만, 그만큼 다양한 하드웨어와 상황에 대처할 수 있는 큰 자유를 줍니다.물리 디바이스(Physical Device) 열람하기인스턴스를 만든 상태라면, 이제 시스템에 장착된 GPU 목록(물리 디바이스..
환경 설정이전 글(#1)에서 Vulkan을 GPGPU용으로 활용할 수 있다는 개념적 소개를 했습니다. 이제 실제 코드를 다루려면 환경이 제대로 갖춰져야 합니다. Ubuntu를 예로 들어 Vulkan SDK 설치, 드라이버 설정, CMake 및 기타 툴 설치 방법을 정리하고, Windows 사용자를 위한 간단한 가이드도 제공하겠습니다. 또한 CUDA 경험자들이 Vulkan 환경 구축을 이해하기 쉽도록 CUDA와의 차이점도 다시 상기시켜드리겠습니다.Ubuntu에서 Vulkan 환경 설정1. GPU 드라이버 설치:NVIDIA의 경우:sudo apt updatesudo ubuntu-drivers devicessudo ubuntu-drivers autoinstallAMD/Intel의 경우에는 Mesa 드라이버가 ..