Vulkan - 1. 벌칸의 특징, 그리고 시작을 위해 구성하기(Windows)

2022. 6. 8. 15:02Vulkan

개요

벌칸은 저수준에 대한 많은 제어가 가능하여 성능이 뛰어난 API라고 알려져 있습니다. 그래픽스 맥락에서는 대략 어느 정도를 제어할 수 있고 어떤 식으로 사용하게 될지에 대한 큰 그림을 확인하며, 사용을 위해 벌칸 API를 다운로드하고 일단 작동하는 프로그램을 만들어 봅니다.

목차

본문

1. 특징을 간단하게만 알아보자

2. 세팅하고 프로그램 돌려 보기

3. 요약

본문

1. 특징을 간단하게만 알아보자

OpenGL에서 삼각형을 하나 그릴 때 프로그램에서 뭘 만들었었는지 떠올려 봅시다.

가장 먼저 OpenGL 컨텍스트를 초기화해서 창 시스템에 연결했었고, 셰이더 단계를 컴파일하고, 그것을 사용한다고 하고, 정점 버퍼 내용을 만들어서 바인드하고, 그리기 명령을 내리면 됐었습니다. OpenGL은 전역에서 보이지 않는 상태 머신을 쓰고 기본적으로 주어진 상태가 있어 초기화하고 나서 이것저것 중간에 조절하면 되는 식입니다.

Vulkan은 다릅니다. 잠깐 표를 만들어 대응해 볼까요?

OpenGL Vulkan
컨텍스트 초기화, 창 시스템에 연결
LoadGLLoader(), glfwMakeContextCurrent()
인스턴스를 만들어 Vulkan 함수를 불러오고, 가용 물리 장치를 찾고 거기서 필요한 큐 계열을 찾고, 물리 장치로부터 가상(논리적) 장치를 생성하고, 가상 장치로부터 사용할 큐를 생성하고, 창 표면을 정의하여 창 시스템에 붙임, 명령 풀을 만들어 그를 통해 버퍼를 할당하고, 렌더 패스를 시작
셰이더 컴파일하여 파이프라인 생성.
glCompileShader(), glLinkProgram()
 고정 기능은 glEnable() 등으로 필요할 때 변경
SPIR-V까지 컴파일한 셰이더로 셰이더 모듈을 만들고, 하드웨어 고정 기능에 대한 세팅을 구성하여 셰이더 모듈과 합쳐 파이프라인을 만듦
위에서 설정한 대부분의 사항은 실시간 변경이 불가능하고 별도의 파이프라인을 만들어야 함
창에다가 기본 프레임버퍼를 붙이게 돼 있음
창 크기가 변하면 glViewport로 자연스럽게 보정하게 하면 됨
스왑 체인을 만들어 버퍼(이미지)를 세팅하고, 만들어진 모든 이미지는 이미지 뷰를 통해서 접근해야 하고, 프레임버퍼 첨부물을 정하는 렌더 패스를 만들고, 그걸로 프레임버퍼를 만듦
창 크기가 변하면 저 이미지를 다시 만들어야 함 
정점 내용을 만들고 버퍼에 올리고 glVertexAttribPointer 계열 함수로 속성 구분 받는 정점 속성 형식은 파이프라인에서 명시, 적절한 메모리 형식을 정하여 할당. 메모리 매핑으로 gpu에서 읽을 수 있게 함, 혹은 스테이징 버퍼로부터 장치 버퍼로 복사
정점 객체를 바인드하고 glDraw 계열 함수를 사용하여 그림. 그리기 명령이 끝날 때까지 CPU는 대기 명령 풀에 명령을 올리고 필요한 동기화 처리를 세팅, 큐의 명령을 실행. 명령을 큐에 올리고 CPU는 바로 하던 일 진행

이게 내적으로 이루어지는 일이 아니라 개발자가 해야 할 일을 나열한 것입니다. 여기서 대충 할 일이 너무 많다는 생각과 그래도 생각보다 짧다며 할 수는 있겠다는 생각이 들면 적당하겠네요. 결국 결정적인 차이점은 말 그대로 제어권입니다. (Windows에서 사용되는 Direct3D 12나 애플 계열에서 사용되는 Metal 역시 이런 느낌이며 고성능이라고 알려져 있습니다.) 이외에 위 표의 마지막 항목에서 GPU 동작은 비동기라는 점도 내포되어 있습니다. 그래서 앞으로 우리는 받은 제어권 중에서 성능과 용도의 절충에 해당하는 부분을 알기 쉽게 응용 단에 제시할 필요가 있습니다. 예를 들어 더블/트리플 버퍼링은 굳이 선택권을 주지 않고 밑단에서 알아서 하고, 텍스처 필터링이나 밉맵 수준 같은 건 GL에서 제공하는 정도의 자유는 부여해야겠죠.

