사전 Vulkan
표준

Vulkan

gabury1고친 사람 github-actions[bot]

Vulkan 은 프로그램이 그래픽 카드에 그림 그리기와 계산을 시킬 때 따르는 약속입니다. 업계 단체가 문서로 정한 약속이라, 그래픽 카드 회사마다 그 문서에 맞춰 드라이버를 만듭니다. 메모리를 언제 잡고 명령을 어떤 순서로 돌릴지까지 프로그램이 직접 정합니다. 드라이버가 뒤에서 하던 일이 줄어든 만큼 프로그램이 맡는 일은 늘어납니다.

쉽고 빠른 이해

Vulkan 은 그래픽 카드에 그림과 계산을 시키는 함수와 값을 정해 둔 문서입니다. 게임이 장면 하나를 그릴 때 그릴 명령을 먼저 목록에 적어 둡니다. 그 목록을 그래픽 카드의 대기줄에 한꺼번에 넣습니다.

이렇게 하는 까닭이 있습니다. 앞선 방식에서는 명령이 하나씩 차례로 처리되는 것처럼 드라이버가 뒤에서 꾸며 줬습니다. 그 일에 프로세서 시간이 들었습니다. 그리기 명령도 한 스레드에서만 만들 수 있었습니다.

어떻게 도나:

  1. 쓸 그래픽 카드를 고르고 그 카드로 통하는 통로를 엽니다
  2. 그릴 명령을 목록에 적습니다. 스레드마다 따로 적을 수 있습니다
  3. 목록을 대기줄에 넣고 다 끝났다는 신호를 기다립니다

그릴 명령을 만드는 일에 프로세서가 바빠 병목이 되는 프로그램에서 값이 큽니다. 게임이 그런 프로그램으로 꼽힙니다.

대가도 있습니다. 명령의 순서를 맞추는 일과 메모리를 잡는 일을 프로그램이 맡습니다. 잘못 불러도 대개 알려 주지 않아서 개발하는 동안에만 따로 검사를 켜 둡니다.

상세

Vulkan 은 GPU(Graphics Processing Unit, 그래픽 처리 장치)에 그래픽과 계산 일을 시키는 API(Application Programming Interface, 응용 프로그램 인터페이스)의 규격입니다. 함수와 구조체와 열거값, 그리고 그 함수를 불렀을 때 일어나야 할 동작을 문서 한 벌로 정합니다. 예를 들어 vkWaitForFences 는 CPU(Central Processing Unit, 중앙 처리 장치)가 그래픽 카드의 일이 끝나기를 기다리는 함수입니다. 이 함수의 이름과 인자와 동작이 문서에 적혀 있습니다.

아래에서는 프로그램이 Vulkan 으로 그래픽 카드를 부리는 한 바퀴를 따라갑니다. 대상은 그 바퀴에서 프로그램이 만들고 다루는 객체들입니다. 객체마다 무엇을 프로그램이 직접 정하고 무엇을 드라이버에 맡기는지를 봅니다.

낱말 둘을 먼저 정해 둡니다. 호스트는 프로그램이 도는 CPU 와 그 메모리입니다. 디바이스는 그래픽 카드입니다. 그리고 아래 문장에 괄호로 붙은 must · should 는 요구의 세기를 가리키는 규격의 낱말입니다. 뜻은 아래 「요구 강도를 읽는 법」에 있습니다.

규격과 구현

Vulkan 은 설치하는 프로그램이 아니라 문서입니다. 업계 회원사들이 모인 단체인 Khronos Group 이 만들고 관리합니다. 그 문서를 따르는 코드는 그래픽 카드의 드라이버 안에 들어 있습니다.

문서는 두 독자를 함께 겨냥합니다. 하나는 Vulkan 을 구현하는 쪽입니다. 다른 하나는 Vulkan 을 불러 쓰는 응용 프로그램 개발자입니다. 문서가 둘 사이의 계약 노릇을 합니다. 구현이 요구 사항을 다 지키면 적합(conformant)하다고 합니다. 응용 프로그램이 다 지키면 API 를 유효하게 쓴다(valid use)고 합니다.

한 번 짠 코드가 회사가 다른 그래픽 카드에서도 도는 것은 이 계약 덕분입니다. 회사마다 같은 문서에 맞춰 드라이버를 만듭니다.

디바이스와 큐

물리 디바이스는 호스트에서 쓸 수 있는 Vulkan 구현 하나를 가리킵니다. 앞 소절에서 말한 구현, 곧 그래픽 카드와 그 드라이버 한 벌이 물리 디바이스 하나로 보입니다. 하나가 대개 완전한 구현입니다. 호스트에서 쓸 수 있는 물리 디바이스의 개수는 유한합니다.

프로그램은 그중 하나를 골라 그 위에 논리 디바이스를 만듭니다. 논리 디바이스는 그 구현을 쓰려고 연 통로입니다. 상태와 자원을 다른 논리 디바이스와 나누지 않습니다.

명령은 논리 디바이스의 큐에 넣습니다. 큐는 디바이스가 일감을 꺼내 가는 대기줄입니다. 한 디바이스에 큐가 하나 이상 있습니다. 큐끼리는 서로 기다리지 않고 따로 일할 수 있습니다.

디바이스가 지원하는 큐는 큐 패밀리로 갈라져 있습니다. 같은 패밀리의 큐는 받는 일의 종류가 같아서, 한 패밀리에 보낼 일은 그 패밀리의 어느 큐에서든 돌 수 있습니다. 큐가 받는 일의 종류는 그래픽스 · 계산 · 비디오 디코드 · 비디오 인코드 · 보호 메모리 관리 · 스파스 메모리 관리 · 전송 일곱입니다.

flowchart TD
    P["물리 디바이스 · 호스트에서 쓸 수 있는 구현"] --> L["논리 디바이스 · 프로그램이 연 통로"]
    L --> F1
    L --> F2
    subgraph F1["큐 패밀리 · 받는 일의 종류가 같은 큐 묶음"]
        Q1["큐"]
        Q2["큐"]
    end
    subgraph F2["다른 큐 패밀리"]
        Q3["큐"]
    end

물리 디바이스와 큐 패밀리는 디바이스가 이미 갖춘 것을 알아보는 단계입니다. 프로그램이 만드는 것은 논리 디바이스입니다.

기록과 제출

Vulkan 함수를 불렀다고 그래픽 카드가 바로 움직이지는 않습니다. 큐에 보낼 명령 대부분은 먼저 명령 버퍼에 기록합니다. 명령 버퍼는 보낼 명령을 차례로 적어 두는 객체입니다. 명령 버퍼마다 상태를 서로 따로 관리합니다.

기록을 마친 명령 버퍼를 큐에 제출하면 그때 일이 시작됩니다. 제출 함수는 일이 끝나기를 기다리지 않고 제출만 마치면 돌아오게 되어 있습니다(should). 제출된 일은 프로그램이 더 손대지 않아도 끝까지 돕니다. 일이 끝났는지는 펜스로 압니다. 펜스는 큐의 일이 끝났다는 것을 호스트에 알리는 신호 객체입니다.

sequenceDiagram
    participant 호스트 as 호스트 스레드
    participant 버퍼 as 명령 버퍼
    participant 큐
    participant 펜스
    호스트->>버퍼: 명령을 기록한다
    호스트->>큐: 명령 버퍼를 제출한다
    큐-->>호스트: 기다리지 않고 바로 돌아온다
    Note over 큐: 디바이스가 일을 돌린다
    큐->>펜스: 다 끝나면 신호를 켠다
    호스트->>펜스: 신호가 켜지기를 기다린다

명령 버퍼는 두 단계로 갈립니다. 1차 명령 버퍼는 큐에 제출하는 명령 버퍼입니다. 2차 명령 버퍼를 불러 실행할 수도 있습니다. 2차 명령 버퍼는 큐에 바로 제출되지 않습니다. 1차 명령 버퍼가 불러야 실행됩니다.

여러 스레드에서 기록하기

Vulkan 함수는 전부 여러 스레드에서 동시에 부를 수 있습니다. 예외는 외부 동기화 대상으로 표시된 인자입니다. 그 인자는 한 번에 한 스레드만 쓴다는 것을 부르는 쪽이 보장해야 합니다(must).

명령 풀이 그 대상입니다. 명령 풀은 명령 버퍼가 쓸 메모리를 떼어 주는 객체입니다. 한 풀을 여러 스레드가 동시에 쓰면 안 됩니다. 그 풀에서 떼어 받은 명령 버퍼에 기록하는 일도 풀을 쓰는 것으로 칩니다.

그래서 여러 스레드가 동시에 기록하려면 풀을 스레드마다 따로 둡니다. 그러면 스레드끼리 서로 기다리지 않고 각자의 명령 버퍼를 채웁니다. 그리기 일을 CPU 코어 여럿에 나눠 만들 수 있다는 점이 OpenGL(Open Graphics Library)과 갈리는 큰 차이로 꼽힙니다.

순서를 맞추는 다섯 수단

구현은 큐에 제출된 일을 겹쳐 돌릴 자유가 넓습니다. 디바이스가 일을 여러 단계로 나눠 동시에 돌리기 때문에 흔히 그렇게 됩니다. 따로 정하지 않으면 한 명령 버퍼 안의 명령끼리도 순서가 정해지지 않습니다. 한 명령이 메모리에 쓴 결과가 다른 명령에 바로 보인다는 보장도 없습니다.

한 큐에 낸 제출끼리는 제출 순서와 그 밖의 암묵적 순서 보장이 지켜집니다. 그것 말고는 명령이 겹쳐 돌거나 순서가 뒤바뀔 수 있습니다. 그래서 자원에 닿는 순서를 맞추는 일은 주로 응용 프로그램의 책임입니다. 큐와 큐 사이, 큐와 호스트 사이에는 저절로 걸리는 순서가 아예 없습니다. Vulkan 은 기다림을 거는 수단 다섯을 내놓습니다. 누가 누구를 기다리느냐로 갈립니다.

수단 누가 누구를 기다리나
펜스 호스트가 디바이스의 일이 끝나기를
세마포어 한 큐의 일이 다른 큐의 일이 끝나기를. 큐와 호스트 사이에도 쓴다
이벤트 한 큐 안에서. 신호는 명령 버퍼나 호스트가 켜고, 기다림은 명령 버퍼 안에서 한다
파이프라인 배리어 한 큐 안에서. 배리어 앞에 제출한 명령과 뒤에 제출한 명령 사이 한 지점에서
렌더 패스 객체 한 큐 안에서. 그리기 작업의 순서를 묶어 정한다