참고로 바로 다음 글 하나 안에서 삼각형 그리기 위해 필요한 과정을 다 할겁니다. 새로 배우는 것에 대한 의존성을 내리기 위해 필요한 모든 C 코드를 때마다 작성하는 식으로 합니다.

 

2. 세팅하고 프로그램 돌려 보기

벌칸을 이용한 프로그램을 실행하려면 필요한 것이 있습니다. 먼저 Windows 기준 system32에 이게 있나 확인해 보세요.

대부분의 장치에 opengl32.dll이 있어서 프로그램이 이를 이용할 수 있었듯 벌칸을 돌리려면 이게 있어야 합니다. 없는데 이걸 다운받으면 되냐고요? 그건 다음 것을 실행할 수 있는지에 따라 달라집니다.

그 다음은 Vulkan SDK를 설치합니다. 이 링크에서 여러분의 환경에 맞는 SDK를 받아서 설치해 주세요. 저 같은 경우 1.3.204.1을 가지고 있습니다.

 

LunarXchange

LunarG uses cookies on our site to help us deliver the best user experience. Review our Privacy Policy for more information. Do you accept cookies? Yes

vulkan.lunarg.com

진행하다 보면 4개의 선택 사항이 등장합니다. 저의 경우에는 아무것도 선택하지 않았는데, 32비트 버전도 제공하고 싶거나(맨 위), 셰이더 디버그가 필요하거나(그 아래 2개 중 64비트/32비트 원하는 대로), GLM 같은 서드파티 라이브러리가 필요하면(맨 아래) 체크해서 같이 깔면 됩니다.

Vulkan SDK는 아파치2.0 라이센스를 가지고 있습니다. 쉽게 말해 니가 만들었다고 우기지 않고 라이센스 내용을 프로그램 안에서 보여주기만 하면 어떻게 써도 된다는 겁니다. 설치한 디렉토리에 가면 Bin, Config, Demo 등 여러 가지가 있습니다. 먼저 Bin에 있는 vkcube를 실행했을 때, 별 문제 없이 LunarXchange 로고가 그려진 육면체가 회전하고 있다면 벌칸의 웬만한 기능을 사용할 수 있다고 보면 될 것 같습니다. 다시 Include로 가면 여러분이 이 라이브러리를 사용하기 위해 포함해야 하는 헤더 파일들이 있습니다. 일단 여기서는 vulkan 폴더랑 shaderc 폴더를 쓸 예정입니다. 기본기를 배우는 건 vulkan 폴더 선에서 끝이고, shaderc는 있어도 없어도 그만인 수준입니다.

 

그리고 Windows랑 X11에서 창을 생성하고 입력 관련해서도 도움을 주는 GLFW를 사용할 겁니다. 여기서 받아 주세요. 소스를 받아 Cmake 해도 되고 pre-compiled 라이브러리를 받아 써도 됩니다.

 

Download

GLFW source code and binary distribution download links.

www.glfw.org

안드로이드와 X11은 맨 첫 글에서 명시했듯 기본기가 끝나고 나서 할 예정입니다.

Cmake를 쓰는 사람에게는 설명할 필요가 없을 것 같고, 미리 컴파일된 것을 다운로드한 경우 비주얼 스튜디오의 맞는 버전의 폴더를 골라 주세요. 예를 들어 저처럼 2022판을 쓴다면 lib-vc2022를 고르면 됩니다. 그 안에 있는 glfw3_mt.lib을 쓰면 됩니다. MSVC의 빌드에서는 MT 옵션과 MD 옵션이 있는데, MT는 CRT 관련 내용이 실행 파일에 포함되고 MD는 아니라고 합니다. 저는 MT로 빌드할 거고 그걸 원하지 않는다면 glfw3.lib을 쓰면 됩니다. glfw3dll.lib은 실행 파일을 배포할 때 glfw3.dll을 같이 배포해야 할 겁니다.

 

그 다음 Windows용 프로젝트를 생성해 봅시다. '빈 프로젝트' 만들면 됩니다. 만들고 나면 일단 main.cpp라는 파일을 추가합니다. 그 다음 프로젝트 속성을 다음과 같이 구성합니다.

  • C/C++ - 코드 생성 - 런타임 라이브러리 - 릴리즈 버전은 다중 스레드(\MT), 디버그 버전은 (\MTd)
  • 일반 - C++ 언어 표준 - C++17

다른 의도가 있다면 기타 속성을 원하는 대로 하면 됩니다. 추가 포함 디렉터리 등을 명시하지 않는 게 의아한 독자도 있을 텐데, 프로젝트 설정과 무관하게 쓸 수 있도록 일괄 ""로 바꾸고 상대 위치를 고정할 겁니다. 원한다면 경로를 여기에 명시하고 아래 과정을 안 해도 됩니다.

디렉토리 구성을 이렇게 해 주세요.