세마포어는 다시 둘로 갈립니다. 이진 세마포어는 켜짐과 꺼짐 두 상태만 갖습니다. 타임라인 세마포어는 늘어나기만 하는 64비트 부호 없는 정수를 들고, 그 값이 기준값에 닿았는지로 신호를 판정합니다.

메모리 할당

Vulkan 의 메모리는 호스트 메모리와 디바이스 메모리로 갈립니다. 디바이스 메모리는 디바이스가 볼 수 있는 메모리입니다. 버퍼나 이미지 객체의 내용이 여기 놓입니다.

디바이스 메모리는 응용 프로그램이 직접 관리합니다. 디바이스는 쓸 수 있는 메모리 영역을 힙 하나 이상으로 알립니다. 힙은 디바이스에 있거나 호스트에 있습니다. 어느 경우든 디바이스가 볼 수 있습니다.

힙마다 메모리 타입이 붙습니다. 메모리 타입은 그 힙을 어떤 성질로 쓰는지를 나타냅니다. 호스트에서 캐시를 거치느냐 마느냐가 그런 성질입니다. 할당할 때 메모리 타입을 고르면 그 타입이 가리키는 힙에서 메모리가 빠집니다.

동시에 살아 있는 할당의 개수에는 한도가 있습니다. 한도는 구현과 플랫폼마다 다릅니다. 모든 구현이 보장해야 하는 최솟값은 4096 개입니다. 한도를 넘으면 동작이 정해지지 않습니다. 이때 VK_ERROR_TOO_MANY_OBJECTS 를 돌려주는 구현도 있지만 그 오류 코드에 기대어 한도를 알아내서는 안 됩니다(should not).

셰이더와 파이프라인

셰이더는 그래픽 카드에서 그리기나 계산의 한 단계를 맡아 도는 작은 프로그램입니다. 정점 하나, 화면 조각(프래그먼트) 하나, 계산 작업 묶음 하나마다 한 번씩 돕니다. Vulkan 은 셰이더를 사람이 쓴 소스 문자열로 받지 않습니다. SPIR-V(Standard Portable Intermediate Representation, 표준 이식 중간 표현)라는 중간 표현으로 받습니다. 중간 표현은 사람이 읽는 소스와 하드웨어가 읽는 명령 사이에 놓인 형식입니다.

고수준 셰이더 언어로 쓴 소스는 언어마다 있는 앞단 컴파일러가 SPIR-V 로 내립니다. 드라이버는 SPIR-V 만 받으면 됩니다. 그 덕에 드라이버 안에 고수준 언어 컴파일러를 둘 필요가 없어졌습니다. 드라이버도 그만큼 단순해졌습니다.

flowchart TD
    A["고수준 셰이더 언어 소스"] --> B["언어 앞단 컴파일러"]
    B --> C["SPIR-V"]
    C --> D["셰이더 모듈"]
    D --> E["파이프라인 · 셰이더와 고정 단계 설정을 한데 묶은 객체"]

셰이더 모듈은 SPIR-V 코드와 진입점 하나 이상을 담은 객체입니다. 파이프라인을 만들 때 진입점을 골라 셰이더를 꺼냅니다.

파이프라인은 셰이더 단계 전부와 고정 기능 단계의 설정을 한데 묶어 만든 객체입니다. 고정 기능 단계는 프로그램을 끼우지 않고 설정만 고르는 단계입니다. 전체를 미리 묶어 두면 셰이더 사이의 입출력을 보고 셰이더를 최적화할 수 있습니다. 그리는 순간마다 상태가 맞는지 확인하는 비용도 사라집니다.

묶음에서 빼 둘 수 있는 설정도 있습니다. 동적 상태로 표시한 설정은 파이프라인을 만들 때 정해지지 않습니다. 명령 버퍼에서 따로 정합니다.

파이프라인을 만든 결과는 파이프라인 캐시에 담아 다시 씁니다. 관련된 파이프라인 여럿을 만들 때 같은 캐시를 넘기면 서로 결과를 나눠 씁니다. 캐시 내용을 저장해 두면 다음 실행에서 미리 채울 수도 있습니다.

셰이더 객체 기능을 켜면 파이프라인 대신 단계마다 따로 컴파일한 셰이더 객체를 씁니다. 셰이더 객체는 특정 상태 묶음에 매이지 않습니다. 상태는 명령 버퍼에서 동적으로 정합니다.

검사를 덜어 낸 코어 레이어와 검증 레이어

함수마다 지켜야 할 유효 사용 조건이 있습니다. 이 조건을 다 지켜야 동작이 정해집니다. 어기면 동작이 정해지지 않고, 프로그램이 끝나 버릴 수도 있습니다. 다만 구현은 잘못된 사용이 운영체제나 구현 자신이나 다른 응용 프로그램을 망가뜨리지 않게 해야 합니다(must).

Vulkan 은 레이어를 쌓는 구조입니다. 레이어는 켜면 Vulkan 함수 호출 사슬에 끼어들어 그 호출을 먼저 받는 구성 요소입니다. 맨 아래가 규격이 정한 동작 그대로인 코어 레이어입니다. 그 위에 디버깅이나 검증용 레이어를 더 올립니다.

flowchart TD
    A["응용 프로그램"] --> V["검증 레이어 · 호출을 먼저 받아 검사한다"]
    V --> C["코어 레이어 · 규격이 정한 동작 그대로 · 검사 최소"]
    A -->|"검증 레이어를 켜지 않으면 바로 간다"| C

코어 레이어는 응용 프로그램이 API 를 바르게 쓴다고 가정합니다. 명령 버퍼를 만들고 제출하는 일을 가볍게 하려고 오류 검사를 최소로 둡니다. 예를 들어 열거값이 허용 범위 안에 있는지도 구현은 확인하지 않아도 됩니다.

검사는 검증 레이어가 맡습니다. 개발할 때는 검증 레이어를 켜고 만드는 것이 권장(should)입니다. 검증을 마치고 내보낸 응용 프로그램은 검증 레이어를 기본으로 켜지 않는 것이 권장입니다. 그래서 검사 비용이 출시된 프로그램에 붙지 않습니다.

확장

규격 본문이 정한 기본 기능 묶음을 코어라 부릅니다. 앞 소절의 코어 레이어와는 다른 것을 가리키는 말입니다. 코어 레이어는 호출을 받는 맨 아래 구성 요소입니다. 여기서 말하는 코어는 기능 묶음입니다.

코어 밖의 기능은 확장으로 붙습니다. 확장은 새 명령과 구조체와 열거값을 정의합니다. 등록된 확장의 선언은 Khronos 가 내놓는 헤더 파일 vulkan_core.h 에 코어와 함께 들어 있습니다.

확장은 Vulkan 구현이 내놓기도 하고 레이어가 내놓기도 합니다. 확장 가운데 일부는 나중에 판이 올라갈 때 코어로 올라옵니다. 판마다 무엇이 올라왔는지는 아래 「갈래」에 있습니다.

고르는 기준

Vulkan 은 GPU 를 더 직접 부리는 대신 응용 프로그램에 일과 책임을 더 지웁니다. 그 수고를 들여 바르게 쓰면 성능을 더 끌어낼 수 있습니다. 모든 개발자가 그 수고를 원하지는 않습니다.

그리기 명령을 만드는 데 CPU 가 병목인 프로그램에서 값이 큽니다. 게임 · 설계용 CAD(Computer-Aided Design, 컴퓨터 지원 설계) · 모바일 앱이 그런 예로 꼽힙니다. 일을 CPU 코어 여럿에 나눠 만들 수 있어서입니다.

Vulkan 은 OpenGL 을 바로 대체하는 규격이 아닙니다. OpenGL 과 OpenGL ES(OpenGL for Embedded Systems)는 GPU 기능을 더 높은 추상 수준에서 다룹니다. 많은 개발자에게는 그 둘이 더 편할 수 있습니다. Khronos 는 두 규격을 Vulkan 과 나란히 계속 발전시키겠다고 밝혔습니다.

출처 문서

정본은 Khronos Group 의 「Vulkan API Specification」입니다. 문서 스스로를 「Vulkan Specification」이라 부릅니다. Khronos Vulkan Working Group 이 판을 냅니다. 저작권 표기는 「Copyright 2014-2026 The Khronos Group Inc.」입니다.

정본의 위치와 판

아래 표에 나오는 낱말 하나를 먼저 정해 둡니다. 비준은 Khronos 이사회(Board of Promoters)의 투표로 주는 지위입니다. 비준을 받으면 그 판이나 확장이 Khronos 지식재산권 정책의 보호 아래 들어갑니다. 코어 판과 KHR(Khronos) 꼬리표가 붙은 확장은 전부 비준을 받습니다. 여러 회사가 함께 낸 EXT(extension) 꼬리표 확장은 일부만 받습니다.

항목 내용
정본 Vulkan Registry(registry.khronos.org/vulkan) 에 실린 판
원본 소스 GitHub 의 KhronosGroup/Vulkan-Docs 저장소. 규격 본문은 그 저장소의 소스 파일과 vk.xml 에서 생성됩니다. 이슈 트래커와 수정 제안 창구가 공개되어 있습니다
함께 나오는 것 vk.xml 에서 생성한 C 언어 헤더 파일 · API 레퍼런스 페이지
발행 형태 2024년 12월부터 최신 코어 판에 등록된 확장 전부를 더한 한 벌만 냅니다. 전에는 코어만 · 코어와 비준된 확장 · 코어와 등록된 확장 전부의 세 벌을 판마다 냈습니다
조회한 판 docs.vulkan.org 의 빌드(2026-10-02 조회)는 Vulkan 1.4.364 이고 2026-09-25 에 생성됐습니다
비준 여부 위 빌드는 비준되지 않은 확장까지 담아서 비준본이 아닙니다. 비준본의 상위 집합입니다. 비준본(코어와 비준된 확장 전부)은 Registry 의 「latest-ratified」 경로에 따로 있습니다

판 번호 1.4.364 에서 1 은 major, 4 는 minor, 364 는 patch 입니다. patch 가 오른 판에는 버그 수정과 문구 다듬기가 들어갑니다. major 와 minor 가 같고 patch 만 다른 판끼리는 완전히 호환됩니다. 한 판에 맞춰 짠 응용 프로그램이 다른 판의 구현에서 그대로 돕니다. 판 번호를 32비트에 담는 방법은 아래 「예시」에 있습니다.

요구 강도를 읽는 법

must · required · should · may · optional 다섯 낱말은 RFC(Request for Comments) 2119 의 뜻으로 읽습니다. optionally 는 optional 을 문법에 맞춰 바꿔 쓴 꼴입니다.