(솔루션/프로젝트/소스가 있는 디렉토리)

  • glfw 폴더 아래에는 방금의 glfw3.h, glfw3_mt.lib이 있습니다.
  • shaderc 폴더는 방금 SDK를 받아 놓은 곳에서 Include 폴더에 있는 shaderc 폴더를 복사해 온 겁니다. 참고로 shaderc는 구글이 만든 건데, 아파치 라이센스입니다. 여기에 더하여 Lib 디렉토리에서 shaderc_shared.lib을 복사해 옵니다.
  • vulkan 폴더도 마찬가지로 SDK를 받아 놓은 곳에서 vulkan 폴더를 복사해 온 겁니다. 여기에 더하여 Lib 디렉토리에서 vulkan-1.lib을 복사해 옵니다.

그 다음 실행 파일이 있는 디렉토리에는 SDK의 Bin 디렉토리에서 shaderc_shared.dll을 가져옵니다. 동적 링킹을 사용하는 이유는 MT로 빌드하기 때문입니다. 개인적으로는 개발 중에는 프로그램 시작 시 셰이더를 컴파일하도록 하고, 개발이 완료되면 미리 컴파일된 것으로 배포하는 것이 가장 편하다고 봅니다.

마지막으로 glfw3.h에서 #include <vulkan/vulkan.h> 부분을 #include "../vulkan/vulkan.h"로 고치고, shaderc.h에서 #include "shaderc/..." 부분에서 shaderc/를 빼 주세요.

 

이제 이걸 소스에 붙여 넣고 컴파일해 주세요. 지금 뜻은 몰라도 됩니다. 어차피 이 코드 다 지우고 새로 쓸 겁니다. 이 코드는 여기의 코드를 거의 그대로 썼습니다.

#define GLFW_INCLUDE_VULKAN
#include "externals/glfw/glfw3.h"

#include <cstdio>
#include <filesystem>

#ifdef _MSC_VER
	#pragma comment(lib, "externals/vulkan/vulkan-1.lib")
	#pragma comment(lib, "externals/glfw/glfw3_mt.lib")
#endif

int main(int argc, char* argv[]) {
    std::filesystem::current_path(std::filesystem::path(argv[0]).parent_path());
    glfwInit();
    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    GLFWwindow* window = glfwCreateWindow(800, 600, u8"시작", nullptr, nullptr);
    uint32_t extensionCount = 0;
    vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr); printf("%d ext available\n", extensionCount);
    while (!glfwWindowShouldClose(window)) {
        glfwPollEvents();
    } glfwDestroyWindow(window); glfwTerminate();
    return 0;
}

실행 결과에서 콘솔 창과 흰 창이 이렇게 보이면 성공입니다. 0 ext available라고 출력된 경우라면 안타깝지만 현 장비로는 더 앞으로 나아갈 수 없습니다. 컴파일 혹은 링킹 중에 다른 오류가 있었다면 문의해 주세요. 그리 큰 일은 아닐 겁니다.

콘솔 창과 흰 창이 이렇게 보이면 성공입니다. 

 

프로그램을 배포할 때도 계속 이렇게 콘솔을 보게 해야겠어?
개발이 완료되면 저런 건 필요 없지. Windows에서는 프로젝트 속성 - 구성 속성 - 링커 - 고급에 들어가서 진입점을 "mainCRTStartup"으로 바꾸고, 다시 링커 - 시스템에 들어가서 하위 시스템을 "창(SUBSYSTEM:WINDOWS)"로 바꾸면 없어지더라.

저도 원리는 모르기 때문에, 리눅스 대상 크로스 컴파일을 할 때도 이 방법이 가능할지는 모릅니다. GLFW 자체에는 이 콘솔을 안 보이게 하는 기능이 없었던 것 같고요.

 

https://github.com/onart/OAVKE/tree/40436954fd399884c52c2d3629c48b854957dd79에서 클론하셔도 가능합니다. (링크는 3번째 커밋입니다.) 사실 이걸 쓰면 dll이 모두 갖춰졌으므로 SDK를 안 받아도 개발 진행이 되지만, 이후 사용할 "확인(validation) 계층"은 SDK를 가지고 있어야 사용할 수 있다고 하니, 설치는 해 주시기 바랍니다.

3. 요약

  • 벌칸은 그래픽 카드에 접근하는 것부터 하여 파이프라인 생성, 프레임 버퍼 구성, 메모리 확보 등 전체에 걸쳐 개발자에게 제어를 맡깁니다. 기본값은 없으며 일일이 세팅해야 합니다.
  • 이 시리즈에서는 앞으로 GLFW를 이용하여 PC의 창 시스템과 벌칸을 연동합니다.

 

과제

없음

 

'Vulkan' 카테고리의 다른 글

Vulkan - 5. 인덱스 버퍼와 스테이징 버퍼  (0) 2022.06.21
Vulkan - 4. 공유(uniform) 변수  (0) 2022.06.16
Vulkan - 3. 세마포어와 펜스  (0) 2022.06.15
Vulkan - 2. 안녕 삼각형  (0) 2022.06.08
Vulkan  (0) 2022.06.08