낱말 뜻
must · required 어기면 규격을 안 지킨 것입니다
should 이유가 있으면 어겨도 됩니다. 어기기 전에 그 결과를 따져 봐야 합니다
may · optional 해도 되고 안 해도 됩니다
cannot API 가 그것을 표현하거나 해낼 방법을 아예 주지 않습니다
must not 표현은 할 수 있지만 유효한 사용이 아닙니다. 결과가 정해지지 않고 되돌릴 수 없을 수도 있습니다

규격 문장은 구현하는 쪽과 응용 프로그램 쪽 가운데 한쪽을 겨냥합니다. 요구는 그 문장이 겨냥한 쪽에만 걸립니다. 예를 들어 「Valid Usage」 소절은 응용 프로그램 개발자에게만 말합니다.

참고용(informative) 문장은 요구를 걸지 않습니다. 배경 설명이나 제안을 담습니다. 「Note」 상자는 전부 참고용입니다. 장이나 절이나 부록 전체가 참고용이면 제목 끝에 「(Informative)」가 붙습니다. 그 표시가 없는 부분은 전부 규범입니다.

적합 판정

구현이 구현 쪽 요구를 다 지키면 적합하다고 합니다. 그렇지만 자기 구현이 적합하다고 공개적으로 말하려면 Khronos 가 거는 조건을 더 채워야 합니다. 조건은 셋입니다. Vulkan 채택자 계약(Adopter's Agreement)에 서명해야 합니다. 그에 따른 비용을 내야 합니다. Khronos 적합성 절차에 적합성 시험 결과를 내서 통과해야 합니다.

구현에 맡긴 대목

표에 나오는 디바이스 분실은 논리 디바이스나 물리 디바이스를 쓸 수 없게 되는 일입니다. 분실이 났을 때 무슨 일이 벌어지는지는 아래 「예시」의 VK_ERROR_DEVICE_LOST 에 있습니다.

대목 규격이 정한 것 구현이 정하는 것
동시 할당 개수 최솟값 4096 실제 한도
디바이스 분실 분실을 알리는 방법과 그 뒤의 처리 분실이 일어나는 원인
파이프라인 캐시 캐시를 넘기고 저장하는 방법 캐시에 담기는 내용
큐 안의 명령 실행 제출 순서와 그 밖의 암묵적 순서 보장을 지킨다는 것 그것 말고 명령을 얼마나 겹쳐 돌리나

같은 이름의 다른 문서

Vulkan SC(Safety Critical, 안전 필수)는 별개 규격입니다. Vulkan 1.2 를 바탕으로 안전 필수 시스템에 쓰도록 다듬은 API 입니다. 정본도 Vulkan SC Registry(registry.khronos.org/vulkansc)에 따로 있습니다. 무시되는 인자와 정의되지 않은 동작을 걷어 냈습니다. 지금은 Vulkan 과 셰이더 도구 사슬과 SPIR-V 방언을 같이 씁니다.

본문 주장과 근거

본문 주장 근거
구현과 응용 프로그램 사이의 계약 · 적합 · 유효 사용 Vulkan Specification 「Introduction」 장의 Document Conventions · Normative Requirements
큐 · 큐 패밀리 · 일곱 종류의 일 · 큐 사이 순서 없음 · 제출은 바로 돌아온다 「Fundamentals」 장의 Execution Model · Queue Operation
물리 디바이스와 논리 디바이스 · 디바이스 분실 「Devices and Queues」 장 · Lost Device
1차와 2차 명령 버퍼 · 한 명령 버퍼 안에서도 순서 없음 · 명령 풀은 외부 동기화 「Command Buffers」 장
모든 함수는 여러 스레드에서 부를 수 있다 · 외부 동기화 인자 「Fundamentals」 장의 Threading Behavior
동기화 수단 다섯 · 펜스와 세마포어의 정의 「Synchronization and Cache Control」 장
힙과 메모리 타입 · 동시 할당 한도 「Memory Allocation」 장 · 「Limits」 장의 Required Limits 표
셰이더 모듈은 SPIR-V · 셰이더 객체 「Shaders」 장
파이프라인을 미리 묶는 까닭 · 동적 상태 · 파이프라인 캐시 「Pipelines」 장
유효 사용 조건 · 코어 레이어의 최소 검사 · 검증 레이어 should 「Fundamentals」 장의 Valid Usage · Usage Validation
레이어가 호출 사슬에 끼어든다 · 확장의 정의 · 판 번호 · 판 사이 호환 「Extending Vulkan」 장
판마다 코어로 올라온 확장 부록 「Core Revisions (Informative)」
로드맵 이정표 부록 「Vulkan Roadmap Milestones」
OpenGL 을 바로 대체하지 않는다 · 응용 프로그램에 더 지운다 Khronos 가 관리하는 Vulkan Guide 「What is Vulkan?」
CPU 코어 여럿에서 일을 만든다 · SPIR-V 로 드라이버의 컴파일러를 걷었다 · 1.0 발표일 Khronos 의 Vulkan 1.0 보도자료(2016-02-16)
앞선 방식에서 드라이버가 떠맡던 일 Khronos Vulkan Samples 의 「Vulkan basics」. 비교 상대는 OpenGL ES 입니다. 원본 파일의 저작권 표기는 Arm Limited 와 기여자입니다

예시

규격이 정하는 값 셋을 봅니다. 판 번호를 담는 정수, 함수가 돌려주는 결과 코드, 그리고 순서를 맞추는 배리어 한 벌입니다.

판 번호 32비트

Vulkan 의 판 번호는 네 부분입니다. variant · major · minor · patch 입니다. 이 넷을 32비트 정수 하나에 담아 API 여러 곳에서 씁니다.

부분 비트 자리 폭 뜻
variant 31~29 3비트 Vulkan API 면 언제나 0 입니다. 0 이 아니면 Vulkan 의 변형이고, 응용 프로그램을 대개 고쳐야 그 위에서 돕니다
major 28~22 7비트 API 가 크게 바뀐 판입니다. 규격이 통째로 새 판이 됩니다
minor 21~12 10비트 코어에 새 기능이 들어간 판입니다
patch 11~0 12비트 버그 수정과 문구 다듬기가 들어갔음을 나타냅니다

variant 칸은 규격 1.2.175 판에서 더해졌습니다.

C
#define VK_MAKE_API_VERSION(variant, major, minor, patch) \
    ((((uint32_t)(variant)) << 29U) | (((uint32_t)(major)) << 22U) | (((uint32_t)(minor)) << 12U) | ((uint32_t)(patch)))

#define VK_API_VERSION_1_3 VK_MAKE_API_VERSION(0, 1, 3, 0)// Patch version should always be set to 0

VK_MAKE_API_VERSION 은 네 값을 각자의 비트로 밀어 올려 합치는 매크로입니다. VK_API_VERSION_1_3 은 Vulkan 1.3.0 을 뜻하는 상수입니다. 계산하면 1 을 22비트 올린 4194304 와 3 을 12비트 올린 12288 을 더한 4206592, 16진수로 0x00403000 입니다. 이 상수는 patch 를 언제나 0 으로 둡니다.

VkResult

Vulkan 함수는 결과를 VkResult 열거값으로 돌려줍니다. 값은 두 갈래입니다. 성공 코드는 성공이나 상태를 알리고 전부 0 이상입니다. 실행 중 오류 코드는 실행해 봐야 알 수 있는 실패를 알리고 전부 음수입니다.

C
typedef enum VkResult {
    VK_SUCCESS = 0,
    VK_NOT_READY = 1,
    VK_TIMEOUT = 2,
    VK_EVENT_SET = 3,
    VK_EVENT_RESET = 4,
    VK_INCOMPLETE = 5,
    VK_ERROR_OUT_OF_HOST_MEMORY = -1,
    VK_ERROR_OUT_OF_DEVICE_MEMORY = -2,
    VK_ERROR_INITIALIZATION_FAILED = -3,
    VK_ERROR_DEVICE_LOST = -4,
    // 이하 생략

VK_SUCCESS 는 명령이 성공적으로 끝났다는 뜻입니다. VK_ERROR_OUT_OF_DEVICE_MEMORY 는 디바이스 메모리 할당이 실패했다는 뜻입니다.

VK_ERROR_DEVICE_LOST 는 논리 디바이스나 물리 디바이스를 잃었다는 뜻입니다. 논리 디바이스는 구현마다 다른 여러 사정으로 분실될 수 있습니다. 분실이 났으면 대기 중인 명령과 앞으로 낼 명령이 실패할 수 있습니다. 자원과 그 밑의 메모리 내용도 정해지지 않게 될 수 있습니다. 흔한 원인은 실행 시간 초과 · 전원 관리 이벤트 · 플랫폼의 자원 관리 · 구현 오류입니다.

유효 사용 조건을 어긴 응용 프로그램도 분실 보고를 받을 수 있지만 그렇게 된다는 보장은 없습니다. 그런 응용 프로그램은 분실 보고를 받은 뒤에도 API 를 더 쓰는 것이 여전히 유효하지 않습니다. 분실이 보고되면 시스템이 되돌릴 수 없는 상태일 수도 있습니다.

코어 API 는 잘못된 사용을 잡도록 설계되지 않았습니다. 그래도 실행해 봐야 아는 사정은 남아서 이 결과 코드가 있습니다.

메모리 배리어 한 벌

계산 셰이더를 두 번 돌리는 경우입니다. 첫 번째 디스패치가 스토리지 버퍼에 씁니다. 두 번째 디스패치가 그 버퍼를 읽습니다. 스토리지 버퍼는 셰이더가 읽고 쓰는 버퍼입니다. 디스패치는 계산 셰이더를 실행시키는 명령입니다. 둘 사이에 배리어가 없으면 두 번째가 첫 번째의 결과를 본다는 보장이 없습니다.

C
vkCmdDispatch(...);

VkMemoryBarrier2KHR memoryBarrier = {
  ...
  .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT_KHR,
  .srcAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT_KHR,
  .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT_KHR,
  .dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT_KHR };

VkDependencyInfoKHR dependencyInfo = {
    ...
    1,              // memoryBarrierCount
    &memoryBarrier, // pMemoryBarriers
    ...
}

vkCmdPipelineBarrier2KHR(commandBuffer, &dependencyInfo);

vkCmdDispatch(...);

배리어는 앞뒤를 네 값으로 묶습니다. srcStageMask 와 srcAccessMask 는 앞쪽을 가리킵니다. 여기서는 계산 셰이더 단계와 셰이더 쓰기, 곧 첫 번째 디스패치가 버퍼에 쓰는 일입니다. dstStageMask 와 dstAccessMask 는 뒤쪽을 가리킵니다. 여기서는 계산 셰이더 단계와 셰이더 읽기, 곧 두 번째 디스패치가 버퍼를 읽는 일입니다.

vkCmdPipelineBarrier2KHR 를 큐에 제출하면 같은 큐에 그 앞에 제출한 명령과 뒤에 제출한 명령 사이에 메모리 의존이 생깁니다. 이 함수는 synchronization2 확장의 것입니다. 그 확장이 1.3 에서 코어로 올라온 뒤로는 꼬리표 없는 vkCmdPipelineBarrier2 로 부릅니다.

배경

Vulkan 이 새로 생긴 까닭을 앞선 Khronos 그래픽 규격인 OpenGL ES 와 견줘 봅니다. 무엇이 불편했고 그래서 무엇이 필요했는지를 차례로 짚습니다.

OpenGL ES 에서는 드라이버가 뒤에서 하는 일이 많았습니다. 아래 표가 네 축으로 그 차이를 보입니다.

축 OpenGL ES Vulkan
상태 전역 상태 하나. 그리기 호출마다 필요한 상태와 자원 연결 표를 다시 만든다. 어떤 상태 조합을 쓸지 그리는 순간에야 드러나 최적화를 걸기 어렵다 파이프라인 객체에 상태 조합을 미리 묶어 둔다
실행 모델 동기 모델. 모든 호출은 앞선 호출이 다 처리된 것처럼 동작해야 한다. GPU 는 실제로는 비동기로 일하므로 드라이버가 이 겉모습을 유지한다. 그러려고 자원의 읽기와 쓰기를 추적하고, 순서를 맞추고, 필요하면 호출을 막고 기다린다 비동기 모델. 응용 프로그램이 의존 관계와 동기화를 직접 건다. 드라이버의 CPU 부담이 크게 주는 대신 그 일을 응용 프로그램이 떠맡는다
스레드 그리기를 한 스레드에서만 만든다. CPU 코어 여럿을 쓰기 어렵다 그리기 일을 CPU 코어 여럿에 나눠 만든다
오류 검사 실행 중 오류 검사가 늘 켜져 있다. 개발 중에만 날 실수를 잡는 검사가 출시판에도 비용으로 남는다 드라이버에 실행 중 오류 검사를 요구하지 않는다. 필요하면 검증 레이어를 끼운다

필요했던 것은 GPU 를 직접 다루는 길이었습니다. 1.0 발표가 겨냥한 것은 GPU 가속을 응용 프로그램이 직접 제어하는 것, CPU 부담을 줄이는 것, 멀티스레드 성능, 그리고 더 단순하고 예측 가능한 드라이버였습니다. 셰이더도 같은 방향으로 바뀌었습니다. SPIR-V 라는 중간 표현으로 컴파일러 사슬을 갈라, 드라이버 안에 고수준 언어 컴파일러를 둘 필요를 없앴습니다.

Khronos 는 2016년 2월 16일에 Vulkan 1.0 규격을 내놓았습니다. 하드웨어 회사 · 게임 엔진 회사 · 플랫폼 회사가 18개월 동안 함께 만든 결과입니다. 발표에 실린 AMD(Advanced Micro Devices) 쪽 인용은 Vulkan API 가 AMD 의 Mantle 에서 갈라져 나왔다고 말합니다.

규격은 스스로를 OpenGL · OpenGL ES · OpenCL(Open Computing Language)의 후속으로 적습니다. 이 규격이 담은 기능 가운데 상당 부분은 그 세 규격에서 거의 고치지 않고 가져온 것입니다. 거의 고치지 않고 이어받은 것은 할 수 있는 일입니다. 위 표의 네 축은 그 일을 시키는 방법입니다. 방법은 달라졌습니다. 그래도 Khronos 는 Vulkan 을 OpenGL 과 OpenGL ES 를 보완하는 규격으로 내놓았습니다.

갈래

판을 가르는 축은 코어에 무엇을 올렸나입니다. minor 판이 오를 때마다 새 기능이 코어에 들어갑니다. 그 새 기능에는 먼저 확장으로 나와 있던 것을 코어로 올린 것도 들어갑니다. 아래에서는 판마다 대표 몇 가지만 짚습니다.

판 사이 호환은 이렇게 정해져 있습니다. minor 판이 낮은 쪽에 맞춰 쓴 응용 프로그램은 minor 판이 높은 구현에서도 돕니다. 코어 기능과 KHR 확장에 걸리는 약속입니다. 코어 기능은 minor 판에서 낡은 것(legacy)으로 표시될 수는 있어도 없어지지는 않습니다. major 판이 다르면 인터페이스와 동작이 바뀌고 낡은 기능이 빠질 수 있습니다.

Vulkan 1.0

Vulkan API 의 첫 판입니다. 2016년 2월에 나왔습니다.

Vulkan 1.1

확장 23개를 코어로 올렸습니다. VK_KHR_device_group · VK_KHR_multiview · VK_KHR_external_memory · VK_KHR_external_semaphore · VK_KHR_external_fence 가 그 일부입니다.

확장이 아닌 것으로는 서브그룹 범위와 그룹 연산, 보호 메모리 기능, SPIR-V 1.1~1.3 지원이 더해졌습니다. 구현이 지원하는 판을 묻는 vkEnumerateInstanceVersion 도 이때 생겼습니다.

Vulkan 1.2

확장 24개를 코어로 올렸습니다. 위 「순서를 맞추는 다섯 수단」의 타임라인 세마포어가 VK_KHR_timeline_semaphore 로 이때 들어왔습니다. VK_EXT_descriptor_indexing · VK_KHR_buffer_device_address · VK_KHR_vulkan_memory_model 도 같은 판에 올라왔습니다. SPIR-V 1.4 와 1.5 지원이 더해졌습니다.

Vulkan 1.3

확장 23개를 코어로 올렸습니다. VK_KHR_dynamic_rendering 과, 위 「예시」의 배리어 함수를 준 VK_KHR_synchronization2 가 이 판에 들어왔습니다.

이 판부터 반드시 지원해야 하는 것도 늘었습니다. SPIR-V 1.6, 셰이더가 버퍼 주소로 메모리에 닿는 bufferDeviceAddress 기능, Vulkan 메모리 모델 기능 둘이 필수가 됐습니다.

Vulkan 1.4

확장 16개를 코어로 올렸습니다. VK_KHR_push_descriptor · VK_KHR_maintenance5 · VK_EXT_host_image_copy 가 그 일부입니다.

그래픽스나 계산 일을 받는 큐는 전송 일도 받는다고 반드시 알려야 하게 됐습니다. 구현이 보장해야 하는 한도도 몇 가지 올랐습니다. 예를 들어 2차원 이미지의 최대 크기는 4096 에서 8192 로 올랐습니다.

로드맵 이정표

로드맵 이정표는 판과 다른 축입니다. 판이 코어에 무엇이 있나를 정한다면, 이정표는 어느 해에 나오는 중급 이상 기기가 무엇을 지원해야 하나를 정합니다. 대상은 스마트폰 · 태블릿 · 노트북 · 콘솔 · 데스크톱입니다. 이정표마다 지원할 확장 · 기능 · 한도 · 포맷 묶음을 정합니다.

이정표 요구하는 것
Roadmap 2022 Vulkan 1.3 을 요구합니다
Roadmap 2024 Roadmap 2022 이정표의 지원 묶음을 요구합니다. Khronos 는 이 이정표와 같은 시기에 Vulkan 1.4 를 내지 않았습니다. 대신 VK_KHR_push_descriptor 와 VK_KHR_maintenance5 의 자잘한 개선 같은 기능 몇 가지를 이 이정표에 함께 넣었습니다
Roadmap 2026 기본 지원 기능을 다시 올리고, 스왑체인과 화면 출력 지원을 보장하게 합니다

이름의 연도는 그 해에 출하되는 기기를 가리킵니다. 판이 나온 해가 아닙니다.

관련 항목

Vulkan 이 속하는 상위 분류

그래픽스 · 그래픽스 API · 렌더링 · API · GPGPU

Vulkan 규격을 만들고 구현하는 주체

Khronos Group · GPU · 디바이스 드라이버 · GPU 드라이버 · Mesa · AMD

Vulkan 규격을 펴내는 저장소와 파일

Vulkan Registry · Vulkan-Docs · vk.xml · vulkan_core.h · SPIR-V Registry · Vulkan Loader

Vulkan 프로그램이 만들어 쓰는 객체

Vulkan 인스턴스 · 물리 디바이스 · 논리 디바이스 · 큐 · 큐 패밀리 · 명령 버퍼 · 명령 풀 · 디스크립터 셋 · 렌더 패스 · 프레임버퍼 · 스왑체인 · 샘플러 · 쿼리

Vulkan 이 그리기와 계산을 거치는 처리 단계

그래픽스 파이프라인 · 정점 셰이더 · 테셀레이션 · 지오메트리 셰이더 · 메시 셰이딩 · 래스터화 · 프래그먼트 셰이더 · 깊이 테스트 · 블렌딩 · 컴퓨트 셰이더 · 디스패치

Vulkan 이 실행 순서를 맞추는 수단

파이프라인 배리어 · 세마포어 · 타임라인 세마포어 · 펜스 · 이벤트 · 메모리 배리어 · 이미지 레이아웃 · 외부 동기화 · 메모리 모델

Vulkan 이 GPU 메모리를 다루는 방법

디바이스 메모리 · 메모리 힙 · 메모리 타입 · 버퍼 · 이미지 · 텍스처 · 스파스 리소스 · 메모리 할당자

Vulkan 이 셰이더를 받는 형식과 그 소스 언어

SPIR-V · GLSL · HLSL · 셰이더 · 셰이더 모듈 · 셰이더 객체 · 파이프라인 캐시 · 동적 상태 · 바이트코드

Vulkan 이 규격 밖 기능을 붙이는 장치

Vulkan 확장 · 검증 레이어 · 레이어 · WSI · 가속 구조 · 레이 트레이싱 · 비디오 코딩

Vulkan 규격이 요구 강도와 적합을 정하는 규칙

RFC 2119 · 유효 사용 조건 · 미정의 동작 · 적합성 시험 · 비준 · Vulkan 로드맵 · Vulkan 프로파일

Vulkan 에서 갈라졌거나 Vulkan 이 이어받은 규격

Vulkan SC · Mantle · OpenGL · OpenGL ES · OpenCL

Vulkan 과 같은 일을 맡는 다른 그래픽스 API

Direct3D · Metal · WebGPU · WebGL

Vulkan 과 다른 그래픽스 API 사이를 옮겨 주는 변환 계층

MoltenVK · DXVK · ANGLE · Proton

Vulkan 을 감싸 쓰는 게임 엔진

게임 엔진 · Unity · Unreal Engine · Godot

Vulkan 과 같은 GPU 계산 일감을 받는 계산 전용 API

CUDA · SYCL · OpenCL C · GPGPU 프로그래밍

다른 이름: 불칸 · Vulkan API · Vulkan Specification